Skip to content
This repository has been archived by the owner on Apr 28, 2021. It is now read-only.

Commit

Permalink
Merge pull request #177 from donaldkibet/biometricsChart
Browse files Browse the repository at this point in the history
MF-383 Implemented biometrics chart view
  • Loading branch information
nmalyschkin authored Jan 20, 2021
2 parents 8cba83c + 79ae796 commit 3a094b2
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 51 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"homepage": "https://github.com/openmrs/openmrs-esm-patient-chart-widgets#readme",
"scripts": {
"start": "openmrs debug --importmap @",
"debug": "webpack-dev-server",
"serve": "webpack-dev-server",
"debug": "npm run serve",
"build": "webpack --mode production",
"analyze": "webpack --mode=production --env.analyze=true",
"lint": "eslint src --ext tsx",
Expand Down
38 changes: 38 additions & 0 deletions src/widgets/biometrics/biometrics-chart.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import "../../root.scss";

.biometricChartContainer {
display: flex;
text-align: left;
margin: 0 $spacing-03;
flex-direction: row;
justify-content: space-between;
}

.biometricSignsArea {
margin: $spacing-03 0;
padding: 0rem;
width: 8.938rem;
border-right: 0.063rem solid $ui-03;
padding-right: $spacing-05;
height: 13.875rem;
flex: 1;
}

.biometricChartArea {
padding: $spacing-03 $spacing-05;
width: 100%;
height: 13.875rem;
flex: 4;
}

.biometricSign {
@extend .label01;
color: $color-gray-70;
width: 7.063rem;
}

.biometricSignsRadioButton {
@extend .bodyShort01;
color: $ui-05;
padding: $spacing-03 0;
}
118 changes: 118 additions & 0 deletions src/widgets/biometrics/biometrics-chart.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from "react";
import styles from "./biometrics-chart.component.scss";
import { LineChart } from "@carbon/charts-react";
import { useConfig } from "@openmrs/esm-react-utils";
import { RadioButton, RadioButtonGroup } from "carbon-components-react";
import { PatientBiometrics } from "./biometrics-overview.component";
import { LineChartOptions } from "@carbon/charts/interfaces/charts";
import { ScaleTypes } from "@carbon/charts/interfaces/enums";
import dayjs from "dayjs";

interface BiometricsChartProps {
patientBiometrics: Array<PatientBiometrics>;
conceptsUnits: Array<string>;
}

interface biometricChartData {
title: string;
value: number | string;
groupName: "weight" | "height" | "bmi" | string;
}

const chartColors = { weight: "#6929c4", height: "#6929c4", bmi: "#6929c4" };

const BiometricsChart: React.FC<BiometricsChartProps> = ({
patientBiometrics,
conceptsUnits
}) => {
const config = useConfig();
const { bmiUnit } = config.biometrics;
const [, , , heightUnit, weightUnit] = conceptsUnits;
const [selectedBiometrics, setSelectedBiometrics] = React.useState<
biometricChartData
>({
title: `Weight (${weightUnit})`,
value: "weight",
groupName: "weight"
});

const chartData = React.useMemo(
() =>
patientBiometrics.map(biometric => {
return {
group: selectedBiometrics.groupName,
key: dayjs(biometric.date).format("DD-MMM"),
value: biometric[selectedBiometrics.value]
};
}),
[patientBiometrics, selectedBiometrics]
);

const chartOptions: LineChartOptions = React.useMemo(() => {
return {
axes: {
bottom: {
title: "Date",
mapsTo: "key",
scaleType: ScaleTypes.LABELS
},
left: {
mapsTo: "value",
title: selectedBiometrics.title,
scaleType: ScaleTypes.LINEAR,
includeZero: false
}
},
legend: {
enabled: false
},
color: {
scale: chartColors
}
};
}, [selectedBiometrics]);
return (
<div className={styles.biometricChartContainer}>
<div className={styles.biometricSignsArea}>
<label
className={styles.biometricSign}
htmlFor="biometrics-chart-radio-group"
>
Biometric Displayed
</label>
<RadioButtonGroup
defaultSelected="weight"
name="biometrics-chart-radio-group"
valueSelected="weight"
orientation="vertical"
labelPosition="right"
>
{[
{ id: "weight", label: `Weight (${weightUnit})` },
{ id: "height", label: `Height (${heightUnit})` },
{ id: "bmi", label: `BMI (${bmiUnit})` }
].map(({ id, label }) => (
<RadioButton
id={id}
labelText={label}
value={id}
className={styles.biometricSignsRadioButton}
onClick={() =>
setSelectedBiometrics({
title: label,
value: id,
groupName: id
})
}
/>
))}
</RadioButtonGroup>
</div>
<div className={styles.biometricChartArea}>
<LineChart data={chartData} options={chartOptions} />
</div>
</div>
);
};

export default BiometricsChart;
111 changes: 61 additions & 50 deletions src/widgets/biometrics/biometrics-overview.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import ErrorState from "../../ui-components/error-state/error-state.component";
import styles from "./biometrics-overview.scss";
import { getPatientBiometrics } from "./biometric.resource";
import { useVitalsSignsConceptMetaData } from "../vitals/vitals-biometrics-form/use-vitalsigns";
import BiometricsChart from "./biometrics-chart.component";

interface PatientBiometrics {
export interface PatientBiometrics {
id: string;
date: string;
weight: number;
Expand All @@ -50,6 +51,7 @@ const BiometricsOverview: React.FC<BiometricsOverviewProps> = ({ config }) => {
const displayText = t("biometrics", "biometrics");
const headerTitle = t("biometrics", "Biometrics");
const [, , , heightUnit, weightUnit] = conceptsUnits;
const [chartView, setChartView] = React.useState<boolean>();

const tableHeaders = [
{ key: "date", header: "Date", isSortable: true },
Expand Down Expand Up @@ -112,7 +114,7 @@ const BiometricsOverview: React.FC<BiometricsOverviewProps> = ({ config }) => {
const RenderBiometrics: React.FC = () => {
if (tableRows.length) {
return (
<div>
<div className={styles.biometricsWidgetContainer}>
<div className={styles.biometricHeaderContainer}>
<h4>Biometrics</h4>
<Button
Expand All @@ -129,67 +131,76 @@ const BiometricsOverview: React.FC<BiometricsOverviewProps> = ({ config }) => {
className={styles.toggle}
size="field"
hasIconOnly
kind="secondary"
kind={chartView ? "ghost" : "secondary"}
renderIcon={Table16}
iconDescription="Table View"
onClick={() => setChartView(false)}
/>
<Button
className={styles.toggle}
size="field"
kind="ghost"
kind={chartView ? "secondary" : "ghost"}
hasIconOnly
renderIcon={ChartLineSmooth16}
iconDescription="Chart View"
onClick={() => setChartView(true)}
/>
</div>
<TableContainer>
<DataTable
rows={tableRows}
headers={tableHeaders}
isSortable={true}
sortRow={sortRow}
>
{({ rows, headers, getHeaderProps, getTableProps }) => (
<Table {...getTableProps()}>
<TableHead>
<TableRow>
{headers.map(header => (
<TableHeader
{...getHeaderProps({
header,
isSortable: header.isSortable
})}
>
{header.header?.content ?? header.header}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map(row => (
<TableRow key={row.id}>
{row.cells.map(cell => (
<TableCell key={cell.id}>
{cell.value?.content ?? cell.value}
</TableCell>
))}
</TableRow>
))}
{biometrics.length > initialResultsDisplayed && (
{chartView ? (
<BiometricsChart
patientBiometrics={biometrics}
conceptsUnits={conceptsUnits}
/>
) : (
<TableContainer>
<DataTable
rows={tableRows}
headers={tableHeaders}
isSortable={true}
sortRow={sortRow}
>
{({ rows, headers, getHeaderProps, getTableProps }) => (
<Table {...getTableProps()}>
<TableHead>
<TableRow>
{!displayAllResults && (
<TableCell colSpan={4}>
{`${initialResultsDisplayed} / ${biometrics.length}`}{" "}
<Link onClick={toggleAllResults}>See all</Link>
</TableCell>
)}
{headers.map(header => (
<TableHeader
{...getHeaderProps({
header,
isSortable: header.isSortable
})}
>
{header.header?.content ?? header.header}
</TableHeader>
))}
</TableRow>
)}
</TableBody>
</Table>
)}
</DataTable>
</TableContainer>
</TableHead>
<TableBody>
{rows.map(row => (
<TableRow key={row.id}>
{row.cells.map(cell => (
<TableCell key={cell.id}>
{cell.value?.content ?? cell.value}
</TableCell>
))}
</TableRow>
))}
{biometrics.length > initialResultsDisplayed && (
<TableRow>
{!displayAllResults && (
<TableCell colSpan={4}>
{`${initialResultsDisplayed} / ${biometrics.length}`}{" "}
<Link onClick={toggleAllResults}>See all</Link>
</TableCell>
)}
</TableRow>
)}
</TableBody>
</Table>
)}
</DataTable>
</TableContainer>
)}
</div>
);
}
Expand Down
5 changes: 5 additions & 0 deletions src/widgets/biometrics/biometrics-overview.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
@import "../../root.scss";

.biometricsWidgetContainer {
background-color: $ui-background;
position: relative;
}

.biometricHeaderContainer {
display: flex;
justify-content: space-between;
Expand Down

0 comments on commit 3a094b2

Please sign in to comment.