mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
feat: online user status
This commit is contained in:
parent
6f855af3db
commit
f92ef01353
@ -1,10 +1,11 @@
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { Router, Switch } from 'react-router-dom';
|
||||
import { routes } from './routes.config';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useContext } from 'react';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
|
||||
/**
|
||||
@ -18,6 +19,7 @@ import { SocketContext } from './contexts';
|
||||
const App = () => {
|
||||
const {
|
||||
uiStore: { history },
|
||||
onlineStore,
|
||||
} = useRootStore();
|
||||
const { socket } = useContext(SocketContext);
|
||||
|
||||
@ -33,6 +35,7 @@ const App = () => {
|
||||
socket.userId = userId;
|
||||
}
|
||||
});
|
||||
useSocketEvent('user:online', online => onlineStore.loadOnline(online));
|
||||
|
||||
return (
|
||||
<Router history={history}>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import React, { Suspense, useContext } from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Redirect } from 'react-router';
|
||||
import { useErrorHandler } from 'react-error-boundary';
|
||||
import { userContainRoles } from '@educt/helpers';
|
||||
import { Flex, Box } from '@chakra-ui/react';
|
||||
|
||||
@ -20,7 +19,8 @@ import NavDesktop from '@educt/components/Nav/Desktop';
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useContext } from 'react';
|
||||
import { useErrorHandler } from 'react-error-boundary';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
|
||||
/**
|
||||
|
||||
@ -10,7 +10,7 @@ const Avatar: React.FC<IAvatarProps> = props => {
|
||||
return (
|
||||
<Flex flexDir={'column'} alignItems={'center'}>
|
||||
<ChakraAvatar border={`4px solid ${borderColor}`} borderColor={borderColor} name={name} size='2xl'>
|
||||
{isOnline && <ChakraAvatarBadge boxSize='0.75em' bg={onlineColor} />}
|
||||
{isOnline !== undefined && <ChakraAvatarBadge boxSize='0.75em' bg={onlineColor} />}
|
||||
</ChakraAvatar>
|
||||
{props.children}
|
||||
</Flex>
|
||||
|
||||
@ -5,7 +5,12 @@ export const useSocket = (url: string) => {
|
||||
const [socket, setSocket] = useState<Socket | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const socketClient = io(url, { autoConnect: false, withCredentials: true });
|
||||
const socketClient = io(url, {
|
||||
autoConnect: false,
|
||||
withCredentials: true,
|
||||
transports: ['websocket'],
|
||||
upgrade: false,
|
||||
});
|
||||
|
||||
setSocket(socketClient);
|
||||
|
||||
|
||||
@ -25,9 +25,7 @@ import { observer } from 'mobx-react';
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useFetchCourses, useFetchStat } from '@educt/hooks/queries';
|
||||
import { useSocketEvent } from '@educt/hooks/useSocketEvent';
|
||||
|
||||
/**
|
||||
* Main page
|
||||
@ -35,23 +33,10 @@ import { useSocketEvent } from '@educt/hooks/useSocketEvent';
|
||||
const MainPage: React.FC<IPageProps> = () => {
|
||||
const {
|
||||
userStore: { me },
|
||||
onlineStore,
|
||||
} = useRootStore();
|
||||
const { data: courses } = useFetchCourses({ limit: 3 });
|
||||
const { data: stat } = useFetchStat();
|
||||
const [online, setOnline] = useState<number>(0);
|
||||
|
||||
/**
|
||||
* Update online state on socket event
|
||||
*/
|
||||
useSocketEvent('user:online', online => setOnline(online));
|
||||
|
||||
// useSocketEvent('user:connected', user => console.table(user));
|
||||
|
||||
useEffect(() => {
|
||||
if (stat) {
|
||||
setOnline(stat.online);
|
||||
}
|
||||
}, [stat]);
|
||||
|
||||
if (me === null || courses === null || stat === null) return <LoadingPage />;
|
||||
|
||||
@ -63,7 +48,7 @@ const MainPage: React.FC<IPageProps> = () => {
|
||||
<Stat>
|
||||
<StatLabel>Online</StatLabel>
|
||||
<StatContent>
|
||||
<StatNumber>{online}</StatNumber>
|
||||
<StatNumber>{onlineStore.count}</StatNumber>
|
||||
<StatIcon icon={MdOutlineGroup} />
|
||||
</StatContent>
|
||||
</Stat>
|
||||
|
||||
@ -17,6 +17,7 @@ const UserPage: React.FC<IPageProps> = () => {
|
||||
const params = useParams<{ id: string }>();
|
||||
const {
|
||||
userStore: { me },
|
||||
onlineStore,
|
||||
} = useRootStore();
|
||||
const { data: user, error, isLoading } = useFetchUser(params.id);
|
||||
|
||||
@ -34,7 +35,7 @@ const UserPage: React.FC<IPageProps> = () => {
|
||||
<Page.Content maxW={'900px'}>
|
||||
<UserProfile>
|
||||
<UserProfile.Base>
|
||||
<UserProfile.Avatar name={user.fullname} isOnline>
|
||||
<UserProfile.Avatar name={user.fullname} isOnline={onlineStore.isOnline(user.id)}>
|
||||
<UserProfile.ChatButton userid={user.id} />
|
||||
</UserProfile.Avatar>
|
||||
<UserProfile.Info>
|
||||
|
||||
27
src/stores/OnlineStore.ts
Normal file
27
src/stores/OnlineStore.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import RootStore from './RootStore';
|
||||
|
||||
export default class OnlineStore {
|
||||
public root: RootStore;
|
||||
|
||||
public online: Set<string>;
|
||||
|
||||
constructor(root: RootStore) {
|
||||
this.root = root;
|
||||
this.online = new Set();
|
||||
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public loadOnline(online: string[]) {
|
||||
this.online = new Set(online);
|
||||
}
|
||||
|
||||
public isOnline(id: string) {
|
||||
return this.online.has(id);
|
||||
}
|
||||
|
||||
public get count() {
|
||||
return this.online.size;
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import UIStore from './UIStore';
|
||||
import CategoryStore from './CategoryStore';
|
||||
import CourseStore from './CourseStore';
|
||||
import PageStore from './PageStore';
|
||||
import OnlineStore from './OnlineStore';
|
||||
|
||||
export default class RootStore {
|
||||
public pageStore: PageStore;
|
||||
@ -23,6 +24,8 @@ export default class RootStore {
|
||||
|
||||
public userStore: UserStore;
|
||||
|
||||
public onlineStore: OnlineStore;
|
||||
|
||||
constructor() {
|
||||
/**
|
||||
* Stores
|
||||
@ -33,6 +36,7 @@ export default class RootStore {
|
||||
this.pageStore = new PageStore(this);
|
||||
this.uiStore = new UIStore(this);
|
||||
this.userStore = new UserStore(this);
|
||||
this.onlineStore = new OnlineStore(this);
|
||||
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import {
|
||||
CreateUserParamsType,
|
||||
FetchUsersParamsType,
|
||||
UpdateUserContactsParamsType,
|
||||
UpdateUserInfoParamsType,
|
||||
UpdateUserParamsType,
|
||||
} from '@educt/types';
|
||||
import { IUser, IMe, IPaginationMeta } from '@educt/interfaces';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user