feat(socketio): get users online and offline (users status)

This commit is contained in:
Leandro Antônio Farias Machado 2023-06-18 22:25:16 -03:00
parent b0e8794d94
commit 526804c291
8 changed files with 2610 additions and 43 deletions

View File

@ -17,18 +17,20 @@ let users = []
io.on('connection', (socket) => {
console.log(`🚀: ${socket.id} user just connected!`);
const sessionId = socket.id
socket.on("newuser", (data) => {
users.push(data)
console.log(data)
console.log("total users: ", users)
io.emit('users', users)
})
socket.on("getusers", () => {
socket.broadcast.emit('users', )
});
socket.on('disconnect', () => {
console.log('🔥: A user disconnected');
users.splice(users.findIndex(x => x.id === sessionId), 1);
console.log("users after disconection: ", users)
io.emit('users', users)
});
});

View File

@ -1,7 +1,7 @@
# ----------------------------- Local Environment ---------------------------- #
NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000/api"
NEXT_PUBLIC_WS_ENPOINT="http://localhost:5000/"
# ---------------------------------------------------------------------------- #

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@
"react-apexcharts": "1.4.0",
"react-dom": "18.2.0",
"simplebar-react": "^3.2.1",
"socket.io-client": "^4.6.2",
"styled-components": "^6.0.0-rc.3",
"yup": "1.0.0"
},
"devDependencies": {

View File

@ -0,0 +1,59 @@
import { createContext, useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import io from 'socket.io-client';
import { useAuth } from 'src/hooks/use-auth';
// The role of this context is to propagate socketio io state through app tree
export const WsContext = createContext({ undefined });
export const WsProvider = (props) => {
const { children } = props;
const [users, setUsers] = useState([])
const auth = useAuth()
const initialize = async () => {
// Prevent from calling twice in development mode with React.StrictMode enable
const socket = io(process.env.NEXT_PUBLIC_WS_ENPOINT)
socket.on('connect', () => {
console.log('[IO] Connect => A new connection has been established')
socket.on("users", (data) => {
setUsers(data)
console.log("data received from users event: ", users)
})
socket.emit("newuser",{
id:socket.id,
name: window.sessionStorage.getItem("email")
})
})
};
useEffect(
() => {
if(auth.isAuthenticated){
initialize();
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[auth.isAuthenticated]
);
return (
<WsContext.Provider
value={{
users,
}}
>
{children}
</WsContext.Provider>
);
};
WsProvider.propTypes = {
children: PropTypes.node
};
export const WsConsumer = WsContext.Consumer;
export const useWsContext = () => useContext(WsContext);

View File

@ -1,12 +1,8 @@
import ChartBarIcon from '@heroicons/react/24/solid/ChartBarIcon';
import CogIcon from '@heroicons/react/24/solid/CogIcon';
import LockClosedIcon from '@heroicons/react/24/solid/LockClosedIcon';
import ShoppingBagIcon from '@heroicons/react/24/solid/ShoppingBagIcon';
import UserIcon from '@heroicons/react/24/solid/UserIcon';
import UserPlusIcon from '@heroicons/react/24/solid/UserPlusIcon';
import UsersIcon from '@heroicons/react/24/solid/UsersIcon';
import ChatBubbleLeftRightIcon from '@heroicons/react/24/solid/ChatBubbleLeftRightIcon'
import MapIcon from '@heroicons/react/24/solid/MapIcon'
import CpuChip from '@heroicons/react/24/solid/CpuChipIcon';
import XCircleIcon from '@heroicons/react/24/solid/XCircleIcon';
import { SvgIcon } from '@mui/material';
export const items = [
@ -28,6 +24,24 @@ export const items = [
</SvgIcon>
)
},
{
title: 'Chat',
path: '/chat',
icon: (
<SvgIcon fontSize="small">
<ChatBubbleLeftRightIcon/>
</SvgIcon>
)
},
{
title: 'Map',
path: '/',
icon: (
<SvgIcon fontSize="small">
<MapIcon/>
</SvgIcon>
)
},
{
title: 'Settings',
path: '/settings',

147
frontend/src/pages/chat.js Normal file
View File

@ -0,0 +1,147 @@
import React, { useEffect, useState, useContext } from "react";
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
import PhoneIcon from "@heroicons/react/24/solid/PhoneIcon";
import PhoneXMarkIcon from "@heroicons/react/24/solid/PhoneXMarkIcon"
import {
Card,
Box,
CardContent,
Container,
SvgIcon,
CircularProgress,
Avatar,
Backdrop,
} from "@mui/material";
import { WsContext } from "src/contexts/socketio-context";
const Page = () => {
//const [isConnected, setIsConnected] = useState(socket.connected);
const [users, setUsers] = useState([])
//const [onlineUsers, setOnlineUsers] = useState([])
const ws = useContext(WsContext)
useEffect(()=>{
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", localStorage.getItem("token"));
var requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/users`,requestOptions)
.then(response => response.json())
.then(result => {
// let teste = JSON.stringify(JSON.parse(result), null, 2)
setUsers(result)
})
.catch(error => console.log('error', error));
},[])
const renderUsers = () => {
console.log("users: ", users)
console.log("wsUsers: ", ws.users)
if(users.length == 0){
console.log("users is empty")
return (
<div style={{display:'flex', justifyContent:'center'}} height={'100%'} >
<CircularProgress color="inherit" width='100%'/>
</div>
)
}else {
return (
<Card sx={{
display: 'flex',
justifyContent:'center',
}}>
<CardContent>
<Container sx={{display:'flex',justifyContent:'center'}}>
{users.map((x)=> {
let color = "#CB1E02"
let status = "offline"
if (ws.users.findIndex(y => y.name === x.email) >= 0){
console.log("user: "+x.email+" is online")
//color = "#11ADFB"
color = "#17A000"
status = "online"
}
if (x.email !== window.sessionStorage.getItem("email")){
return (
<Box sx={{margin:"30px",textAlign:'center'}}>
<Avatar
sx={{
height: 150,
width: 150,
border: '3px solid '+color
}}
src={"/assets/avatars/default-avatar.png"}
/>
<div style={{marginTop:'10px'}}>
</div>
<SvgIcon
sx={{cursor:'pointer'}}
>
{status === "online" ?
<PhoneIcon
color={color}
onClick={()=>{
console.log("call", x.email)
}}
title={"call"}
/>
:
<PhoneXMarkIcon
color={color}
onClick={()=>{
console.log("call", x.email)
}}
title={"offline"}
/>
}
</SvgIcon>
<p style={{marginTop:'-2.5px'}}>{x.email}</p>
</Box>
)
}
})}
</Container>
</CardContent>
</Card>
)
}
}
return(ws.users.length > 1 ?
<Box
component="main"
sx={{
flexGrow: 1,
py: 10,
alignItems: 'center',
flexDirection: 'column',
}}
>
<Container maxWidth="md">
{renderUsers()}
</Container>
</Box>
:
<CircularProgress color="inherit" />
)
}
Page.getLayout = (page) => (
<DashboardLayout>
{page}
</DashboardLayout>
);
export default Page;

View File

@ -1,4 +1,5 @@
import Head from 'next/head';
import React, { useState } from 'react';
import { subDays, subHours } from 'date-fns';
import { Box, Container, Unstable_Grid2 as Grid } from '@mui/material';
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
@ -13,7 +14,9 @@ import { OverviewTraffic } from 'src/sections/overview/overview-traffic';
const now = new Date();
const Page = () => (
const Page = () => {
return(
<>
<Head>
<title>
@ -109,8 +112,8 @@ const Page = () => (
</Grid>
</Container>
</Box>
</>
);
</>)
};
Page.getLayout = (page) => (
<DashboardLayout>