feat(socketio): get users online and offline (users status)
This commit is contained in:
parent
b0e8794d94
commit
526804c291
|
|
@ -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)
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# ----------------------------- Local Environment ---------------------------- #
|
||||
|
||||
NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000/api"
|
||||
|
||||
NEXT_PUBLIC_WS_ENPOINT="http://localhost:5000/"
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
|
|
|
|||
2398
frontend/package-lock.json
generated
2398
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -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": {
|
||||
|
|
|
|||
59
frontend/src/contexts/socketio-context.js
Normal file
59
frontend/src/contexts/socketio-context.js
Normal 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);
|
||||
|
|
@ -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
147
frontend/src/pages/chat.js
Normal 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;
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user