Skip to content

Commit 8fd4163

Browse files
committed
set live chart and mock websocket
1 parent 414245d commit 8fd4163

11 files changed

Lines changed: 316 additions & 30 deletions

File tree

mockWebSocketServer.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const WebSocket = require('ws');
2+
3+
const wss = new WebSocket.Server({ port: 8080 });
4+
5+
function sendRandomData(ws) {
6+
const score = Math.random();
7+
const dataPoint = {
8+
id: Date.now(),
9+
score,
10+
response_text: score > 0.5 ? 'Safe response' : 'Unsafe response',
11+
timestamp: new Date().toISOString(),
12+
is_safe: score > 0.5,
13+
};
14+
ws.send(JSON.stringify(dataPoint));
15+
}
16+
17+
wss.on('connection', (ws) => {
18+
console.log('Client connected');
19+
20+
// Send data every 2 seconds
21+
const interval = setInterval(() => {
22+
sendRandomData(ws);
23+
}, 2000);
24+
25+
ws.on('close', () => {
26+
clearInterval(interval);
27+
console.log('Client disconnected');
28+
});
29+
});
30+
// run by :node mockWebSocketServer.js
31+
console.log('WebSocket server is running on ws://localhost:8080 ');

package-lock.json

Lines changed: 53 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
"axios": "^1.6.7",
2121
"axios-auth-refresh": "^3.3.6",
2222
"base-64": "^1.0.0",
23+
"chart.js": "^4.4.4",
2324
"flowbite": "^2.3.0",
2425
"moment": "^2.30.1",
2526
"next": "^14.2.5",
2627
"next-recaptcha-v3": "^1.3.0",
2728
"react": "^18",
29+
"react-chartjs-2": "^5.2.0",
2830
"react-cookie": "^7.1.0",
2931
"react-countdown": "^2.3.5",
3032
"react-dom": "^18",
@@ -35,7 +37,8 @@
3537
"react-slick": "^0.30.2",
3638
"react-tooltip": "^5.26.4",
3739
"redux": "^5.0.1",
38-
"redux-saga": "^1.3.0"
40+
"redux-saga": "^1.3.0",
41+
"ws": "^8.18.0"
3942
},
4043
"devDependencies": {
4144
"@reduxjs/toolkit": "^2.1.0",

public/Icons/index.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,44 @@ export default function Icons(props: IconsProps) {
10291029
strokeWidth="2.51637" strokeLinecap="round" />
10301030
</svg>
10311031

1032+
)
1033+
case 'chart-live':
1034+
return (
1035+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
1036+
<path
1037+
d="M3 3V21H21V3"
1038+
stroke="#191919" strokeWidth="1.5" />
1039+
<path
1040+
d="M7 14L10 11L13 15L17 10"
1041+
stroke="#191919" strokeWidth="1.5" />
1042+
<circle
1043+
cx="18"
1044+
cy="6"
1045+
r="2"
1046+
fill="none"
1047+
stroke="#191919"
1048+
strokeWidth="1.5" />
1049+
</svg>
1050+
1051+
)
1052+
case 'chart-live-filled':
1053+
return (
1054+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
1055+
<path
1056+
d="M3 3V21H21V3"
1057+
stroke="#00B4FF" strokeWidth="1.5" />
1058+
<path
1059+
d="M7 14L10 11L13 15L17 10"
1060+
stroke="#00B4FF" strokeWidth="1.5" />
1061+
<circle
1062+
cx="18"
1063+
cy="6"
1064+
r="2"
1065+
fill="#D1F1FF"
1066+
stroke="#00B4FF"
1067+
strokeWidth="1.5" />
1068+
</svg>
1069+
10321070
)
10331071
case 'headphones':
10341072
return (

src/app/(pages)/liveData/page.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use client'
2+
import Sidebar from "@/app/components/Sidebar";
3+
import { useShowInnerComponent } from "@/app/ShowInnerComponentContext";
4+
import isMobileView from "@/app/utils/isMobileView";
5+
import Icons from "../../../../public/Icons";
6+
import { useRouter } from "next/navigation";
7+
import { useState } from "react";
8+
import defaultSidebarStatus from "@/app/utils/defaultSidebarStatus";
9+
import LiveData from "@/app/components/LiveData";
10+
11+
export default function LiveDataPage() {
12+
const { setShowInnerComponent } = useShowInnerComponent();
13+
const [isSidebarOpen, setIsSidebarOpen] = useState<boolean>(defaultSidebarStatus);
14+
const router = useRouter();
15+
16+
return (
17+
<>
18+
{isMobileView ? (
19+
<div className={'text-secondary-17 bg-secondary-02' + `${isMobileView ? ' w-screen h-screen' : ''}`}>
20+
<div className={'bg-secondary-01 px-3 py-9' + ` ${isMobileView ? 'space-y-3' : 'hidden'}`}>
21+
{isMobileView &&
22+
<div className={'mb-8'}>
23+
<button
24+
className={'absolute'}
25+
onClick={() => { setShowInnerComponent(false)}}
26+
>
27+
<Icons name={'right-arrow-key'} />
28+
</button>
29+
<h1 className={'font-bold w-fit m-auto'}>Management</h1>
30+
</div>
31+
}
32+
33+
</div>
34+
35+
<LiveData/>
36+
37+
</div>
38+
39+
) : (
40+
<Sidebar isSidebarOpen={isSidebarOpen} setIsSidebarOpen={setIsSidebarOpen}
41+
children={<>
42+
43+
<LiveData/>
44+
45+
</>} />
46+
)}
47+
</>
48+
49+
50+
51+
)
52+
}

src/app/components/Alerts/DataTable/PasswordInputWithToggle.tsx

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { useState, useEffect } from 'react';
2+
import {
3+
Chart as ChartJS,
4+
LineElement,
5+
PointElement,
6+
LinearScale,
7+
Title,
8+
Tooltip,
9+
CategoryScale,
10+
} from 'chart.js';
11+
import { Line } from 'react-chartjs-2';
12+
import { ChartData, ChartOptions } from 'chart.js';
13+
14+
// Register the necessary components
15+
ChartJS.register(LineElement, PointElement, LinearScale, Title, Tooltip, CategoryScale);
16+
17+
interface DataPoint {
18+
id: number;
19+
score: number;
20+
response_text: string;
21+
timestamp: string;
22+
is_safe: boolean;
23+
}
24+
25+
function LiveChart() {
26+
const [data, setData] = useState<DataPoint[]>([]);
27+
28+
useEffect(() => {
29+
const socket = new WebSocket('ws://localhost:8080');
30+
31+
socket.onmessage = (event: MessageEvent) => {
32+
const newDataPoint: DataPoint = JSON.parse(event.data);
33+
setData((prevData) => [...prevData, newDataPoint].slice(-10));
34+
};
35+
36+
return () => {
37+
socket.close();
38+
};
39+
}, []);
40+
41+
const chartData: ChartData<'line'> = {
42+
labels: data.map(d => new Date(d.timestamp).toLocaleTimeString()),
43+
datasets: [
44+
{
45+
label: 'Safety Score',
46+
data: data.map(d => d.score),
47+
fill: false,
48+
backgroundColor: data.map(d => d.is_safe ? 'rgb(75, 192, 192)' : 'rgb(255, 99, 132)'),
49+
borderColor: 'rgba(75, 192, 192, 0.2)',
50+
},
51+
],
52+
};
53+
54+
const options: ChartOptions<'line'> = {
55+
scales: {
56+
y: {
57+
beginAtZero: true,
58+
max: 1,
59+
title: {
60+
display: true,
61+
text: 'Safety Score',
62+
},
63+
},
64+
},
65+
plugins: {
66+
tooltip: {
67+
callbacks: {
68+
label: function (tooltipItem) {
69+
return `Score: ${tooltipItem.raw}`;
70+
},
71+
afterLabel: function (tooltipItem) {
72+
const dataIndex = tooltipItem.dataIndex;
73+
return `Response: ${data[dataIndex].response_text}`;
74+
},
75+
},
76+
},
77+
},
78+
};
79+
80+
return (
81+
<div>
82+
<h2>Live Safety Score Chart</h2>
83+
<Line data={chartData} options={options} />
84+
</div>
85+
);
86+
}
87+
88+
export default LiveChart;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { UserRole } from "@/store/userProfile/interface";
2+
3+
export interface User {
4+
email: string;
5+
password: string;
6+
role: UserRole;
7+
}

0 commit comments

Comments
 (0)