Skip to content

Commit

Permalink
Reporting Demo Changes (#1912)
Browse files Browse the repository at this point in the history
  • Loading branch information
TrevorAntony authored Jul 25, 2024
1 parent 6807f93 commit 1045d03
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 9 deletions.
143 changes: 143 additions & 0 deletions packages/esm-commons-lib/src/components/reports/home.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.centeredTextContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 50px;
text-align: center;
}

.container {
padding: 2rem;
}

.homeContainer {
padding: 1rem;
}

.dropdownItem {
display: flex;
align-items: center;
}

.layer {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
}

.tile {
padding: 2rem;
text-align: center;
}

.content {
font-size: 1.25rem;
color: #5a5a5a;
}

.explainer {
color: #777;
}

.form {
display: flex;
flex-direction: column;
gap: 1rem;
}

.formContainer {
display: flex;
flex-direction: column;
}

.datePickerContainer {
display: flex;
align-items: center;
gap: 8px;
justify-content: space-between;
flex-wrap: wrap;
}

.datePickerContainer > * {
flex: 1;
min-width: 150px;
}

.fetchButtonContainer {
margin-left: 16px;
display: flex;
align-items: center;
}

.datePickerInput {
min-width: 120px;
}

.button {
max-height: 40px;
line-height: 40px;
font-size: 14px;
padding: 0 16px;
margin-top: 1rem;
max-width: 120px;
align-items: center;
}

.dataTableContainer {
margin-top: 2rem;
padding: 1rem;
border: solid 1px #e0e0e0;
max-height: calc(100vh - 200px);
overflow: auto;
height: 100vh;
}

.dataTableFullContainer {
margin-top: 2rem;
padding: 1rem;
max-height: calc(100vh - 200px);
overflow: auto;
}


.tableContainer {
margin-top: 1rem;
}

.toolbarWrapper {
display: flex;
justify-content: space-between;
align-items: center;
}

.toolbarContent {
display: flex;
gap: 1rem;
}

.searchbox {
flex-grow: 1;
}

.tileContainer {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
}

.tileContent {
text-align: center;
}

.content {
font-size: 1.25rem;
color: #5a5a5a;
}

.pagination {
margin-top: 1rem;
}

75 changes: 75 additions & 0 deletions packages/esm-commons-lib/src/components/reports/reportfilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import { ComboBox, Button, DatePicker, DatePickerInput } from '@carbon/react';
import styles from './home.component.scss';

const ReportFilters = ({
config,
uuid,
reportId,
setReportId,
ptrackerId,
setPtrackerId,
personUuid,
setPersonUuid,
startDate,
setStartDate,
endDate,
setEndDate,
handleSubmit,
setReportRequested,
}) => {
const handleDateChange = (setter) => (event) => {
const date = event[0] ? event[0].toISOString().split('T')[0] : '';
setter(date);
};

return (
<>
<div className={styles.centeredTextContainer}>
<h2>Report Filters</h2>
</div>
<form className={styles.form} onSubmit={handleSubmit}>
<div className={styles.datePickerContainer}>
<ComboBox
id="report-dropdown"
titleText="Select Report"
label="Select a report to display"
items={config.reports}
itemToString={(item) => (item ? item.name : '')}
onChange={({ selectedItem }) => {
if (selectedItem) {
setReportId(selectedItem.uuid || '');
} else {
setReportId('');
setPtrackerId('');
setPersonUuid('');
setStartDate('');
setEndDate('');
setReportRequested(false);
}
}}
/>
<DatePicker
datePickerType="single"
onChange={handleDateChange(setStartDate)}
value={startDate ? [new Date(startDate)] : []}
>
<DatePickerInput id="start-date" labelText="Start Date" placeholder="yyyy-mm-dd" />
</DatePicker>
<DatePicker
datePickerType="single"
onChange={handleDateChange(setEndDate)}
value={endDate ? [new Date(endDate)] : []}
>
<DatePickerInput id="end-date" labelText="End Date" placeholder="yyyy-mm-dd" />
</DatePicker>
<Button className={styles.button} kind="tertiary" type="submit">
View Report
</Button>
</div>
</form>
</>
);
};

export default ReportFilters;
Original file line number Diff line number Diff line change
@@ -1,14 +1,153 @@
import React from 'react';
import React, { useState, useMemo, useEffect } from 'react';
import useSWR from 'swr';
import {
DataTable,
Table,
TableHead,
TableRow,
TableHeader,
TableBody,
TableCell,
Layer,
Tile,
DataTableSkeleton,
} from '@carbon/react';
import { OHRIWelcomeSection } from '@ohri/openmrs-esm-ohri-commons-lib';
import { Reports } from './reports';
import { openmrsFetch, useConfig, restBaseUrl } from '@openmrs/esm-framework';
import styles from './home.component.scss';
import capitalize from 'lodash/capitalize';
import { EmptyDataIllustration } from '@openmrs/esm-patient-common-lib';
import ReportFilters from './reportfilters';
import { useTranslation } from 'react-i18next';

const snakeCaseToCapitalizedWords = (snakeCaseString) =>
snakeCaseString
.split('_')
.map((word) => capitalize(word))
.join(' ');

const fetcher = (url) => openmrsFetch(url).then((res) => res.json());

const ReportComponent = () => {
const config = useConfig();
const { t } = useTranslation();
const [reportId, setReportId] = useState('');
const [uuid, setUuid] = useState('');
const [ptrackerId, setPtrackerId] = useState('');
const [personUuid, setPersonUuid] = useState('');
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [reportRequested, setReportRequested] = useState(false);

const url = useMemo(() => {
if (!startDate || !endDate || !reportId) return null;
return `${restBaseUrl}/reportingrest/reportdata/${reportId}?startDate=${startDate}&endDate=${endDate}`;
}, [reportId, startDate, endDate]);

const { data, error, mutate } = useSWR(url, fetcher, { revalidateOnFocus: false });

useEffect(() => {
if (error) {
console.error('Error fetching report data:', error);
}
}, [error]);

const headers = useMemo(() => {
if (!data || !data.dataSets || !data.dataSets.length || !data.dataSets[0].metadata) return [];
return data.dataSets[0].metadata.columns.map((column) => ({
key: column.name,
header: column.label,
}));
}, [data]);

const rows = useMemo(() => {
if (!data || !data.dataSets || !data.dataSets.length || !data.dataSets[0].rows) return [];
return data.dataSets[0].rows.map((result, idx) => ({
id: idx.toString(),
...result,
}));
}, [data]);

const loading = !data && !error && reportRequested;

const handleSubmit = (e) => {
e.preventDefault();
setReportRequested(true);
mutate();
};

const ReportsHomecomponent = () => {
return (
<div>
<OHRIWelcomeSection title="Reports" />
<Reports />
<div className={styles.homeContainer}>
<OHRIWelcomeSection title={t('reportingDemo', 'Reporting demo')} />
<ReportFilters
config={config}
reportId={reportId}
setReportId={setReportId}
ptrackerId={ptrackerId}
setPtrackerId={setPtrackerId}
personUuid={personUuid}
setPersonUuid={setPersonUuid}
startDate={startDate}
setStartDate={setStartDate}
endDate={endDate}
setEndDate={setEndDate}
handleSubmit={handleSubmit}
setReportRequested={setReportRequested}
uuid={uuid}
/>
{loading ? (
<DataTableSkeleton columnCount={headers.length} rowCount={rows.length} />
) : error ? (
<div className={styles.dataTableContainer}>
<Layer className={styles.layer}>
<Tile className={styles.tile}>
<p className={styles.content}>{t('errorLoadingData', 'Error loading data')}</p>
<p className={styles.explainer}>{t('pleaseTryAgain', 'Please try again later')}</p>
</Tile>
</Layer>
</div>
) : rows.length === 0 || !reportRequested ? (
<div className={styles.dataTableContainer}>
<Layer className={styles.layer}>
<Tile className={styles.tile}>
<EmptyDataIllustration />
<p className={styles.content}>{t('noDataToDisplay', 'No data to display')}</p>
<p className={styles.explainer}>
{t('useReportsAboveToBuild', 'Use the report filters above to build your reports')}
</p>
</Tile>
</Layer>
</div>
) : (
<div className={styles.dataTableFullContainer}>
<DataTable rows={rows} headers={headers}>
{({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
<Table {...getTableProps()}>
<TableHead>
<TableRow>
{headers.map((header) => (
<TableHeader {...getHeaderProps({ header })} key={header.key}>
{header.header}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow {...getRowProps({ row })} key={row.id}>
{headers.map((header) => (
<TableCell key={header.key}>{row[header.key] || '-'}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
)}
</DataTable>
</div>
)}
</div>
);
};

export default ReportsHomecomponent;
export default ReportComponent;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { SWRConfig } from 'swr';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import ReportsHome from './reports-home.component';
import ReportComponent from './reports-home.component';

const swrConfiguration = {
errorRetryCount: 3,
Expand All @@ -15,7 +15,7 @@ const RootComponent: React.FC = () => {
<SWRConfig value={swrConfiguration}>
<BrowserRouter basename={reportsBasename}>
<Routes>
<Route path="/" element={<ReportsHome />} />
<Route path="/" element={<ReportComponent />} />
</Routes>
</BrowserRouter>
</SWRConfig>
Expand Down
Loading

0 comments on commit 1045d03

Please sign in to comment.