Compare commits
24 Commits
dev
...
Mariya_Var
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbd252b6ad | ||
|
|
31a4b3f278 | ||
|
|
f8a8c6a789 | ||
|
|
0715733163 | ||
|
|
aefcecf90f | ||
|
|
ebd9d23f12 | ||
|
|
e681a4a9bf | ||
|
|
f17408f5ce | ||
|
|
60a8044041 | ||
|
|
2d040ff1c8 | ||
|
|
e9da7a7983 | ||
|
|
4579ad914d | ||
|
|
b4ab8cbff0 | ||
|
|
d35510d39a | ||
|
|
5af8197664 | ||
|
|
29b7db446e | ||
|
|
ca71641341 | ||
|
|
45aecc658e | ||
|
|
5524f135ff | ||
|
|
65f5fdc428 | ||
|
|
4bf75a2473 | ||
|
|
87e4ca7c9a | ||
|
|
e34a618198 | ||
|
|
f9c054c62b |
45
firmware/hemocube_mock/hemocube_mock.ino
Normal file
45
firmware/hemocube_mock/hemocube_mock.ino
Normal file
@@ -0,0 +1,45 @@
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
Serial.println("SN:182829");
|
||||
// while (Serial.available() == 0) {} //wait for data available
|
||||
// String bufferCommand = Serial.readString(); //read until timeout
|
||||
// bufferCommand.trim(); // remove any \r \n whitespace at the end of the String
|
||||
// if (bufferCommand == "B") {
|
||||
// Serial.println("#Start Buffer");
|
||||
// delay(2000);
|
||||
// Serial.println("#Buffer Completed");
|
||||
// }
|
||||
|
||||
// while (Serial.available() == 0) {} //wait for data available
|
||||
// String SampleCommand = Serial.readString(); //read until timeout
|
||||
// SampleCommand.trim(); // remove any \r \n whitespace at the end of the String
|
||||
// if (SampleCommand == "S") {
|
||||
// Serial.println("#Sample Started");
|
||||
// delay(2000);
|
||||
// Serial.println("#Sample Completed");
|
||||
// }
|
||||
|
||||
// while (Serial.available() == 0) {} //wait for data available
|
||||
// String resultCommand = Serial.readString(); //read until timeout
|
||||
// resultCommand.trim(); // remove any \r \n whitespace at the end of the String
|
||||
// if (resultCommand == "R") {
|
||||
// delay(3000);
|
||||
// Serial.println("RESULT SN 18291 1937.23 2828.11 28211.20 121829.12 REND");
|
||||
// delay(15000);
|
||||
// }
|
||||
|
||||
while (Serial.available() == 0) {} //wait for data available
|
||||
String resultCommand = Serial.readString(); //read until timeout
|
||||
resultCommand.trim(); // remove any \r \n whitespace at the end of the String
|
||||
if (resultCommand == "B") {
|
||||
delay(3000);
|
||||
Serial.println("ERROR 500 REND");
|
||||
delay(15000);
|
||||
}
|
||||
}
|
||||
BIN
scripts/224321944144PADGMC.pdf
Normal file
BIN
scripts/224321944144PADGMC.pdf
Normal file
Binary file not shown.
64
scripts/UserCollection.py
Normal file
64
scripts/UserCollection.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
import firebase_admin
|
||||
from IPython.core.display import Image
|
||||
from IPython.core.display_functions import display
|
||||
from firebase_admin import credentials
|
||||
from firebase_admin import firestore
|
||||
import pandas as pd
|
||||
import datetime
|
||||
|
||||
|
||||
print("pritimay")
|
||||
|
||||
# Initialize Firebase Admin SDK
|
||||
cred = credentials.Certificate(r'C:\Users\smila\PycharmProjects\pythonProject\hpos-prod-firebase-adminsdk-bionp-5486f7becd.json') # Replace with your own service account key path
|
||||
|
||||
firebase_admin.initialize_app(cred)
|
||||
|
||||
# Get a reference to the Firestore database
|
||||
db = firestore.client()
|
||||
|
||||
# Specify the collections
|
||||
patient_collection = db.collection("patientData")
|
||||
test_collection = db.collection("testData")
|
||||
start_date = input("Please enter the start date (yyyy-mm-dd): ")
|
||||
end_date = input("Please enter the end date (yyyy-mm-dd): ")
|
||||
|
||||
query = patient_collection.where("createdAt", ">=", start_date).where("createdAt", "<", end_date)
|
||||
patient_docs = query.stream()
|
||||
|
||||
# Prepare data to store in CSV
|
||||
data = []
|
||||
for patient_doc in patient_docs:
|
||||
patient_data = patient_doc.to_dict()
|
||||
patient_id = patient_data["_id"]
|
||||
|
||||
# Query the document from testData collection based on the common _id
|
||||
test_docs = test_collection.where("_id", "==", patient_id).stream()
|
||||
|
||||
for test_doc in test_docs:
|
||||
test_data = test_doc.to_dict()
|
||||
|
||||
# Combine the data from both collections into a single dictionary
|
||||
combined_data = {**patient_data, **test_data}
|
||||
|
||||
# Skip if the csvPath is not a valid URL
|
||||
|
||||
data.append(combined_data)
|
||||
|
||||
# Convert the data to a DataFrame
|
||||
df = pd.DataFrame(data)
|
||||
print(df.size)
|
||||
|
||||
# Save the DataFrame to a CSV file
|
||||
output_filename = "data.csv"
|
||||
df.to_csv(output_filename, index=False)
|
||||
|
||||
downloads_dir = os.path.join(os.path.expanduser("~"), "Downloads")
|
||||
output_path = os.path.join(downloads_dir, output_filename)
|
||||
df.to_csv(output_path, index=False)
|
||||
|
||||
print(f"Data saved to '{output_path}'")
|
||||
|
||||
# Close the Firebase Admin SDK
|
||||
firebase_admin.delete_app(firebase_admin.get_app())
|
||||
BIN
scripts/logo.png
Normal file
BIN
scripts/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
BIN
scripts/logo_nobg.png
Normal file
BIN
scripts/logo_nobg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
235
scripts/report_template.html
Normal file
235
scripts/report_template.html
Normal file
@@ -0,0 +1,235 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
@media print {
|
||||
body {
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
|
||||
.person-details-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.person-details-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 90px;
|
||||
width: 50%;
|
||||
margin: 1px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.test-details-row {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.test-details-col {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.test-cell-div {
|
||||
/* border: 1px solid black; */
|
||||
border-collapse: collapse;
|
||||
height: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
border: 1px solid black;
|
||||
margin: 0 0 -10px 10px;
|
||||
background-color: rgb(191, 191, 191);
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
height: 50px;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.table-header {
|
||||
background-color: rgb(191, 191, 191) !important;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.vendorListHeading th {
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.test-method {
|
||||
font-weight: 200 !important;
|
||||
color: rgb(191, 191, 191);
|
||||
}
|
||||
|
||||
.result-value {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.end-of-report {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
/* margin: 0; */
|
||||
/* padding: 0; */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<div class="logo">
|
||||
<img src="./logo_nobg.png" width="128" height="128" alt="sickle cell logo" />
|
||||
</div>
|
||||
<table style="border: 1px solid black; margin: 10px; width: 98%;">
|
||||
<tr class="person-details-row">
|
||||
<td class="person-details-col" style="border-right: 2; width: 70%;">
|
||||
<div><strong>Name:</strong></div>
|
||||
<div><strong>Age / Gender:</strong></div>
|
||||
<div><strong>Sample type:</strong></div>
|
||||
<div><strong>Family History of Sickle Cell Anemia:</strong></div>
|
||||
</td>
|
||||
<td class="person-details-col" style="width: 30%;">
|
||||
<div><strong>Marital Status:</strong></div>
|
||||
<div><strong>Test Date:</strong></div>
|
||||
<div><strong>ABHA ID:</strong></div>
|
||||
<div><strong>Sample ID:</strong></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="height: 2px;width: 98%; background-color: rgb(56, 105, 166); margin: 30px 10px 40px 10px;"></div>
|
||||
|
||||
|
||||
<div>
|
||||
<div class="table-header">POINT OF CARE SICKLE CELL ANEMIA TEST</div>
|
||||
<table class="test-details-table" style="border: 1px solid black; margin: 10px; width: 98%;">
|
||||
<tr style="height: 50px;">
|
||||
<th>
|
||||
Test Description
|
||||
</th>
|
||||
<th>
|
||||
RESULT
|
||||
</th>
|
||||
<th>
|
||||
REFERENCE RANGES
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="test-details-row">
|
||||
<td class="test-details-col" style="width: 20%; margin: 10px;">
|
||||
<div style="margin: 10px;">Sickle Cell
|
||||
Anemia
|
||||
<div class="test-method">(Method: HPOS)</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 30%;">
|
||||
<div class="result-value">Ra = 0.16</div>
|
||||
<!-- <div class="test-cell-div">Normal</div>
|
||||
<div class="test-cell-div">Sickle Cell Trait</div>
|
||||
<div class="test-cell-div">Sickle Cell Disease</div>
|
||||
<div class="test-cell-div">Negative Borderline</div>
|
||||
<div class="test-cell-div">Positive Borderline</div> -->
|
||||
</td>
|
||||
<td style="width: 50%;">
|
||||
<div class="test-cell-div">
|
||||
< 0.16: Normal (HbA)</div>
|
||||
<div class="test-cell-div">0.165 – 0.235: Sickle-cell Trait (HbAS)</div>
|
||||
<div class="test-cell-div">> 0.24: Sickle-cell Disease (HbSS)</div>
|
||||
<div class="test-cell-div">0.16-0.165: Inconclusive (Negative Borderline)</div>
|
||||
<div class="test-cell-div">0.235 – 0.24: Inconclusive (Positive Borderline)</div>
|
||||
</td>
|
||||
<!-- <td style="width: 25%;">
|
||||
<div class="test-cell-div">Normal</div>
|
||||
<div class="test-cell-div">Sickle Cell Trait</div>
|
||||
<div class="test-cell-div">Sickle Cell Disease</div>
|
||||
<div class="test-cell-div">Recommended for HPLC or Electrophoresis Tests</div>
|
||||
<div class="test-cell-div">Recommended for HPLC or Electrophore</div>
|
||||
</td> -->
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- <div style="font-weight: 600; margin: 10px;">INTERPRETATION:</div> -->
|
||||
|
||||
<div style="margin: 10px;">
|
||||
<strong>Test Principle:</strong> This point of care quantitative diagnostic test for sickle-cell anemia
|
||||
works on the principle of absorption
|
||||
spectroscopy. The test helps in differentiating heterozygous/homozygous hemoglobin from normal hemoglobin.
|
||||
</div>
|
||||
|
||||
<div style="margin: 10px;">
|
||||
<strong>Method:</strong> High Performance Optical Spectroscopy (HPOS) for detection of Sickle cell trait and
|
||||
sickle cell disease in whole blood capillary blood samples.
|
||||
</div>
|
||||
|
||||
<div style="margin: 10px;">
|
||||
<strong> Note:</strong>
|
||||
<!-- <ul>
|
||||
<li>a. Blood transfusion may have an impact on the test results.</li>
|
||||
|
||||
<li>
|
||||
b. Patients already on sickle-cell medications may impact test results.
|
||||
</li>
|
||||
</ul> -->
|
||||
|
||||
Borderline cases are reported as inconclusive. It may occur due to several factors such as medication,
|
||||
transfusion, field conditions and assay process. Further clinical tests are recommended in these cases for
|
||||
diagnosis.
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="margin: 80px 10px 20px 50px; width: 88%; display: flex; flex-direction: row; justify-content: space-between; align-items: center;">
|
||||
<div style="margin: 5px;">DATE:</div>
|
||||
<div style="margin: 5px;">Hematologist</div>
|
||||
</div>
|
||||
|
||||
<!-- <div style="margin: 30px;">
|
||||
This report is for the perusal of doctor only. Not for medico legal cases. Clinical correlation is
|
||||
essential.
|
||||
Please contact us in case of unexpected result.
|
||||
</div> -->
|
||||
<div style="height: 3px;width: 98%; background-color: black;"></div>
|
||||
<div class="end-of-report">
|
||||
*** END OF REPORT ***</div>
|
||||
<div style="display: flex; justify-content: center; align-items: center; flex-direction: column;">
|
||||
<div style="font-style: italic;">
|
||||
This is an electronically generated report. Generated at HH:MM hrs on DD-MMM-YYYY.
|
||||
</div>
|
||||
<div>
|
||||
Note: Assay results should be correlated clinically with other clinical findings
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
16
src/App.css
16
src/App.css
@@ -50,7 +50,7 @@ body {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
font-size: xx-large;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
|
||||
.last-update {
|
||||
@@ -146,7 +146,7 @@ body {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
font-size: xx-large;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
|
||||
.nscm-logo {
|
||||
@@ -206,7 +206,7 @@ body {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
font-size: xx-large;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ body {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
font-size: xx-large;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
|
||||
.title-text {
|
||||
@@ -289,7 +289,7 @@ body {
|
||||
}
|
||||
|
||||
.cards-container {
|
||||
height: 80vh;
|
||||
height: 90vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@@ -307,7 +307,7 @@ body {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
font-size: xx-large;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
|
||||
.title-text {
|
||||
@@ -356,7 +356,7 @@ body {
|
||||
}
|
||||
|
||||
.cards-container {
|
||||
height: 80vh;
|
||||
height: 90vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@@ -372,7 +372,7 @@ body {
|
||||
.dashboard-title {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
background-color: rgb(215, 192, 252);
|
||||
background-color: rgb(207, 235, 250);
|
||||
}
|
||||
|
||||
.title-text {
|
||||
|
||||
9
src/components/Calibrations.css
Normal file
9
src/components/Calibrations.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.page-title {
|
||||
/* width: 100vw; */
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: rgb(207, 235, 250);
|
||||
color: black;
|
||||
font-size: 30px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
78
src/components/Calibrations.js
Normal file
78
src/components/Calibrations.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { query, collection, onSnapshot } from 'firebase/firestore';
|
||||
import Dropdown from 'react-dropdown';
|
||||
import 'react-dropdown/style.css';
|
||||
import moment from 'moment';
|
||||
|
||||
import db from '../firebase';
|
||||
import './Calibrations.css';
|
||||
|
||||
const Calibrations = () => {
|
||||
const [device, setDevice] = useState("Select a device");
|
||||
const [devices, setDevices] = useState([]);
|
||||
const [curDeviceData, setCurDeviceData] = useState(null);
|
||||
|
||||
const changeDevice = ({ value }) => {
|
||||
setDevice(value);
|
||||
}
|
||||
|
||||
const toggleShowDevice = () => {
|
||||
console.log(devices.filter(x => x.deviceId === device))
|
||||
setCurDeviceData(devices.find(x => x.deviceId === device));
|
||||
// if (!device) {
|
||||
// setCurDeviceData(devices.filter(x => x.deviceId === device));
|
||||
// } else {
|
||||
// setDevice(null);
|
||||
// }
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!devices?.length) {
|
||||
const q = query(collection(db, "devices"));
|
||||
|
||||
const unsub = onSnapshot(q, (querySnapshot) => {
|
||||
const testDevices = [];
|
||||
querySnapshot.forEach((document) => {
|
||||
const deviceData = document.data();
|
||||
testDevices.push(deviceData);
|
||||
});
|
||||
setDevices(testDevices);
|
||||
});
|
||||
|
||||
return () => unsub;
|
||||
}
|
||||
}, [device, curDeviceData]);
|
||||
|
||||
return (
|
||||
<div className="calibrations-page">
|
||||
<div className='page-title'>Calibrations</div>
|
||||
<div className='dropdown-group'>
|
||||
<Dropdown className='device-dropdown' options={devices?.map(x => x.deviceId)} onChange={changeDevice} value={device} placeholder="Select an device" />
|
||||
|
||||
<button className='clear-button' onClick={toggleShowDevice}><img className="graph-icon" src={require('../assets/graph_icon.png')} alt='icon'></img>{device ? 'Clear' : 'Show'}</button>
|
||||
</div>
|
||||
|
||||
<div className='graph-person-conatiner'>
|
||||
{curDeviceData && <div className='test-details'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>key</th>
|
||||
<th>value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>device</td> <td>{curDeviceData?.deviceId} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>calibratedAt</td> <td>{curDeviceData?.calibratedAt} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>coefficients</td> <td>{curDeviceData?.coefficients?.toString()} </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Calibrations;
|
||||
@@ -2,12 +2,14 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
.insights-title {
|
||||
/* width: 100vw; */
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: rgb(215, 192, 252);
|
||||
background: rgb(207, 235, 250);
|
||||
color: black;
|
||||
font-size: 30px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.device-dropdown {
|
||||
@@ -79,7 +81,7 @@
|
||||
background-color: rgb(207, 235, 250);
|
||||
width: 10vw;
|
||||
height: 5vh;
|
||||
margin: 5px;
|
||||
/* margin: 5px; */
|
||||
border-radius: 10px;
|
||||
font-size: medium;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { query, collection, onSnapshot } from 'firebase/firestore';
|
||||
import Dropdown from 'react-dropdown';
|
||||
import 'react-dropdown/style.css';
|
||||
import moment from 'moment';
|
||||
import Select from 'react-select';
|
||||
|
||||
import DeviceGraph from "./DeviceGraph";
|
||||
import db from '../firebase';
|
||||
@@ -18,11 +19,15 @@ const Devices = () => {
|
||||
const [tests, setTests] = useState([]);
|
||||
const [allTests, setAllTests] = useState(null);
|
||||
const [showGraph, setShowGraph] = useState(false);
|
||||
const selectDateDropdownRef = useRef();
|
||||
const selectTestDropdownRef = useRef();
|
||||
|
||||
const changeDevice = ({ value }) => {
|
||||
setDevice(value);
|
||||
setTestDate(null);
|
||||
setCurTest(null);
|
||||
selectDateDropdownRef.current?.setValue("");
|
||||
selectTestDropdownRef.current?.setValue("");
|
||||
setDays([...new Set(allTests
|
||||
.filter((x) => x.deviceSerialNumber === value)
|
||||
.map(x => moment(x.testTime).format("YYYY-MM-DD")))]
|
||||
@@ -32,6 +37,7 @@ const Devices = () => {
|
||||
|
||||
const changeTestDate = ({ value }) => {
|
||||
setTestDate(value);
|
||||
selectTestDropdownRef.current?.setValue("");
|
||||
setCurTest(null);
|
||||
setCurTestData(null);
|
||||
setShowGraph(false);
|
||||
@@ -84,22 +90,45 @@ const Devices = () => {
|
||||
|
||||
return (
|
||||
<div className="devices-page">
|
||||
<div className='title'>Insights</div>
|
||||
<div className='insights-title'>Insights</div>
|
||||
<div className='dropdown-group'>
|
||||
<Dropdown className='device-dropdown' options={devices} onChange={changeDevice} value={device} placeholder="Select an device" />
|
||||
{/* <Dropdown className='device-dropdown' options={devices} onChange={changeDevice} value={device} placeholder="Select an device" />
|
||||
<Dropdown className='day-dropdown' options={days} onChange={changeTestDate} value={testDate} placeholder="Select an test date" />
|
||||
<Dropdown className='test-dropdown' options={tests} onChange={changeTest} value={curTest} placeholder="Select an test" />
|
||||
<Dropdown className='test-dropdown' options={tests} onChange={changeTest} value={curTest} placeholder="Select an test" /> */}
|
||||
|
||||
{/* <Select className='device-dropdown' options={devices.map(x => { return { value: x, label: x }; })} menuPlacement='auto' maxMenuHeight={250} menuShouldScrollIntoView={true} onChange={changeDevice} />
|
||||
<Select className='day-dropdown' options={days.map(x => { return { value: x, label: x }; })} menuPlacement='auto' maxMenuHeight={250} menuShouldScrollIntoView={true} onChange={changeTestDate} />
|
||||
<Select className='test-dropdown' options={tests.map(x => { return { value: x, label: x }; })} menuPlacement='auto' maxMenuHeight={220} menuShouldScrollIntoView={true} onChange={changeTestDate} /> */}
|
||||
<Select
|
||||
className='device-dropdown'
|
||||
defaultValue={{ label: "Select a device", value: "Select a device" }}
|
||||
options={devices.map(x => { return { value: x, label: x }; })}
|
||||
menuPlacement='auto'
|
||||
maxMenuHeight={250}
|
||||
menuShouldScrollIntoView={true}
|
||||
onChange={changeDevice} />
|
||||
<Select
|
||||
ref={selectDateDropdownRef}
|
||||
className='day-dropdown'
|
||||
defaultValue={{ label: "Select a test date", value: "Select a test date" }}
|
||||
options={days.map(x => { return { value: x, label: x }; })}
|
||||
menuPlacement='auto'
|
||||
maxMenuHeight={250}
|
||||
menuShouldScrollIntoView={true}
|
||||
onChange={changeTestDate} />
|
||||
<Select
|
||||
ref={selectTestDropdownRef}
|
||||
className='test-dropdown'
|
||||
defaultValue={{ label: "Select a test", value: "Select a test" }}
|
||||
options={tests.map(x => { return { value: x, label: x }; })}
|
||||
menuPlacement='auto'
|
||||
maxMenuHeight={220}
|
||||
menuShouldScrollIntoView={true}
|
||||
onChange={changeTest} />
|
||||
|
||||
<button className='clear-button' onClick={toggleShowGraph}><img className="graph-icon" src={require('../assets/graph_icon.png')} alt='icon'></img>{curTestData ? 'Clear' : 'Show'}</button>
|
||||
</div>
|
||||
|
||||
<div className='graph-person-conatiner'>
|
||||
{!curTestData && <div className='refresh-graph-message'>Select test device, date and person to get the detailed graph. Then, click show button to render graph.</div>}
|
||||
{curTestData?.csvPath && <DeviceGraph url={curTestData?.csvPath} show={showGraph} />}
|
||||
{curTestData?.csvPath && curTestData?.testType !== 'HEMOCUBE' && <DeviceGraph url={curTestData?.csvPath} show={showGraph} />}
|
||||
|
||||
{curTestData && <div className='test-details'>
|
||||
<table>
|
||||
@@ -122,6 +151,26 @@ const Devices = () => {
|
||||
<tr>
|
||||
<td>result</td> <td>{curTestData?.result}</td>
|
||||
</tr>
|
||||
{curTestData?.testType === 'HEMOCUBE' && <tr>
|
||||
<td>calculatedRatio</td>
|
||||
<td>{curTestData?.calculatedRatio}</td>
|
||||
</tr>}
|
||||
{curTestData?.testType === 'HEMOCUBE' && <tr>
|
||||
<td>deviceRatio</td>
|
||||
<td>{curTestData?.deviceRatio}</td>
|
||||
</tr>}
|
||||
{curTestData?.testType === 'HEMOCUBE' && <tr>
|
||||
<td>green led Average</td>
|
||||
<td>{curTestData?.led1Average}</td>
|
||||
</tr>}
|
||||
{curTestData?.testType === 'HEMOCUBE' && <tr>
|
||||
<td>blue led Average</td>
|
||||
<td>{curTestData?.led2Average}</td>
|
||||
</tr>}
|
||||
{curTestData?.testType === 'HEMOCUBE' && <tr>
|
||||
<td>blue led Average</td>
|
||||
<td>{curTestData?.led2Average}</td>
|
||||
</tr>}
|
||||
</table>
|
||||
{/* <img src={curTestData?.userImageURL} width={100} height={150} /> */}
|
||||
</div>}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.locations-card {
|
||||
width: 40vw;
|
||||
height: 45vh;
|
||||
height: 40vh;
|
||||
background-color: white;
|
||||
margin: 10px;
|
||||
display: flex;
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
.locations-graph-card {
|
||||
width: 40vw;
|
||||
height: 45vh;
|
||||
height: 40vh;
|
||||
background-color: white;
|
||||
margin: 10px;
|
||||
border-style: solid;
|
||||
@@ -27,7 +27,7 @@
|
||||
.locations-card-title {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
padding-top: 10px;
|
||||
/* padding-top: 10px; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.resultratio-graph-card {
|
||||
width: 40vw;
|
||||
height: 45vh;
|
||||
height: 40vh;
|
||||
background-color: white;
|
||||
margin: 10px;
|
||||
border-style: solid;
|
||||
|
||||
@@ -24,7 +24,7 @@ class ScatterPlot extends Component {
|
||||
if (!data) return;
|
||||
|
||||
// set the dimensions and margins of the graph
|
||||
var margin = { top: 10, right: 30, bottom: 30, left: 60 },
|
||||
var margin = { top: 10, right: 30, bottom: 40, left: 60 },
|
||||
width = 460 - margin.left - margin.right,
|
||||
height = 250 - margin.top - margin.bottom;
|
||||
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
.container {
|
||||
.analytics-page::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.analytics-title::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.analytics-page {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.analytics-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 50vh;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.analytics-title {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: rgb(207, 235, 250);
|
||||
color: black;
|
||||
font-size: 30px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 900px) {
|
||||
.container {
|
||||
.analytics-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 50vh;
|
||||
height: 45vh;
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,8 @@ const TestAnalytics = () => {
|
||||
}, [curTestData, curTest, device, testDate]);
|
||||
|
||||
return (
|
||||
<div className="devices-page">
|
||||
<div className='title'>Analytics</div>
|
||||
<div className="analytics-page">
|
||||
<div className='analytics-title'>Analytics</div>
|
||||
{/* <div className='dropdown-group'>
|
||||
<Dropdown className='device-dropdown' options={devices} onChange={changeDevice} value={device} placeholder="Select an device" />
|
||||
<Dropdown className='day-dropdown' options={days} onChange={changeTestDate} value={testDate} placeholder="Select an test date" />
|
||||
@@ -92,11 +92,11 @@ const TestAnalytics = () => {
|
||||
<button className='clear-button' onClick={toggleShowGraph}><img className="graph-icon" src={require('./graph_icon.png')}></img>{curTestData ? 'Clear' : 'Show'}</button>
|
||||
</div> */}
|
||||
|
||||
<div className='container'>
|
||||
<div className='analytics-container'>
|
||||
{dailyCategoryCounts && <TestAnalyticsPie data={dailyCategoryCounts} />}
|
||||
{dailyResults && <TestAnalyticsGraph data={dailyResults} />}
|
||||
</div>
|
||||
<div className='container'>
|
||||
<div className='analytics-container'>
|
||||
{allTests && <ScatterPlot data={allTests} />}
|
||||
{allTests && <Locations />}
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.tests-count-card {
|
||||
width: 40vw;
|
||||
height: 45vh;
|
||||
height: 40vh;
|
||||
background-color: white;
|
||||
margin: 10px;
|
||||
/* display: flex;
|
||||
@@ -58,4 +58,18 @@
|
||||
font-size: x-small;
|
||||
font-weight: 400;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div#tests-count-graph {
|
||||
height: 180px;
|
||||
width: 430px;
|
||||
/* border: 2px solid #000; */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
svg#bargraph {
|
||||
height: 180px; /* 500px; */
|
||||
width: 700px; /* 1100px; */
|
||||
/* border: 1px dotted #ccc; */
|
||||
/* background-color: #ccc; */
|
||||
}
|
||||
@@ -25,11 +25,12 @@ 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 = 700 - margin.left - margin.right,
|
||||
height = 180 - margin.top - margin.bottom;
|
||||
|
||||
var svg = d3.select("#tests-count-graph").append('svg')
|
||||
.attr("id", "bargraph")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g").attr("transform",
|
||||
@@ -40,7 +41,7 @@ class TestAnalyticsGraph extends Component {
|
||||
yScale = d3.scaleLinear().range([height, 0]);
|
||||
|
||||
var g = svg.append("g")
|
||||
.attr("transform", "translate(" + 10 + "," + 10 + ")");
|
||||
.attr("transform", "translate(" + 5 + "," + 5 + ")");
|
||||
|
||||
|
||||
xScale.domain(data.map(function (d) { return moment(d.date).format("MM-DD"); }));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.category-graph-card {
|
||||
width: 40vw;
|
||||
height: 45vh;
|
||||
height: 40vh;
|
||||
background-color: white;
|
||||
margin: 10px;
|
||||
border-style: solid;
|
||||
|
||||
@@ -24,7 +24,7 @@ class TestAnalyticsPie extends Component {
|
||||
drawChart(data) {
|
||||
if (!data) return;
|
||||
|
||||
var margin = { top: 30, right: 10, bottom: 15, left: 25 },
|
||||
var margin = { top: 15, right: 10, bottom: 45, left: 10 },
|
||||
width = 480 - margin.left - margin.right,
|
||||
height = 250 - margin.top - margin.bottom,
|
||||
radius = Math.min(width, height) / 2;
|
||||
|
||||
@@ -44,7 +44,7 @@ const WorldMap = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<svg width={ '40vw' } height={ '50vh' } viewBox="0 0 800 450">
|
||||
<svg width={ '40vw' } height={ '35vh' } viewBox="0 0 800 450">
|
||||
<g className="countries">
|
||||
{
|
||||
geographies.map((d,i) => (
|
||||
|
||||
@@ -11,6 +11,7 @@ import Devices from './components/Devices';
|
||||
import TestAnalytics from './components/TestAnalytics';
|
||||
import WorldMap from './components/WorldMap';
|
||||
import RegistraionChart from './RegistraionChart';
|
||||
import Calibrations from './components/Calibrations';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -32,6 +33,10 @@ const router = createBrowserRouter([
|
||||
{
|
||||
path: "/map",
|
||||
element: <RegistraionChart />,
|
||||
},
|
||||
{
|
||||
path: "/calibrations",
|
||||
element: <Calibrations />,
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user