From 656df7c670fc0402229a14789becd01f03bfbed5 Mon Sep 17 00:00:00 2001 From: zerosoul Date: Sat, 19 Feb 2022 15:57:25 +0800 Subject: [PATCH] feat: users online status --- src/app/slices/contacts.js | 26 +++++++++++++++++++++++++ src/app/store.with.persist.js | 25 ++++++++++++++++++++++++ src/common/component/NotificationHub.js | 9 +++++++++ src/common/hook/useFilteredUsers.js | 5 ++--- src/routes/chat/ChannelChat/index.js | 6 ++---- src/routes/chat/DMChat/index.js | 3 +-- src/routes/chat/index.js | 5 ++--- src/routes/contacts/Profile.js | 7 +++---- src/routes/contacts/index.js | 4 ++-- src/routes/home/usePreload.js | 8 +++++++- 10 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 src/app/slices/contacts.js diff --git a/src/app/slices/contacts.js b/src/app/slices/contacts.js new file mode 100644 index 00000000..ba41040b --- /dev/null +++ b/src/app/slices/contacts.js @@ -0,0 +1,26 @@ +import { createSlice } from "@reduxjs/toolkit"; +const initialState = []; +const contactsSlice = createSlice({ + name: `contacts`, + initialState, + reducers: { + setContacts(state, action) { + console.log("set Contacts store", state); + const contacts = action.payload || []; + return contacts; + }, + updateUsersStatus(state, action) { + const onlines = action.payload; + onlines.forEach((item) => { + const { uid, online = false } = item; + const curr = state.find(({ uid: id }) => id == uid); + console.log("update user status", curr, online); + if (curr) { + curr.online = online; + } + }); + }, + }, +}); +export const { setContacts, updateUsersStatus } = contactsSlice.actions; +export default contactsSlice.reducer; diff --git a/src/app/store.with.persist.js b/src/app/store.with.persist.js index 6ee227f1..66630b97 100644 --- a/src/app/store.with.persist.js +++ b/src/app/store.with.persist.js @@ -13,6 +13,7 @@ import { import authDataReducer from "./slices/auth.data"; import uiReducer from "./slices/ui"; import channelsReducer from "./slices/channels"; +import contactsReducer from "./slices/contacts"; import channelMsgReducer from "./slices/message.channel"; import userMsgReducer from "./slices/message.user"; import { authApi } from "./services/auth"; @@ -28,6 +29,7 @@ const persistedReducer = persistReducer( persistConfig, combineReducers({ ui: uiReducer, + contacts: contactsReducer, channels: channelsReducer, userMsg: userMsgReducer, channelMsg: channelMsgReducer, @@ -53,4 +55,27 @@ const store = configureStore({ ), }); setupListeners(store.dispatch); +// export function swapToUserStore(userId) { +// console.log({ userId }); +// const newConfig = { +// ...persistConfig, +// keyPrefix: userId, +// }; +// store.replaceReducer( +// persistReducer( +// newConfig, +// combineReducers({ +// ui: uiReducer, +// channels: channelsReducer, +// userMsg: userMsgReducer, +// channelMsg: channelMsgReducer, +// authData: authDataReducer, +// [authApi.reducerPath]: authApi.reducer, +// [contactApi.reducerPath]: contactApi.reducer, +// [channelApi.reducerPath]: channelApi.reducer, +// [serverApi.reducerPath]: serverApi.reducer, +// }) +// ) +// ); +// } export default store; diff --git a/src/common/component/NotificationHub.js b/src/common/component/NotificationHub.js index 2b9bea4a..a2f707e6 100644 --- a/src/common/component/NotificationHub.js +++ b/src/common/component/NotificationHub.js @@ -10,6 +10,7 @@ import { addChannel, deleteChannel, } from "../../app/slices/channels"; +import { updateUsersStatus } from "../../app/slices/contacts"; import { clearAuthData, setUsersVersion, @@ -71,6 +72,14 @@ const NotificationHub = ({ token, usersVersion = 0, afterMid = 0 }) => { dispatch(setUsersVersion({ version })); } break; + case "users_state": + case "users_state_changed": + { + let { type, ...rest } = data; + const onlines = type == "users_state_changed" ? [rest] : rest.users; + dispatch(updateUsersStatus(onlines)); + } + break; case "kick": { console.log("kicked"); diff --git a/src/common/hook/useFilteredUsers.js b/src/common/hook/useFilteredUsers.js index 06f450e3..4b62a946 100644 --- a/src/common/hook/useFilteredUsers.js +++ b/src/common/hook/useFilteredUsers.js @@ -1,9 +1,8 @@ import { useState, useEffect } from "react"; -import { useGetContactsQuery } from "../../app/services/contact"; - +import { useSelector } from "react-redux"; export default function useFilteredUsers() { const [input, setInput] = useState(""); - const { data: contacts } = useGetContactsQuery(); + const contacts = useSelector((store) => store.contacts); const [filteredUsers, setFilteredUsers] = useState(contacts); useEffect(() => { if (!input) { diff --git a/src/routes/chat/ChannelChat/index.js b/src/routes/chat/ChannelChat/index.js index 4916f035..eea1cf84 100644 --- a/src/routes/chat/ChannelChat/index.js +++ b/src/routes/chat/ChannelChat/index.js @@ -10,7 +10,6 @@ import { clearChannelMsgUnread, setLastAccessTime, } from "../../../app/slices/message.channel"; -import { useGetContactsQuery } from "../../../app/services/contact"; import Contact from "../../../common/component/Contact"; import Layout from "../Layout"; import { @@ -29,10 +28,9 @@ export default function ChannelChat({ // const containerRef = useRef(null); const [dragFiles, setDragFiles] = useState([]); const dispatch = useDispatch(); - const msgs = useSelector((store) => { - return store.channelMsg[cid] || {}; + const { msgs, users } = useSelector((store) => { + return { msgs: store.channelMsg[cid] || {}, users: store.contacts }; }); - const { data: users } = useGetContactsQuery(); const handleClearUnreads = () => { dispatch(clearChannelMsgUnread(cid)); }; diff --git a/src/routes/chat/DMChat/index.js b/src/routes/chat/DMChat/index.js index b0e31786..e3de2f28 100644 --- a/src/routes/chat/DMChat/index.js +++ b/src/routes/chat/DMChat/index.js @@ -3,7 +3,6 @@ import { useSelector } from "react-redux"; import Message from "../../../common/component/Message"; import Send from "../../../common/component/Send"; import Contact from "../../../common/component/Contact"; -import { useGetContactsQuery } from "../../../app/services/contact"; import Layout from "../Layout"; import { StyledHeader, StyledDMChat } from "./styled"; @@ -11,10 +10,10 @@ import { StyledHeader, StyledDMChat } from "./styled"; export default function DMChat({ uid = "", dropFiles = [] }) { console.log("dm files", dropFiles); const [dragFiles, setDragFiles] = useState([]); + const contacts = useSelector((store) => store.contacts); const msgs = useSelector((store) => { return store.userMsg[uid] || {}; }); - const { data: contacts } = useGetContactsQuery(); const [currUser, setCurrUser] = useState(null); useEffect(() => { console.log({ uid }); diff --git a/src/routes/chat/index.js b/src/routes/chat/index.js index dfc652fb..6fca943a 100644 --- a/src/routes/chat/index.js +++ b/src/routes/chat/index.js @@ -6,7 +6,6 @@ import { useSelector } from "react-redux"; import { MdAdd } from "react-icons/md"; import { AiOutlineCaretDown } from "react-icons/ai"; -import { useGetContactsQuery } from "../../app/services/contact"; import StyledWrapper from "./styled"; import Search from "../../common/component/Search"; import Avatar from "../../common/component/Avatar"; @@ -31,7 +30,7 @@ export default function ChatPage() { const [channelModalVisible, setChannelModalVisible] = useState(false); const [contactsModalVisible, setContactsModalVisible] = useState(false); const { channel_id, user_id } = useParams(); - const { data: contacts } = useGetContactsQuery(); + const contacts = useSelector((store) => store.contacts); const toggleContactsModalVisible = () => { setContactsModalVisible((prev) => !prev); }; @@ -121,7 +120,7 @@ export default function ChatPage() {
diff --git a/src/routes/contacts/Profile.js b/src/routes/contacts/Profile.js index 09a90dc4..b21bcb93 100644 --- a/src/routes/contacts/Profile.js +++ b/src/routes/contacts/Profile.js @@ -1,13 +1,12 @@ // import React from "react"; // import toast from "react-hot-toast"; import { useState, useEffect } from "react"; - +import { useSelector } from "react-redux"; import { NavLink } from "react-router-dom"; import { BsChatText } from "react-icons/bs"; import { RiUserAddLine } from "react-icons/ri"; import { IoShareOutline } from "react-icons/io5"; import styled from "styled-components"; -import { useGetContactsQuery } from "../../app/services/contact"; import Avatar from "../../common/component/Avatar"; @@ -52,7 +51,7 @@ const StyledWrapper = styled.div` } `; export default function Profile({ uid = null }) { - const { data: contacts } = useGetContactsQuery(); + const contacts = useSelector((store) => store.contacts); const [profile, setProfile] = useState(null); useEffect(() => { if (contacts && contacts) { @@ -66,7 +65,7 @@ export default function Profile({ uid = null }) { const { name, email, avatar } = profile; return ( - +

{name}

{email}
    diff --git a/src/routes/contacts/index.js b/src/routes/contacts/index.js index 4b03240b..bdfd68e0 100644 --- a/src/routes/contacts/index.js +++ b/src/routes/contacts/index.js @@ -1,6 +1,6 @@ // import { useState, useEffect } from "react"; import { NavLink, useParams } from "react-router-dom"; -import { useGetContactsQuery } from "../../app/services/contact"; +import { useSelector } from "react-redux"; import Search from "../../common/component/Search"; import Contact from "../../common/component/Contact"; import CurrentUser from "../../common/component/CurrentUser"; @@ -10,7 +10,7 @@ import StyledWrapper from "./styled"; export default function ContactsPage() { const { user_id } = useParams(); - const { data: contacts } = useGetContactsQuery(); + const contacts = useSelector((store) => store.contacts); console.log({ contacts, user_id }); if (!contacts) return null; diff --git a/src/routes/home/usePreload.js b/src/routes/home/usePreload.js index 65c58a4f..5fda8470 100644 --- a/src/routes/home/usePreload.js +++ b/src/routes/home/usePreload.js @@ -3,6 +3,7 @@ import { useSelector, useDispatch } from "react-redux"; import { useNavigate } from "react-router-dom"; import { useGetContactsQuery } from "../../app/services/contact"; import { clearAuthData } from "../../app/slices/auth.data"; +import { setContacts } from "../../app/slices/contacts"; // import { useGetChannelsQuery } from "../../app/services/channel"; import { useGetServerQuery } from "../../app/services/server"; @@ -41,8 +42,13 @@ export default function usePreload() { if (!matchedUser) { dispatch(clearAuthData()); navigate("/login"); + } else { + const markedContacts = contacts.map((u) => { + return u.uid == matchedUser.uid ? { ...u, online: true } : u; + }); + dispatch(setContacts(markedContacts)); + setChecked(true); } - setChecked(true); } }, [contacts]);