feat: users online status

This commit is contained in:
zerosoul
2022-02-19 15:57:25 +08:00
parent f96ca44841
commit 656df7c670
10 changed files with 79 additions and 19 deletions
+26
View File
@@ -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;
+25
View File
@@ -13,6 +13,7 @@ import {
import authDataReducer from "./slices/auth.data"; import authDataReducer from "./slices/auth.data";
import uiReducer from "./slices/ui"; import uiReducer from "./slices/ui";
import channelsReducer from "./slices/channels"; import channelsReducer from "./slices/channels";
import contactsReducer from "./slices/contacts";
import channelMsgReducer from "./slices/message.channel"; import channelMsgReducer from "./slices/message.channel";
import userMsgReducer from "./slices/message.user"; import userMsgReducer from "./slices/message.user";
import { authApi } from "./services/auth"; import { authApi } from "./services/auth";
@@ -28,6 +29,7 @@ const persistedReducer = persistReducer(
persistConfig, persistConfig,
combineReducers({ combineReducers({
ui: uiReducer, ui: uiReducer,
contacts: contactsReducer,
channels: channelsReducer, channels: channelsReducer,
userMsg: userMsgReducer, userMsg: userMsgReducer,
channelMsg: channelMsgReducer, channelMsg: channelMsgReducer,
@@ -53,4 +55,27 @@ const store = configureStore({
), ),
}); });
setupListeners(store.dispatch); 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; export default store;
+9
View File
@@ -10,6 +10,7 @@ import {
addChannel, addChannel,
deleteChannel, deleteChannel,
} from "../../app/slices/channels"; } from "../../app/slices/channels";
import { updateUsersStatus } from "../../app/slices/contacts";
import { import {
clearAuthData, clearAuthData,
setUsersVersion, setUsersVersion,
@@ -71,6 +72,14 @@ const NotificationHub = ({ token, usersVersion = 0, afterMid = 0 }) => {
dispatch(setUsersVersion({ version })); dispatch(setUsersVersion({ version }));
} }
break; 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": case "kick":
{ {
console.log("kicked"); console.log("kicked");
+2 -3
View File
@@ -1,9 +1,8 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useGetContactsQuery } from "../../app/services/contact"; import { useSelector } from "react-redux";
export default function useFilteredUsers() { export default function useFilteredUsers() {
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const { data: contacts } = useGetContactsQuery(); const contacts = useSelector((store) => store.contacts);
const [filteredUsers, setFilteredUsers] = useState(contacts); const [filteredUsers, setFilteredUsers] = useState(contacts);
useEffect(() => { useEffect(() => {
if (!input) { if (!input) {
+2 -4
View File
@@ -10,7 +10,6 @@ import {
clearChannelMsgUnread, clearChannelMsgUnread,
setLastAccessTime, setLastAccessTime,
} from "../../../app/slices/message.channel"; } from "../../../app/slices/message.channel";
import { useGetContactsQuery } from "../../../app/services/contact";
import Contact from "../../../common/component/Contact"; import Contact from "../../../common/component/Contact";
import Layout from "../Layout"; import Layout from "../Layout";
import { import {
@@ -29,10 +28,9 @@ export default function ChannelChat({
// const containerRef = useRef(null); // const containerRef = useRef(null);
const [dragFiles, setDragFiles] = useState([]); const [dragFiles, setDragFiles] = useState([]);
const dispatch = useDispatch(); const dispatch = useDispatch();
const msgs = useSelector((store) => { const { msgs, users } = useSelector((store) => {
return store.channelMsg[cid] || {}; return { msgs: store.channelMsg[cid] || {}, users: store.contacts };
}); });
const { data: users } = useGetContactsQuery();
const handleClearUnreads = () => { const handleClearUnreads = () => {
dispatch(clearChannelMsgUnread(cid)); dispatch(clearChannelMsgUnread(cid));
}; };
+1 -2
View File
@@ -3,7 +3,6 @@ import { useSelector } from "react-redux";
import Message from "../../../common/component/Message"; import Message from "../../../common/component/Message";
import Send from "../../../common/component/Send"; import Send from "../../../common/component/Send";
import Contact from "../../../common/component/Contact"; import Contact from "../../../common/component/Contact";
import { useGetContactsQuery } from "../../../app/services/contact";
import Layout from "../Layout"; import Layout from "../Layout";
import { StyledHeader, StyledDMChat } from "./styled"; import { StyledHeader, StyledDMChat } from "./styled";
@@ -11,10 +10,10 @@ import { StyledHeader, StyledDMChat } from "./styled";
export default function DMChat({ uid = "", dropFiles = [] }) { export default function DMChat({ uid = "", dropFiles = [] }) {
console.log("dm files", dropFiles); console.log("dm files", dropFiles);
const [dragFiles, setDragFiles] = useState([]); const [dragFiles, setDragFiles] = useState([]);
const contacts = useSelector((store) => store.contacts);
const msgs = useSelector((store) => { const msgs = useSelector((store) => {
return store.userMsg[uid] || {}; return store.userMsg[uid] || {};
}); });
const { data: contacts } = useGetContactsQuery();
const [currUser, setCurrUser] = useState(null); const [currUser, setCurrUser] = useState(null);
useEffect(() => { useEffect(() => {
console.log({ uid }); console.log({ uid });
+2 -3
View File
@@ -6,7 +6,6 @@ import { useSelector } from "react-redux";
import { MdAdd } from "react-icons/md"; import { MdAdd } from "react-icons/md";
import { AiOutlineCaretDown } from "react-icons/ai"; import { AiOutlineCaretDown } from "react-icons/ai";
import { useGetContactsQuery } from "../../app/services/contact";
import StyledWrapper from "./styled"; import StyledWrapper from "./styled";
import Search from "../../common/component/Search"; import Search from "../../common/component/Search";
import Avatar from "../../common/component/Avatar"; import Avatar from "../../common/component/Avatar";
@@ -31,7 +30,7 @@ export default function ChatPage() {
const [channelModalVisible, setChannelModalVisible] = useState(false); const [channelModalVisible, setChannelModalVisible] = useState(false);
const [contactsModalVisible, setContactsModalVisible] = useState(false); const [contactsModalVisible, setContactsModalVisible] = useState(false);
const { channel_id, user_id } = useParams(); const { channel_id, user_id } = useParams();
const { data: contacts } = useGetContactsQuery(); const contacts = useSelector((store) => store.contacts);
const toggleContactsModalVisible = () => { const toggleContactsModalVisible = () => {
setContactsModalVisible((prev) => !prev); setContactsModalVisible((prev) => !prev);
}; };
@@ -121,7 +120,7 @@ export default function ChatPage() {
<Avatar <Avatar
className="avatar" className="avatar"
url={tmpSessionUser.avatar} url={tmpSessionUser.avatar}
id={user_id} name={tmpSessionUser.name}
/> />
<div className="details"> <div className="details">
<div className="up"> <div className="up">
+3 -4
View File
@@ -1,13 +1,12 @@
// import React from "react"; // import React from "react";
// import toast from "react-hot-toast"; // import toast from "react-hot-toast";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import { BsChatText } from "react-icons/bs"; import { BsChatText } from "react-icons/bs";
import { RiUserAddLine } from "react-icons/ri"; import { RiUserAddLine } from "react-icons/ri";
import { IoShareOutline } from "react-icons/io5"; import { IoShareOutline } from "react-icons/io5";
import styled from "styled-components"; import styled from "styled-components";
import { useGetContactsQuery } from "../../app/services/contact";
import Avatar from "../../common/component/Avatar"; import Avatar from "../../common/component/Avatar";
@@ -52,7 +51,7 @@ const StyledWrapper = styled.div`
} }
`; `;
export default function Profile({ uid = null }) { export default function Profile({ uid = null }) {
const { data: contacts } = useGetContactsQuery(); const contacts = useSelector((store) => store.contacts);
const [profile, setProfile] = useState(null); const [profile, setProfile] = useState(null);
useEffect(() => { useEffect(() => {
if (contacts && contacts) { if (contacts && contacts) {
@@ -66,7 +65,7 @@ export default function Profile({ uid = null }) {
const { name, email, avatar } = profile; const { name, email, avatar } = profile;
return ( return (
<StyledWrapper> <StyledWrapper>
<Avatar className="avatar" url={avatar} id={uid} name={name} /> <Avatar className="avatar" url={avatar} name={name} />
<h2 className="name">{name}</h2> <h2 className="name">{name}</h2>
<span className="email">{email}</span> <span className="email">{email}</span>
<ul className="icons"> <ul className="icons">
+2 -2
View File
@@ -1,6 +1,6 @@
// import { useState, useEffect } from "react"; // import { useState, useEffect } from "react";
import { NavLink, useParams } from "react-router-dom"; 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 Search from "../../common/component/Search";
import Contact from "../../common/component/Contact"; import Contact from "../../common/component/Contact";
import CurrentUser from "../../common/component/CurrentUser"; import CurrentUser from "../../common/component/CurrentUser";
@@ -10,7 +10,7 @@ import StyledWrapper from "./styled";
export default function ContactsPage() { export default function ContactsPage() {
const { user_id } = useParams(); const { user_id } = useParams();
const { data: contacts } = useGetContactsQuery(); const contacts = useSelector((store) => store.contacts);
console.log({ contacts, user_id }); console.log({ contacts, user_id });
if (!contacts) return null; if (!contacts) return null;
+7 -1
View File
@@ -3,6 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useGetContactsQuery } from "../../app/services/contact"; import { useGetContactsQuery } from "../../app/services/contact";
import { clearAuthData } from "../../app/slices/auth.data"; import { clearAuthData } from "../../app/slices/auth.data";
import { setContacts } from "../../app/slices/contacts";
// import { useGetChannelsQuery } from "../../app/services/channel"; // import { useGetChannelsQuery } from "../../app/services/channel";
import { useGetServerQuery } from "../../app/services/server"; import { useGetServerQuery } from "../../app/services/server";
@@ -41,8 +42,13 @@ export default function usePreload() {
if (!matchedUser) { if (!matchedUser) {
dispatch(clearAuthData()); dispatch(clearAuthData());
navigate("/login"); 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]); }, [contacts]);