36 Commits

Author SHA1 Message Date
Pritimay Sarkar
d327fecf8c Merge branch 'dev' into preprod 2023-12-25 13:51:16 +05:30
Pritimay Sarkar
43375556bf add environment variables and point api based on them 2023-12-25 13:46:54 +05:30
Pritimay Sarkar
92feb4081c add preprod stie 2023-12-18 09:16:57 +05:30
Pritimay Sarkar
bb968b4781 ad dtarget 2023-12-14 16:45:53 +05:30
Pritimay Sarkar
a751b55647 add new class column 2023-12-14 15:31:43 +05:30
Pritimay Sarkar
099b3f08fa add dev web app 2023-12-12 22:12:26 +05:30
Pritimay Sarkar
1f55978521 add reference file input and loader 2023-12-11 22:12:56 +05:30
Pritimay Sarkar
84740e846f add loading icon and fix cors 2023-12-10 23:39:27 +05:30
Pritimay Sarkar
09d18106b8 add new helps 2023-12-08 16:36:46 +05:30
Pritimay Sarkar
5dbff78d79 add new multi site support 2023-12-08 15:36:10 +05:30
Pritimay Sarkar
75ad2aba82 add remaining files 2023-12-08 15:35:46 +05:30
Pritimay Sarkar
3a355ffe57 add auto analysis functionality 2023-12-08 15:35:17 +05:30
Pritimay Sarkar
4da937673c add new samples columns 2023-12-08 15:34:46 +05:30
Pritimay Sarkar
48c9bacb4f add supported formats for samples 2023-12-08 15:34:30 +05:30
Pritimay Sarkar
4dd9a31a75 add accordion in help for automatic 2023-12-08 15:33:59 +05:30
Pritimay Sarkar
5d5325d51d add curve fit image api 2023-12-03 16:28:36 +05:30
Pritimay Sarkar
f857e57173 add device quality components 2023-12-03 11:51:12 +05:30
Pritimay Sarkar
c20197c40a add log in ignore 2023-11-17 10:55:22 +05:30
Pritimay Sarkar
ca5106d613 resize card for test counts 2023-11-16 16:33:38 +05:30
Pritimay Sarkar
9c782b7cd1 add css 2023-11-16 16:21:32 +05:30
Pritimay Sarkar
707e338d3a new columns 2023-11-16 14:28:37 +05:30
Pritimay Sarkar
367c36e3f8 revert to old method of cls 2023-11-11 15:35:03 +05:30
Pritimay Sarkar
fc31aea95b new prd classification 2023-11-11 10:53:38 +05:30
Pritimay Sarkar
eaf87791bd new columns 2023-11-10 16:17:25 +05:30
Pritimay Sarkar
89090ff86b install steps 2023-11-10 16:16:53 +05:30
Pritimay Sarkar
515ad41329 change topbar text 2023-11-10 16:16:33 +05:30
Pritimay Sarkar
920858a523 add config 2023-11-09 08:49:00 +05:30
Pritimay Sarkar
b43aba97f2 add qa firebase config 2023-11-09 08:02:59 +05:30
Pritimay Sarkar
16aa545862 add qa firebase config 2023-11-09 08:01:53 +05:30
Pritimay Sarkar
a836335ed3 add samples page 2023-11-09 07:49:36 +05:30
Pritimay Sarkar
65723718c6 add app installation notes 2023-11-09 07:48:36 +05:30
Pritimay Sarkar
fb3d715831 add env name on page title 2023-11-09 07:48:20 +05:30
Pritimay Sarkar
683c6049af add clear button 2023-11-09 07:47:47 +05:30
Pritimay Sarkar
34a770ceed add samples page 2023-11-09 07:46:45 +05:30
Pritimay Sarkar
67a7414d5c hide clear users button in preprod 2023-11-07 10:53:39 +05:30
Pritimay Sarkar
260e6ec734 change apis to qa links 2023-11-07 10:52:33 +05:30
33 changed files with 720 additions and 25 deletions

View File

@@ -1,5 +1,21 @@
{ {
"projects": { "projects": {
"default": "hpos-af3cc" "default": "hpos-af3cc"
} },
} "targets": {
"hpos-af3cc": {
"hosting": {
"dev1": [
"hpos-dev1"
],
"qa": [
"hpos-qa"
],
"dev": [
"hpos-dev"
]
}
}
},
"etags": {}
}

4
.gitignore vendored
View File

@@ -13,6 +13,7 @@
# misc # misc
.DS_Store .DS_Store
.env
.env.local .env.local
.env.development.local .env.development.local
.env.test.local .env.test.local
@@ -30,4 +31,5 @@ public/india-states.json
*.apk *.apk
scripts/reports scripts/reports
scripts/data scripts/data
firebase-debug.log

View File

@@ -14,4 +14,22 @@
http://localhost:3000 http://localhost:3000
### add target (multi site), if not already defined for that site
firebase target:apply hosting dev1 hpos-dev1
### add or change to firebase.json
"target": "dev1",
### run build
npm build
### deploy
firebase deploy --only hosting:dev
pyinstaller --noconfirm --noconsole -i "smi.ico" --windowed --clean hemocube.py pyinstaller --noconfirm --noconsole -i "smi.ico" --windowed --clean hemocube.py

View File

@@ -1,5 +1,6 @@
{ {
"hosting": { "hosting": {
"target": "preprod",
"public": "build", "public": "build",
"ignore": [ "ignore": [
"firebase.json", "firebase.json",

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,63 @@
.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;
}
.file-row {
flex-direction: row;
display: flex;
justify-content: center;
align-items: center;
margin: 1.5rem;
}
.file-label {
margin: 10px;
}
.dates {
flex-direction: row;
display: flex;
justify-content: center;
align-items: center;
margin: 1.5rem;
}
.start-date {
margin: 10px;
}
.end-date {
margin: 10px;
}
.download-row {
flex-direction: row;
display: flex;
justify-content: center;
align-items: center;
margin: 1.5rem;
}
.loading-icon {
animation: rotate 2s linear infinite;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

107
src/components/Accuracy.js Normal file
View File

@@ -0,0 +1,107 @@
import React, { useState } from 'react';
import { FaInfoCircle } from "react-icons/fa";
import { AiOutlineLoading } from "react-icons/ai";
import DatePicker from "react-datepicker";
import moment from 'moment';
import axios from 'axios';
import "react-datepicker/dist/react-datepicker.css";
import './Accuracy.css';
function Accuracy({ show }) {
const [showCardInfo, setShowCardInfo] = useState(false);
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null); // New state for handling errors
const handleFileChange = (event) => {
setSelectedFile(event.target.files[0]);
};
const fetchFile = async (start_date, end_date) => {
try {
setLoading(true);
setError(null); // Reset error state before making a new request
if (selectedFile) {
const formData = new FormData();
formData.append('file', selectedFile);
const queryString = `start_date=${moment(startDate).format(
'YYYY-MM-DD'
)}&end_date=${moment(endDate).format('YYYY-MM-DD')}`;
const url = `https://asia-south1-hpos-af3cc.cloudfunctions.net/performance?${queryString}`;
// Make a POST request using the Fetch API
const response = await fetch(url, {
method: 'POST',
body: formData,
headers: {
// Add any necessary headers
// 'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
},
});
// Check if the request was successful (status code 2xx)
if (response.ok) {
// Create a blob from the response data
const blob = await response.blob();
// Create a download link and trigger a click to download the file
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'autoanlysis.xlsx'; // Set the desired file name
document.body.appendChild(link);
link.click();
// Clean up
document.body.removeChild(link);
} else {
console.error('Error downloading file:', response.statusText);
setError('Error downloading file. Please try again.'); // Set error message
}
} else {
setError("Select file from reference device");
}
} catch (error) {
console.error('Error downloading file:', error);
setError('Error downloading file. Please try again.'); // Set error message
} finally {
setLoading(false); // Set loading back to false when the request completes
}
};
return (
<div>
<h1>Auto Analysis</h1>
<div className='file-row'>
<div className='file-label'>Reference file</div>
<input type="file" onChange={handleFileChange} />
</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>
<div className='download-row'>
<div className='button' onClick={() => fetchFile(startDate, endDate)}>
{loading ? (
<AiOutlineLoading className="loading-icon" />
) : (
'Download Excel'
)}
</div>
</div>
{error && <div className="error-message">{error}</div>} {/* Display error message if there's an error */}
</div>
);
}
export default Accuracy;

View File

@@ -12,7 +12,10 @@ const AppInstallation = () => {
return ( return (
<div> <div>
<div> <h1>App Installation</h1>
<h3>First try the firebase app distribution which is email linked. After adding the email from backend. Check the email to get started.</h3>
{/* <div>
<div>Testing 2.1.27 (Preprod - 07-11-2023)</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"> <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> <img className="app-qrcode" src={require('../assets/hpos-testing_preprod.png')} alt='icon'></img>
@@ -27,7 +30,7 @@ const AppInstallation = () => {
<li>install the downloaded apk and give permissions</li> <li>install the downloaded apk and give permissions</li>
</ul> </ul>
</p> </p>
</div> </div> */}
</div> </div>
) )
} }

View File

View File

@@ -0,0 +1,56 @@
import React, { useEffect, useState } from 'react';
import { FaInfoCircle } from "react-icons/fa";
import axios from 'axios';
import './CurveFit.css';
import ImageDownloader from './ImageDownloader';
function CurveFit({ show }) {
const [showCardInfo, setShowCardInfo] = useState(false);
const [svgData, setSvgData] = useState(null);
const fetchSvg = () => {
axios({
method: 'get',
url: "https://asia-south1-hpos-qa.cloudfunctions.net/curvefit",
data: {
"_id": "id",
"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`);
// setSvgData(data?.plot?.replace('\"', '').replace('\n', '').replace('"', "'"));
})
.catch((err) => {
console.log(err);
// setMessage(`error: ${err?.message}`);
});
}
useEffect(() => {
if (!svgData) {
// fetchSvg();
}
}, []);
return (
<div>
<h1>Curve Fit</h1>
{/* <img alt='' src={ svgData }/>; */}
<img src="https://asia-south1-hpos-qa.cloudfunctions.net/curvefit" width="450" height="340" />
{/* <ImageDownloader /> */}
</div>
);
}
export default CurveFit;

View File

@@ -11,7 +11,7 @@ function ExportData({ url, show }) {
const [endDate, setEndDate] = useState(""); const [endDate, setEndDate] = useState("");
const fetchFile = (start_date, end_date) => { 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")}`; window.location.href = `https://asia-south1-${process.env.REACT_APP_FIREBASE_PROJECT_ID}.cloudfunctions.net/consolidation?start_date=${moment(startDate).format("YYYY-MM-DD")}&end_date=${moment(endDate).format("YYYY-MM-DD")}`;
} }
return ( return (

19
src/components/Help.css Normal file
View File

@@ -0,0 +1,19 @@
.step-title {
font-weight: 600;
margin: 10px;
margin-top: 50px;
}
.help-image {
margin: 10px;
}
.step-description {
margin: 10px;
}
.help-feature {
font-weight: 900;
font-size: 1.5rem;
margin: 10px;
}

128
src/components/Help.js Normal file
View File

@@ -0,0 +1,128 @@
import React, { useState } from 'react';
import Accordion from '@mui/material/Accordion';
import AccordionDetails from '@mui/material/AccordionDetails';
import AccordionSummary from '@mui/material/AccordionSummary';
import Typography from '@mui/material/Typography';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import './Help.css';
function Help({ url, show }) {
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [expanded, setExpanded] = useState(false);
const handleChange =
(panel) => (event, isExpanded) => {
setExpanded(isExpanded ? panel : false);
};
return (
<div>
<Accordion expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<Typography sx={{ width: '33%', flexShrink: 0 }}>
Auto Analysis
</Typography>
<Typography sx={{ color: 'text.secondary' }}>Auto Analysis of device data with dye and HB</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<div className='step-title'>Step 1:</div>
<div className='step-description'>Click on the start date tab and select the necessary date. Repeat the same process on the end date tab as well.</div>
<img className="help-image" src={require('../assets/auto_analysis_help-1.png')} alt='icon'></img>
<div className='step-title'>Step 2:</div>
<div className='step-description'>Select an end date, it has to be at least one date post the start date.</div>
<img className="help-image" src={require('../assets/auto_analysis_help-2.png')} alt='icon'></img>
<div className='step-title'>Step 3:</div>
<div className='step-description'>Click on the Download Excel button and wait for the document to download.</div>
<img className="help-image" src={require('../assets/auto_analysis_help-3.png')} alt='icon'></img>
</Typography>
</AccordionDetails>
</Accordion>
<Accordion expanded={expanded === 'panel2'} onChange={handleChange('panel2')}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel2bh-content"
id="panel2bh-header"
>
<Typography sx={{ width: '33%', flexShrink: 0 }}>Raw Data</Typography>
<Typography sx={{ color: 'text.secondary' }}>
Download raw data
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<div className='step-title'>Step 1:</div>
<div className='step-description'>Click on the <strong>start date</strong> tab and select the necessary date. Repeat the same process on the <strong>end date</strong> tab as well.</div>
<img className="help-image" src={require('../assets/raw_data_help_1.png')} alt='icon'></img>
<img className="help-image" src={require('../assets/raw_data_help_2.png')} alt='icon'></img>
<div className='step-title'>Step 2:</div>
<div className='step-description'>Click on the <strong>Download Excel</strong> button and wait for the document to download.</div>
<img className="help-image" src={require('../assets/raw_data_help_3.png')} alt='icon'></img>
</Typography>
</AccordionDetails>
</Accordion>
<Accordion expanded={expanded === 'panel3'} onChange={handleChange('panel3')}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel3bh-content"
id="panel3bh-header"
>
<Typography sx={{ width: '33%', flexShrink: 0 }}>
Registration
</Typography>
<Typography sx={{ color: 'text.secondary' }}>
Create and clear entries for taking readings in devices
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
<div className='step-title'>Step 1:</div>
<div className='step-description'>Enter the sample or solution name in the <strong>name</strong> tab with appropriate format given below.</div>
<img className="help-image" src={require('../assets/registration_help_1.png')} alt='icon'></img>
<div className='step-title'>Step 2:</div>
<div className='step-description'>Click on the create button to get an ID and you will receive a confirmation message.
If you wish to clear the generated IDs click on the clear button and you will receive a confirmation message.</div>
<img className="help-image" src={require('../assets/raw_data_help_2.png')} alt='icon'></img>
<img className="help-image" src={require('../assets/raw_data_help_3.png')} alt='icon'></img>
</Typography>
</AccordionDetails>
</Accordion>
{/* <Accordion expanded={expanded === 'panel4'} onChange={handleChange('panel4')}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel4bh-content"
id="panel4bh-header"
>
<Typography sx={{ width: '33%', flexShrink: 0 }}>Personal data</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>
Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit
amet egestas eros, vitae egestas augue. Duis vel est augue.
</Typography>
</AccordionDetails>
</Accordion> */}
</div>
);
}
export default Help;

View File

@@ -0,0 +1,47 @@
import React, { useState } from 'react';
const ImageDownloader = () => {
const [imageUrl, setImageUrl] = useState('');
const [imageData, setImageData] = useState(null);
const handleInputChange = (e) => {
setImageUrl(e.target.value);
};
const handleFetchImage = async () => {
try {
const response = await fetch(imageUrl, { mode: 'no-cors'});
const blob = await response.blob();
console.log(blob);
setImageData(URL.createObjectURL(blob));
} catch (error) {
console.error('Error fetching image:', error);
}
};
const handleDownloadImage = () => {
const link = document.createElement('a');
link.href = imageData;
link.download = 'downloaded_image';
link.click();
};
return (
<div>
<label>
Image URL:
<input type="text" value={imageUrl} onChange={handleInputChange} />
</label>
<button onClick={handleFetchImage}>Fetch Image</button>
{imageData && (
<div>
<img src={imageData} alt="Downloadable" style={{ maxWidth: '100%' }} />
<button onClick={handleDownloadImage}>Download Image</button>
</div>
)}
</div>
);
};
export default ImageDownloader;

View File

View File

@@ -0,0 +1,15 @@
import React, { useState } from 'react';
import { FaInfoCircle } from "react-icons/fa";
import './Precision.css';
function Precision({ show }) {
const [showCardInfo, setShowCardInfo] = useState(false);
return (
<div>
<h1>Precision</h1>
</div>
);
}
export default Precision;

View File

@@ -25,4 +25,8 @@
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
margin: 5px; margin: 5px;
}
.format-text {
color: red;
} }

View File

@@ -16,7 +16,7 @@ function Registration() {
setCounter(counter + 1); setCounter(counter + 1);
axios({ axios({
method: 'post', method: 'post',
url: "https://asia-south1-hpos-preprod.cloudfunctions.net/registerUser", url: `https://asia-south1-${process.env.REACT_APP_FIREBASE_PROJECT_ID}.cloudfunctions.net/registerUser`,
data: { data: {
"_id": id, "_id": id,
"aadharId": "2808202300001", "aadharId": "2808202300001",
@@ -65,7 +65,7 @@ function Registration() {
setMessage(""); setMessage("");
axios({ axios({
method: 'get', method: 'get',
url: "https://asia-south1-hpos-preprod.cloudfunctions.net/clearUsers", url: `https://asia-south1-${process.env.REACT_APP_FIREBASE_PROJECT_ID}.cloudfunctions.net/clearUsers`,
withCredentials: false, withCredentials: false,
secure: false, secure: false,
headers: { headers: {
@@ -91,10 +91,11 @@ function Registration() {
<div className="user-creation"> <div className="user-creation">
<label> <label>
name: name:
<input name="name" value={name} placeholder="350umol kmon04" onChange={onNameChange} /> <input name="name" value={name} placeholder="350 UMOL KMNO4" onChange={onNameChange} />
</label> </label>
<h5 className='format-text'>Correct formats for automatic analysis are: 100 UMOL KMNO4, 290uM KMnO4, KMnO4-720umol, 350 UMOL TAR, Tar-120umol, HB-13-N-4, HB-11-4</h5>
<div className='dates'> <div className='dates'>
<div className='button' onClick={() => createUser()}>Create User</div> <div className='button' onClick={() => createUser()}>Create</div>
</div> </div>
<div className='dates'> <div className='dates'>
<div className='clear-users-button' onClick={() => clearsUsers()}>Clear</div> <div className='clear-users-button' onClick={() => clearsUsers()}>Clear</div>

View File

@@ -0,0 +1,39 @@
#samples-table {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
font-size: small;
}
#samples-table td,
#samples-table th {
border: 1px solid #ddd;
padding: 8px;
width: 10vw;
}
#samples-table td {
width: 15vw;
}
#samples-table tr:nth-child(even) {
background-color: #f2f2f2;
}
#samples-table tr:hover {
background-color: #ddd;
}
#samples-table th {
padding-top: 12px;
padding-bottom: 12px;
text-align: center;
background-color: rgb(144, 183, 255);
color: black;
width: 5vw;
}
.samples-container {
overflow-x: auto;
overflow-y: auto;
}

89
src/components/Samples.js Normal file
View File

@@ -0,0 +1,89 @@
import React, { useEffect, useState, useRef } from 'react';
import { query, collection, onSnapshot, where, orderBy, limit } from 'firebase/firestore';
import './Samples.css';
import db from '../firebase';
import moment from 'moment';
const Samples = () => {
const [samples, setSamples] = useState([]);
useEffect(() => {
if (!samples.length) {
const q = query(collection(db, "testData"), where("testTime", ">=", moment().format("YYYY-MM-DD").toString()), orderBy("testTime", "desc"));
const unsub = onSnapshot(q, (querySnapshot) => {
const samples = [];
querySnapshot.forEach((document) => {
console.log(document.id);
const data = document.data();
const id = document.id;
samples.push({id, ...data});
});
setSamples(samples);
});
return () => unsub;
}
}, []);
return (
<div>
{/* <div className='samples-heading'><h3>Samples page for denovix useage</h3></div>
{samples.length ? (
samples.map((alert, index) => (
<div key={index} className='samples-card'>
<div tabIndex={index}><strong>{alert._id}</strong></div>
<p className='sample-time'>{alert.testTime}</p>
<p className='sample-time-ago'>{moment(alert.testTime).fromNow()}</p>
</div>
))
) : (
<div className='no-samples-message'>Samples will appear as in when a test is recorded</div>
)} */}
<h1>Samples</h1>
<div className='samples-container'>
<table id="samples-table">
<tr>
<th>Sample Name</th>
<th>Pdr Class</th>
<th>Dev Ratio Class</th>
<th>SR Class</th>
<th>PDR</th>
<th>Dev Ratio</th>
<th>Slope Ratio</th>
<th>led1Sample</th>
{/* <th>led2Average</th> */}
<th>led2Sample</th>
<th>led3Sample</th>
<th>led4Sample</th>
<th>Device</th>
<th>Time</th>
</tr>
{samples.map((sample, index) => (
<tr key={index} className='samples-table-tr'>
<td>{sample.name || sample._id}</td>
<td>{sample.prdClassification}</td>
<td>{sample.deviceRatioClass}</td>
<td>{sample.slopeRatioClass}</td>
<td>{sample?.predictedDenovixRatio?.toFixed(4)}</td>
<td>{sample?.deviceRatio?.toFixed(4)}</td>
<td>{sample?.slopeRatio?.toFixed(4)}</td>
<td>{sample.led1Sample || 'NA'}</td>
<td>{sample.led2Sample || 'NA'}</td>
<td>{sample.led3Sample || 'NA'}</td>
<td>{sample.led4Sample || 'NA'}</td>
<td>{sample.deviceId}</td>
<td>{moment(sample.testTime).format('HH:MM:SS')}</td>
</tr>
))}
</table>
</div>
</div>
)
}
export default Samples;

View File

@@ -53,7 +53,10 @@ const TestAnalytics = () => {
const dailyCountsList = Object.entries(dailyCounts).sort().map(x => { const dailyCountsList = Object.entries(dailyCounts).sort().map(x => {
return { date: x[0], count: x[1] }; return { date: x[0], count: x[1] };
}); });
setDailyResults(dailyCountsList); if (dailyCountsList?.length > 7)
setDailyResults(dailyCountsList.slice(dailyCountsList.length - 7, dailyCountsList.length));
else
setDailyResults(dailyCountsList);
const rss = _.groupBy(hposTests, function (test) { const rss = _.groupBy(hposTests, function (test) {
return moment(test.testTime).startOf('day').format(); return moment(test.testTime).startOf('day').format();
}); });

View File

@@ -26,7 +26,7 @@ class TestAnalyticsGraph extends Component {
data.reverse(); data.reverse();
var margin = { top: 30, right: 20, bottom: 50, left: 15 }, var margin = { top: 30, right: 20, bottom: 50, left: 15 },
width = 1500 - margin.left - margin.right, width = 400 - margin.left - margin.right,
height = 180 - margin.top - margin.bottom; height = 180 - margin.top - margin.bottom;
var svg = d3.select("#tests-count-graph").append('svg') var svg = d3.select("#tests-count-graph").append('svg')
@@ -113,7 +113,7 @@ class TestAnalyticsGraph extends Component {
drawChart(data) { drawChart(data) {
if (!data) return; if (!data) return;
var margin = { top: 20, right: 20, bottom: 30, left: 50 }, var margin = { top: 20, right: 20, bottom: 30, left: 50 },
width = 960 - margin.left - margin.right, width = 420 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom; height = 500 - margin.top - margin.bottom;
const INNER_WIDTH = width;// - margin.left - margin.right; const INNER_WIDTH = width;// - margin.left - margin.right;

View File

@@ -16,7 +16,7 @@ const Topbar = () => {
> >
<Toolbar> <Toolbar>
<Typography variant="h6"> <Typography variant="h6">
HPOS dashboard HPOS Web - {process.env.REACT_APP_TOPBAR_TITLE}
</Typography> </Typography>
</Toolbar> </Toolbar>
</AppBar> </AppBar>

View File

@@ -14,17 +14,51 @@ import { getAnalytics } from "firebase/analytics";
// measurementId: "G-6JHQ47S9DD" // measurementId: "G-6JHQ47S9DD"
// }; // };
// /* qa: hpos-qa */
// const firebaseConfig = {
// apiKey: "AIzaSyCF7BNZ5vOMQIpKRi_vxquzWP5pIjcb59I",
// authDomain: "hpos-qa.firebaseapp.com",
// projectId: "hpos-qa",
// storageBucket: "hpos-qa.appspot.com",
// messagingSenderId: "1004619739289",
// appId: "1:1004619739289:web:c3ee0c0127f0d073e5c808",
// measurementId: "G-4MSTJHE64W"
// };
/* preprod */ /* preprod */
const firebaseConfig = { const firebaseConfig = {
apiKey: "AIzaSyB2-suWmKh2PgQbRmx7rzPjYhgoovQIsQ8", apiKey: "AIzaSyBFl_YkJ5PMIvMY3G70313SyrqemjFnUv8",
authDomain: "hpos-preprod.firebaseapp.com", authDomain: "hpos-af3cc.firebaseapp.com",
projectId: "hpos-preprod", projectId: "hpos-af3cc",
storageBucket: "hpos-preprod.appspot.com", storageBucket: "hpos-af3cc.appspot.com",
messagingSenderId: "121176529204", messagingSenderId: "650071678820",
appId: "1:121176529204:web:6c0db8e642992192bbed61", appId: "1:650071678820:web:ce50538bf46632d46c6471",
measurementId: "G-GYM6LRQ8KR" measurementId: "G-6JHQ47S9DD"
}; };
// /* qa: hpos-qa */
// const firebaseConfig = {
// apiKey: "AIzaSyCF7BNZ5vOMQIpKRi_vxquzWP5pIjcb59I",
// authDomain: "hpos-qa.firebaseapp.com",
// projectId: "hpos-qa",
// storageBucket: "hpos-qa.appspot.com",
// messagingSenderId: "1004619739289",
// appId: "1:1004619739289:web:c3ee0c0127f0d073e5c808",
// measurementId: "G-4MSTJHE64W"
// };
// /* 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 */ // /* prod */
// const firebaseConfig = { // const firebaseConfig = {

View File

@@ -4,11 +4,16 @@ import AppsOutlinedIcon from '@mui/icons-material/AppsOutlined';
import TestAnalytics from "../components/TestAnalytics"; import TestAnalytics from "../components/TestAnalytics";
import HomePage from '../components/HomePage'; import HomePage from '../components/HomePage';
import Devices from '../components/Devices'; import Devices from '../components/Devices';
import { Download } from '@mui/icons-material'; import { Download, FactCheck } from '@mui/icons-material';
import ExportData from '../components/ExportData'; import ExportData from '../components/ExportData';
import Registration from '../components/Registration'; import Registration from '../components/Registration';
import { FaAndroid, FaPhone, FaUser } from 'react-icons/fa'; import { FaAndroid, FaArrowCircleLeft, FaBars, FaBezierCurve, FaChalkboardTeacher, FaChartArea, FaChartLine, FaCheck, FaExclamation, FaFlask, FaGolfBall, FaPhone, FaQuestionCircle, FaSearch, FaUser } from 'react-icons/fa';
import AppInstallation from '../components/AppInstallation'; import AppInstallation from '../components/AppInstallation';
import Samples from '../components/Samples';
import Precision from '../components/Precision';
import Accuracy from '../components/Accuracy';
import CurveFit from '../components/CurveFit';
import Help from '../components/Help';
const appRoutes = [ const appRoutes = [
{ {
@@ -39,7 +44,7 @@ const appRoutes = [
element: <ExportData />, element: <ExportData />,
state: "downloaddata", state: "downloaddata",
sidebarProps: { sidebarProps: {
displayText: "Data Download", displayText: "Raw Data",
icon: <Download /> icon: <Download />
} }
}, },
@@ -61,6 +66,51 @@ const appRoutes = [
icon: <FaAndroid /> icon: <FaAndroid />
} }
}, },
{
path: "/samples",
element: <Samples />,
state: "Samples",
sidebarProps: {
displayText: "Samples",
icon: <FaFlask />
}
},
// {
// path: "/precision",
// element: <Precision />,
// state: "precision",
// sidebarProps: {
// displayText: "Precision",
// icon: <FaCheck />
// }
// },
{
path: "/autoanalysis",
element: <Accuracy />,
state: "autoanalysis",
sidebarProps: {
displayText: "Auto Analysis (NEW)",
icon: <FaChartLine />
}
},
// {
// path: "/curvefit",
// element: <CurveFit />,
// state: "curvefit",
// sidebarProps: {
// displayText: "Linear Fit",
// icon: <FaBezierCurve />
// }
// },
{
path: "/helpcenter",
element: <Help />,
state: "helpcenter",
sidebarProps: {
displayText: "Help Center",
icon: <FaQuestionCircle />
}
},
] ]
export default appRoutes; export default appRoutes;