Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb975ce11a | ||
|
|
a3d2bea0cc | ||
|
|
420171d24a | ||
|
|
dd4ee6d964 | ||
|
|
62810fe81b | ||
|
|
aa08336f5f | ||
|
|
66838b6360 | ||
|
|
3774972839 | ||
|
|
924e48c1f0 | ||
|
|
36879b6326 | ||
|
|
327aa07735 | ||
|
|
f269b12da1 | ||
|
|
cb0063e286 | ||
|
|
3e01c94e46 | ||
|
|
cde2485a60 | ||
|
|
9893161684 | ||
|
|
eecc6501df | ||
|
|
47d348d791 | ||
|
|
16b3f521d4 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -27,3 +27,7 @@ yarn-error.log*
|
||||
src/components/testData.json
|
||||
public/world-110m.json
|
||||
public/india-states.json
|
||||
*.apk
|
||||
|
||||
scripts/reports
|
||||
scripts/data
|
||||
BIN
logo_nobg.png
Normal file
BIN
logo_nobg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
3007
package-lock.json
generated
3007
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -3,6 +3,11 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/icons-material": "^5.14.1",
|
||||
"@mui/material": "^5.14.2",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
@@ -14,10 +19,12 @@
|
||||
"ml-savitzky-golay-generalized": "^4.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"react": "^18.2.0",
|
||||
"react-datepicker": "^4.16.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dropdown": "^1.11.0",
|
||||
"react-flip-numbers": "^3.0.8",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router-dom": "^6.14.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-select": "^5.7.4",
|
||||
@@ -49,5 +56,9 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"csv-parser": "^3.0.0",
|
||||
"html-pdf-node": "^1.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
281
scripts/pdf.js
Normal file
281
scripts/pdf.js
Normal file
File diff suppressed because one or more lines are too long
16
src/App.js
16
src/App.js
@@ -2,11 +2,27 @@ import './App.css';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import moment from 'moment';
|
||||
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
import MainLayout from "./components/MainLayout";
|
||||
import { routes } from "./routes";
|
||||
|
||||
import { collection, onSnapshot, query } from "firebase/firestore";
|
||||
import Card from './components/Card';
|
||||
import db from './firebase';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<MainLayout />}>
|
||||
{routes}
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
function App1() {
|
||||
const [totalScreened, setTotalScreened] = useState(0);
|
||||
const [males, setMales] = useState(0);
|
||||
const [females, setFemales] = useState(0);
|
||||
|
||||
BIN
src/assets/hpos-testing_preprod.png
Normal file
BIN
src/assets/hpos-testing_preprod.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/hpos_testing_preprod_2.1.10d.png
Normal file
BIN
src/assets/hpos_testing_preprod_2.1.10d.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/testing_2_1_10.png
Normal file
BIN
src/assets/testing_2_1_10.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
0
src/components/Alerts.css
Normal file
0
src/components/Alerts.css
Normal file
39
src/components/Alerts.js
Normal file
39
src/components/Alerts.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { query, collection, onSnapshot } from 'firebase/firestore';
|
||||
|
||||
import './Alerts.css';
|
||||
import db from '../firebase';
|
||||
|
||||
const Alerts = () => {
|
||||
const [alerts, setAlerts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!allTests) {
|
||||
const q = query(collection(db, "alerts"));
|
||||
|
||||
const unsub = onSnapshot(q, (querySnapshot) => {
|
||||
const testDevices = new Set();
|
||||
const hposTests = [];
|
||||
querySnapshot.forEach((document) => {
|
||||
const hposTestData = document.data();
|
||||
hposTests.push(hposTestData);
|
||||
const { deviceSerialNumber } = hposTestData;
|
||||
testDevices.add(deviceSerialNumber);
|
||||
});
|
||||
const groups = [...testDevices];
|
||||
// setDevices(groups);
|
||||
setAlerts(hposTests);
|
||||
});
|
||||
|
||||
return () => unsub;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{alerts.length}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Alerts;
|
||||
4
src/components/AppInstallation.css
Normal file
4
src/components/AppInstallation.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.app-qrcode {
|
||||
height: 250px;
|
||||
width: 250px;
|
||||
}
|
||||
35
src/components/AppInstallation.js
Normal file
35
src/components/AppInstallation.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { query, collection, onSnapshot } from 'firebase/firestore';
|
||||
|
||||
import './AppInstallation.css';
|
||||
import db from '../firebase';
|
||||
|
||||
const AppInstallation = () => {
|
||||
const [alerts, setAlerts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<div>Testing 2.1.27 (Preprod - 07-11-2023)</div>
|
||||
<a href="https://www.dropbox.com/scl/fi/v0hux8qrby54rjns8mhum/hpos-testing_preprod_2.1.27.apk?rlkey=ias0fe0zq72avy01rk4cvzmvp&dl=1">
|
||||
<img className="app-qrcode" src={require('../assets/hpos-testing_preprod.png')} alt='icon'></img>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<p>Steps to install:</p>
|
||||
<p>
|
||||
<ul>
|
||||
<li>use an QR code scanner app to download the app</li>
|
||||
<li>if the phone browser prompts an warning, select download anyway</li>
|
||||
<li>install the downloaded apk and give permissions</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AppInstallation;
|
||||
@@ -24,7 +24,7 @@ const Devices = () => {
|
||||
setTestDate(null);
|
||||
setCurTest(null);
|
||||
setDays([...new Set(allTests
|
||||
.filter((x) => x.deviceSerialNumber === value)
|
||||
.filter((x) => x.deviceSerialNumber === value || x.deviceId === value)
|
||||
.map(x => moment(x.testTime).format("YYYY-MM-DD")))]
|
||||
.sort()
|
||||
.reverse());
|
||||
@@ -36,7 +36,7 @@ const Devices = () => {
|
||||
setCurTestData(null);
|
||||
setShowGraph(false);
|
||||
setTests(allTests
|
||||
.filter((x) => x.deviceSerialNumber === device && moment(x.testTime).isBetween(moment(value).startOf('day'), moment(value).endOf('day')))
|
||||
.filter((x) => (x.deviceSerialNumber === device || x.deviceId === device) && moment(x.testTime).isBetween(moment(value).startOf('day'), moment(value).endOf('day')))
|
||||
.map(x => x._id)
|
||||
.sort());
|
||||
}
|
||||
@@ -70,8 +70,13 @@ const Devices = () => {
|
||||
querySnapshot.forEach((document) => {
|
||||
const hposTestData = document.data();
|
||||
hposTests.push(hposTestData);
|
||||
const { deviceSerialNumber } = hposTestData;
|
||||
testDevices.add(deviceSerialNumber);
|
||||
const { deviceType, deviceId, deviceSerialNumber } = hposTestData;
|
||||
if (deviceType === 'HEMOCUBE' && deviceId) {
|
||||
testDevices.add(deviceId);
|
||||
}
|
||||
if (deviceType !== 'HEMOCUBE' && deviceSerialNumber) {
|
||||
testDevices.add(deviceSerialNumber);
|
||||
}
|
||||
});
|
||||
const groups = [...testDevices];
|
||||
setDevices(groups);
|
||||
|
||||
29
src/components/ExportData.css
Normal file
29
src/components/ExportData.css
Normal file
@@ -0,0 +1,29 @@
|
||||
.button {
|
||||
background-color: #4CAF50;
|
||||
/* Green */
|
||||
border: none;
|
||||
color: white;
|
||||
/* padding: 15px 32px; */
|
||||
padding: 5px 10px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.dates {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 1.5rem;
|
||||
}
|
||||
|
||||
.start-date {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.end-date {
|
||||
margin: 10px;
|
||||
}
|
||||
32
src/components/ExportData.js
Normal file
32
src/components/ExportData.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import React, { useState } from 'react';
|
||||
import DatePicker from "react-datepicker";
|
||||
import moment from 'moment';
|
||||
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
|
||||
import './ExportData.css';
|
||||
|
||||
function ExportData({ url, show }) {
|
||||
const [startDate, setStartDate] = useState("");
|
||||
const [endDate, setEndDate] = useState("");
|
||||
|
||||
const fetchFile = (start_date, end_date) => {
|
||||
window.location.href = `https://asia-south1-hpos-preprod.cloudfunctions.net/consolidation?start_date=${moment(startDate).format("YYYY-MM-DD")}&end_date=${moment(endDate).format("YYYY-MM-DD")}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='dates'>
|
||||
<div className='start-date'>
|
||||
<DatePicker selected={startDate} onChange={(date) => setStartDate(date)} placeholderText='start date' />
|
||||
</div>
|
||||
<div className='end-date'>
|
||||
<DatePicker selected={endDate} onChange={(date) => setEndDate(date)} placeholderText='end date' />
|
||||
</div>
|
||||
|
||||
<div className='button' onClick={() => fetchFile(startDate, endDate)}>Download Excel</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default ExportData;
|
||||
9
src/components/HomePage.js
Normal file
9
src/components/HomePage.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
const HomePage = (props) => {
|
||||
return (
|
||||
<div>HomePage</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
||||
38
src/components/MainLayout.js
Normal file
38
src/components/MainLayout.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { Box, Toolbar } from "@mui/material";
|
||||
import colorConfigs from "../configs/colorConfigs";
|
||||
import sizeConfigs from "../configs/sizeConfigs";
|
||||
import Sidebar from "./nav/Sidebar";
|
||||
import Topbar from "./nav/Topbar";
|
||||
|
||||
const MainLayout = () => {
|
||||
return (
|
||||
<Box sx={{ display: "flex" }}>
|
||||
<Topbar />
|
||||
<Box
|
||||
component="nav"
|
||||
sx={{
|
||||
width: sizeConfigs.sidebar.width,
|
||||
flexShrink: 0
|
||||
}}
|
||||
>
|
||||
<Sidebar />
|
||||
</Box>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
p: 3,
|
||||
width: `calc(100% - ${sizeConfigs.sidebar.width})`,
|
||||
minHeight: "100vh",
|
||||
backgroundColor: colorConfigs.mainBg
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
<Outlet />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
19
src/components/PageWrapper.js
Normal file
19
src/components/PageWrapper.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { setAppState } from "../store/appStateSlice";
|
||||
|
||||
const PageWrapper = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (props.state) {
|
||||
dispatch(setAppState(props.state));
|
||||
}
|
||||
}, [dispatch, props]);
|
||||
|
||||
return (
|
||||
<>{props.children}</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageWrapper;
|
||||
28
src/components/Registration.css
Normal file
28
src/components/Registration.css
Normal file
@@ -0,0 +1,28 @@
|
||||
.message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80vw;
|
||||
height: 50px;
|
||||
background-color: rgb(187, 218, 174);
|
||||
}
|
||||
|
||||
.user-creation {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clear-users-button {
|
||||
background-color: #b62200;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 5px;
|
||||
}
|
||||
106
src/components/Registration.js
Normal file
106
src/components/Registration.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import React, { useState } from 'react';
|
||||
import moment from 'moment';
|
||||
import axios from 'axios';
|
||||
|
||||
import './Registration.css';
|
||||
|
||||
function Registration() {
|
||||
const [userId, setUserId] = useState("2808202300103SMIBLR");
|
||||
const [counter, setCounter] = useState(0);
|
||||
const [message, setMessage] = useState("");
|
||||
const [name, setName] = useState("");
|
||||
|
||||
const createUser = () => {
|
||||
setMessage("");
|
||||
const id = moment().unix() + counter + "SMIBLR";
|
||||
setCounter(counter + 1);
|
||||
axios({
|
||||
method: 'post',
|
||||
url: "https://asia-south1-hpos-preprod.cloudfunctions.net/registerUser",
|
||||
data: {
|
||||
"_id": id,
|
||||
"aadharId": "2808202300001",
|
||||
"abhaId": "12434949797979",
|
||||
"birthYear": "2000",
|
||||
"bloodGroup": "",
|
||||
"careOf": "",
|
||||
"caste": "",
|
||||
"city": "Bengaluru",
|
||||
"district": "Bengaluru",
|
||||
"gender": "Male",
|
||||
"house": "42",
|
||||
"maritalStatus": "Single",
|
||||
"name": name ? name : "Web",
|
||||
"phoneNumber": "9123456789",
|
||||
"pinCode": "560060",
|
||||
"registeredBy": "admin",
|
||||
"registrationCenterName": "SMI",
|
||||
"sickleCellHistory": null,
|
||||
"state": "Karnataka",
|
||||
"subCaste": "",
|
||||
"testStatus": false,
|
||||
"incubationTime": moment().subtract('15', 'minutes').utcOffset("+05:30").format("YYYY-MM-DD HH:mm:ss"),
|
||||
"underMedication": false,
|
||||
"underTransfusion": false,
|
||||
"userImageURL": "https://hpos-prod.web.app/logo.png"
|
||||
},
|
||||
withCredentials: false,
|
||||
secure: false,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-client": "e16a1bd15af2ee640f5a7a18c8d8333f5f01f7c66e003bbc21ee52870f1bce27",
|
||||
},
|
||||
})
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
setMessage(`${id} is being created`);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setMessage(`error: ${err?.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
const clearsUsers = () => {
|
||||
setMessage("");
|
||||
axios({
|
||||
method: 'get',
|
||||
url: "https://asia-south1-hpos-preprod.cloudfunctions.net/clearUsers",
|
||||
withCredentials: false,
|
||||
secure: false,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
// "x-client": "e16a1bd15af2ee640f5a7a18c8d8333f5f01f7c66e003bbc21ee52870f1bce27",
|
||||
},
|
||||
})
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
setMessage(`${data}`);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setMessage(`error: ${err?.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
const onNameChange = (event) => {
|
||||
setName(event.target.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="user-creation">
|
||||
<label>
|
||||
name:
|
||||
<input name="name" value={name} placeholder="350umol kmon04" onChange={onNameChange} />
|
||||
</label>
|
||||
<div className='dates'>
|
||||
<div className='button' onClick={() => createUser()}>Create User</div>
|
||||
</div>
|
||||
<div className='dates'>
|
||||
<div className='clear-users-button' onClick={() => clearsUsers()}>Clear</div>
|
||||
</div>
|
||||
<div>{message && <div className='message'>{message}</div>}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Registration;
|
||||
@@ -25,9 +25,9 @@ class TestAnalyticsGraph extends Component {
|
||||
|
||||
data.reverse();
|
||||
|
||||
var margin = { top: 60, right: 20, bottom: 30, left: 50 },
|
||||
width = 520 - margin.left - margin.right,
|
||||
height = 220 - margin.top - margin.bottom;
|
||||
var margin = { top: 30, right: 20, bottom: 50, left: 15 },
|
||||
width = 1500 - margin.left - margin.right,
|
||||
height = 180 - margin.top - margin.bottom;
|
||||
|
||||
var svg = d3.select("#tests-count-graph").append('svg')
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
|
||||
50
src/components/nav/Sidebar.js
Normal file
50
src/components/nav/Sidebar.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Avatar, Drawer, List, Stack, Toolbar } from "@mui/material";
|
||||
|
||||
// import assets from "../../assets";
|
||||
import colorConfigs from "../../configs/colorConfigs";
|
||||
import sizeConfigs from "../../configs/sizeConfigs";
|
||||
import appRoutes from "../../routes/appRoutes";
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import SidebarItemCollapse from "./SidebarItemCollapse";
|
||||
|
||||
const Sidebar = () => {
|
||||
return (
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
width: sizeConfigs.sidebar.width,
|
||||
flexShrink: 0,
|
||||
"& .MuiDrawer-paper": {
|
||||
width: sizeConfigs.sidebar.width,
|
||||
boxSizing: "border-box",
|
||||
borderRight: "0px",
|
||||
backgroundColor: colorConfigs.sidebar.bg,
|
||||
color: colorConfigs.sidebar.color
|
||||
}
|
||||
}}
|
||||
>
|
||||
<List disablePadding>
|
||||
<Toolbar sx={{ marginBottom: "20px" }}>
|
||||
<Stack
|
||||
sx={{ width: "100%" }}
|
||||
direction="row"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Avatar src={require('../../smi-logo-120x120.webp')} />
|
||||
</Stack>
|
||||
</Toolbar>
|
||||
{appRoutes.map((route, index) => (
|
||||
route.sidebarProps ? (
|
||||
route.child ? (
|
||||
<SidebarItemCollapse item={route} key={index} />
|
||||
) : (
|
||||
<SidebarItem item={route} key={index} />
|
||||
)
|
||||
) : null
|
||||
))}
|
||||
</List>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
34
src/components/nav/SidebarItem.js
Normal file
34
src/components/nav/SidebarItem.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ListItemButton, ListItemIcon } from "@mui/material";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import colorConfigs from "../../configs/colorConfigs";
|
||||
|
||||
const SidebarItem = ({ item }) => {
|
||||
const { appState } = useSelector((state) => state.appState);
|
||||
|
||||
return (
|
||||
item.sidebarProps && item.path ? (
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={item.path}
|
||||
sx={{
|
||||
"&: hover": {
|
||||
backgroundColor: colorConfigs.sidebar.hoverBg
|
||||
},
|
||||
backgroundColor: appState === item.state ? colorConfigs.sidebar.activeBg : "unset",
|
||||
paddingY: "12px",
|
||||
paddingX: "24px"
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{
|
||||
color: colorConfigs.sidebar.color
|
||||
}}>
|
||||
{item.sidebarProps.icon && item.sidebarProps.icon}
|
||||
</ListItemIcon>
|
||||
{item.sidebarProps.displayText}
|
||||
</ListItemButton>
|
||||
) : null
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarItem;
|
||||
66
src/components/nav/SidebarItemCollapse.js
Normal file
66
src/components/nav/SidebarItemCollapse.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Collapse, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import colorConfigs from "../../configs/colorConfigs";
|
||||
import ExpandLessOutlinedIcon from '@mui/icons-material/ExpandLessOutlined';
|
||||
import ExpandMoreOutlinedIcon from '@mui/icons-material/ExpandMoreOutlined';
|
||||
import SidebarItem from "./SidebarItem";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const SidebarItemCollapse = ({ item }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { appState } = useSelector((state) => state.appState);
|
||||
|
||||
useEffect(() => {
|
||||
if (appState.includes(item.state)) {
|
||||
setOpen(true);
|
||||
}
|
||||
}, [appState, item]);
|
||||
|
||||
return (
|
||||
item.sidebarProps ? (
|
||||
<>
|
||||
<ListItemButton
|
||||
onClick={() => setOpen(!open)}
|
||||
sx={{
|
||||
"&: hover": {
|
||||
backgroundColor: colorConfigs.sidebar.hoverBg
|
||||
},
|
||||
paddingY: "12px",
|
||||
paddingX: "24px"
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{
|
||||
color: colorConfigs.sidebar.color
|
||||
}}>
|
||||
{item.sidebarProps.icon && item.sidebarProps.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
disableTypography
|
||||
primary={
|
||||
<Typography>
|
||||
{item.sidebarProps.displayText}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{open ? <ExpandLessOutlinedIcon /> : <ExpandMoreOutlinedIcon />}
|
||||
</ListItemButton>
|
||||
<Collapse in={open} timeout="auto">
|
||||
<List>
|
||||
{item.child?.map((route, index) => (
|
||||
route.sidebarProps ? (
|
||||
route.child ? (
|
||||
<SidebarItemCollapse item={route} key={index} />
|
||||
) : (
|
||||
<SidebarItem item={route} key={index} />
|
||||
)
|
||||
) : null
|
||||
))}
|
||||
</List>
|
||||
</Collapse>
|
||||
</>
|
||||
) : null
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarItemCollapse;
|
||||
26
src/components/nav/Topbar.js
Normal file
26
src/components/nav/Topbar.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { AppBar, Toolbar, Typography } from "@mui/material";
|
||||
import colorConfigs from "../../configs/colorConfigs";
|
||||
import sizeConfigs from "../../configs/sizeConfigs";
|
||||
|
||||
const Topbar = () => {
|
||||
return (
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{
|
||||
width: `calc(100% - ${sizeConfigs.sidebar.width})`,
|
||||
ml: sizeConfigs.sidebar.width,
|
||||
boxShadow: "unset",
|
||||
backgroundColor: colorConfigs.topbar.bg,
|
||||
color: colorConfigs.topbar.color
|
||||
}}
|
||||
>
|
||||
<Toolbar>
|
||||
<Typography variant="h6">
|
||||
HPOS dashboard
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
|
||||
export default Topbar;
|
||||
17
src/configs/colorConfigs.js
Normal file
17
src/configs/colorConfigs.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { colors } from "@mui/material";
|
||||
|
||||
const colorConfigs = {
|
||||
sidebar: {
|
||||
bg: "#233044",
|
||||
color: "#eeeeee",
|
||||
hoverBg: "#1e293a",
|
||||
activeBg: "#1e253a"
|
||||
},
|
||||
topbar: {
|
||||
bg: "#fff",
|
||||
color: "#000"
|
||||
},
|
||||
mainBg: colors.grey["100"]
|
||||
};
|
||||
|
||||
export default colorConfigs;
|
||||
7
src/configs/sizeConfigs.js
Normal file
7
src/configs/sizeConfigs.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const sizeConfigs = {
|
||||
sidebar: {
|
||||
width: "300px"
|
||||
}
|
||||
};
|
||||
|
||||
export default sizeConfigs;
|
||||
@@ -14,17 +14,28 @@ import { getAnalytics } from "firebase/analytics";
|
||||
// measurementId: "G-6JHQ47S9DD"
|
||||
// };
|
||||
|
||||
|
||||
/* preprod */
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyB2-suWmKh2PgQbRmx7rzPjYhgoovQIsQ8",
|
||||
authDomain: "hpos-preprod.firebaseapp.com",
|
||||
projectId: "hpos-preprod",
|
||||
storageBucket: "hpos-preprod.appspot.com",
|
||||
messagingSenderId: "121176529204",
|
||||
appId: "1:121176529204:web:6c0db8e642992192bbed61",
|
||||
measurementId: "G-GYM6LRQ8KR"
|
||||
};
|
||||
|
||||
/* prod */
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyBF4pLZReAedU4dWX1eRJNFNIaOIz2xk4s",
|
||||
authDomain: "hpos-prod.firebaseapp.com",
|
||||
projectId: "hpos-prod",
|
||||
storageBucket: "hpos-prod.appspot.com",
|
||||
messagingSenderId: "1012719870714",
|
||||
appId: "1:1012719870714:web:fcd00acef93f6612de5f43",
|
||||
measurementId: "G-B0NZ7DEF69"
|
||||
};
|
||||
// /* prod */
|
||||
// const firebaseConfig = {
|
||||
// apiKey: "AIzaSyBF4pLZReAedU4dWX1eRJNFNIaOIz2xk4s",
|
||||
// authDomain: "hpos-prod.firebaseapp.com",
|
||||
// projectId: "hpos-prod",
|
||||
// storageBucket: "hpos-prod.appspot.com",
|
||||
// messagingSenderId: "1012719870714",
|
||||
// appId: "1:1012719870714:web:fcd00acef93f6612de5f43",
|
||||
// measurementId: "G-B0NZ7DEF69"
|
||||
// };
|
||||
|
||||
|
||||
const app = initializeApp(firebaseConfig);
|
||||
|
||||
14
src/index.js
14
src/index.js
@@ -4,6 +4,9 @@ import {
|
||||
createBrowserRouter,
|
||||
RouterProvider,
|
||||
} from "react-router-dom";
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { store } from './store/store';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
@@ -11,6 +14,7 @@ import Devices from './components/Devices';
|
||||
import TestAnalytics from './components/TestAnalytics';
|
||||
import WorldMap from './components/WorldMap';
|
||||
import RegistraionChart from './RegistraionChart';
|
||||
import TestAnalyticsGraph from './components/TestAnalyticsGraph';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -29,6 +33,10 @@ const router = createBrowserRouter([
|
||||
path: "/analytics",
|
||||
element: <TestAnalytics />,
|
||||
},
|
||||
{
|
||||
path: "/hposdata",
|
||||
element: <TestAnalyticsGraph />,
|
||||
},
|
||||
{
|
||||
path: "/map",
|
||||
element: <RegistraionChart />,
|
||||
@@ -38,7 +46,11 @@ const router = createBrowserRouter([
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<RouterProvider router={router} />
|
||||
<Provider store={store}>
|
||||
{/* <CssBaseline /> */}
|
||||
{/* <RouterProvider router={router} /> */}
|
||||
<App />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
||||
66
src/routes/appRoutes.js
Normal file
66
src/routes/appRoutes.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import DashboardOutlinedIcon from '@mui/icons-material/DashboardOutlined';
|
||||
import AppsOutlinedIcon from '@mui/icons-material/AppsOutlined';
|
||||
|
||||
import TestAnalytics from "../components/TestAnalytics";
|
||||
import HomePage from '../components/HomePage';
|
||||
import Devices from '../components/Devices';
|
||||
import { Download } from '@mui/icons-material';
|
||||
import ExportData from '../components/ExportData';
|
||||
import Registration from '../components/Registration';
|
||||
import { FaAndroid, FaPhone, FaUser } from 'react-icons/fa';
|
||||
import AppInstallation from '../components/AppInstallation';
|
||||
|
||||
const appRoutes = [
|
||||
{
|
||||
index: true,
|
||||
element: <HomePage />,
|
||||
state: "home"
|
||||
},
|
||||
{
|
||||
path: "/analytics",
|
||||
element: <TestAnalytics />,
|
||||
state: "analytics",
|
||||
sidebarProps: {
|
||||
displayText: "Analytics",
|
||||
icon: <DashboardOutlinedIcon />
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/tests/insights",
|
||||
element: <Devices />,
|
||||
state: "insights",
|
||||
sidebarProps: {
|
||||
displayText: "Insights",
|
||||
icon: <AppsOutlinedIcon />
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/downloaddata",
|
||||
element: <ExportData />,
|
||||
state: "downloaddata",
|
||||
sidebarProps: {
|
||||
displayText: "Data Download",
|
||||
icon: <Download />
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/registration",
|
||||
element: <Registration />,
|
||||
state: "registration",
|
||||
sidebarProps: {
|
||||
displayText: "Registration",
|
||||
icon: <FaUser />
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/appinstallation",
|
||||
element: <AppInstallation />,
|
||||
state: "appinstallation",
|
||||
sidebarProps: {
|
||||
displayText: "App Installation",
|
||||
icon: <FaAndroid />
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
export default appRoutes;
|
||||
34
src/routes/index.js
Normal file
34
src/routes/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Route } from "react-router-dom";
|
||||
import PageWrapper from "../components/PageWrapper";
|
||||
import appRoutes from "./appRoutes";
|
||||
|
||||
const generateRoute = (routes) => {
|
||||
return routes.map((route, index) => (
|
||||
route.index ? (
|
||||
<Route
|
||||
index
|
||||
path={route.path}
|
||||
element={<PageWrapper state={route.state}>
|
||||
{route.element}
|
||||
</PageWrapper>}
|
||||
key={index}
|
||||
/>
|
||||
) : (
|
||||
<Route
|
||||
path={route.path}
|
||||
element={
|
||||
<PageWrapper state={route.child ? undefined : route.state}>
|
||||
{route.element}
|
||||
</PageWrapper>
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
{route.child && (
|
||||
generateRoute(route.child)
|
||||
)}
|
||||
</Route>
|
||||
)
|
||||
));
|
||||
};
|
||||
|
||||
export const routes = generateRoute(appRoutes);
|
||||
21
src/store/appStateSlice.js
Normal file
21
src/store/appStateSlice.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
const initialState = {
|
||||
appState: ""
|
||||
};
|
||||
|
||||
export const appStateSlice = createSlice({
|
||||
name: "appState",
|
||||
initialState,
|
||||
reducers: {
|
||||
setAppState: (state, action) => {
|
||||
state.appState = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const {
|
||||
setAppState
|
||||
} = appStateSlice.actions;
|
||||
|
||||
export default appStateSlice.reducer;
|
||||
8
src/store/store.js
Normal file
8
src/store/store.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import appStateSlice from "./appStateSlice";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
appState: appStateSlice
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user