Skip to content

Commit

Permalink
Merge branch 'dev' into issue-152
Browse files Browse the repository at this point in the history
  • Loading branch information
francisli committed Nov 1, 2024
2 parents 0042398 + 85ab24e commit 4c5a7c5
Show file tree
Hide file tree
Showing 27 changed files with 1,466 additions and 42 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
name: CI
on: [push]
on:
push:
branches:
- "dev"
- "main"
pull_request:
types: [opened, reopened, synchronize]

jobs:
ci:
name: CI
Expand Down
2 changes: 2 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import AuthLayout from './stories/AuthLayout/AuthLayout';
import Verify from './pages/verify/verify';
import PatientRegistration from './pages/patients/register/PatientRegistration';
import PatientDetails from './pages/patients/patient-details/PatientDetails';
import Patients from './pages/patients/Patients';

const RedirectProps = {
isLoading: PropTypes.bool.isRequired,
Expand Down Expand Up @@ -140,6 +141,7 @@ function App() {
element={<AdminPatientsGenerate />}
/>
<Route element={<Layout />}>
<Route path="/patients" element={<Patients />} />
<Route path="/patients/:patientId" element={<PatientDetails />} />
<Route
path="/patients/register/:patientId"
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Sidebar/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ const sections = [
label: 'Management',
icon: null,
links: [
{ label: 'Patient', href: '/', icon: <IconEmergencyBed stroke={2} /> },
{
label: 'Patients',
href: '/patients',
icon: <IconEmergencyBed stroke={2} />,
},
{
label: 'Team Member',
href: '/admin/users',
Expand Down
26 changes: 26 additions & 0 deletions client/src/pages/patients/LifelineAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export default class LifelineAPI {
});
}

static async registerPhysician(data) {
const response = await fetch(`${SERVER_BASE_URL}/physicians`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

return response;
}

static async getHospitals(query) {
const response = await fetch(
`${SERVER_BASE_URL}/hospitals?hospital=${query}`,
Expand All @@ -36,6 +48,13 @@ export default class LifelineAPI {
return response;
}

static async getPatients(query, page) {
const response = await fetch(
`${SERVER_BASE_URL}/patients?patient=${query}&page=${page}`,
);
return response;
}

static async registerPatient(data, patientId) {
const response = await fetch(`${SERVER_BASE_URL}/patients`, {
method: 'POST',
Expand All @@ -59,6 +78,13 @@ export default class LifelineAPI {
return response;
}

static async deletePatient(patientId) {
const response = await fetch(`${SERVER_BASE_URL}/patients/${patientId}`, {
method: 'DELETE',
});
return response;
}

static async getMedicalData(path, pathInfo, query) {
const response = await fetch(
`${SERVER_BASE_URL}/${path}?${pathInfo}=${query}`,
Expand Down
89 changes: 89 additions & 0 deletions client/src/pages/patients/PatientTableRow.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import PropTypes from 'prop-types';

import { Link } from 'react-router-dom';

import { Table, Menu, ActionIcon } from '@mantine/core';
import {
IconDotsVertical,
IconUser,
IconQrcode,
IconTrash,
} from '@tabler/icons-react';

const patientTableRowProps = {
headers: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
text: PropTypes.node,
}),
),
patient: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
createdBy: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
updatedBy: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
}),

onDelete: PropTypes.func.isRequired,
showDeleteMenu: PropTypes.bool.isRequired,
};

/**
* Patient table row component
* @param {PropTypes.InferProps<typeof patientTableRowProps>} props
*/
export default function PatientTableRow({
headers,
patient,
onDelete,
showDeleteMenu,
}) {
return (
<Table.Tr key={patient.id}>
{headers.map((header) => (
<Table.Td key={patient[header.key] + header.key}>
{patient[header.key]}
</Table.Td>
))}
<Table.Td>
<Menu shadow="md">
<Menu.Target>
<ActionIcon variant="subtle" color="gray">
<IconDotsVertical size={18} />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
leftSection={<IconUser size={18} />}
component={Link}
to={`/patients/${patient.id}`}
>
View/Edit
</Menu.Item>
<Menu.Item leftSection={<IconQrcode size={18} />}>
Reprint QR Code
</Menu.Item>
{showDeleteMenu && (
<Menu.Item
leftSection={<IconTrash size={18} />}
color="red"
onClick={() =>
onDelete({
id: patient.id,
name: patient.name,
})
}
>
Delete
</Menu.Item>
)}
</Menu.Dropdown>
</Menu>
</Table.Td>
</Table.Tr>
);
}

PatientTableRow.propTypes = patientTableRowProps;
63 changes: 63 additions & 0 deletions client/src/pages/patients/Patients.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
Container,
Group,
TextInput,
Divider,
Pagination,
LoadingOverlay,
Text,
} from '@mantine/core';
import { useDebouncedCallback } from '@mantine/hooks';
import { useState } from 'react';

import { IconSearch } from '@tabler/icons-react';

import classes from './Patients.module.css';
import PatientsTable from './PatientsTable';
import { usePatients } from './usePatients';

/**
* Patients page component
*
*/
export default function Patients() {
const [inputValue, setInputValue] = useState('');
const { patients, headers, isFetching, page, pages, setPage, setSearch } =
usePatients();

const handleSearch = useDebouncedCallback((query) => {
setSearch(query);
}, 500);

return (
<Container>
<div className={classes.header}>
<Text fw={600} size="xl" mr="md">
Patients
</Text>
<Group>
<TextInput
leftSectionPointerEvents="none"
leftSection={<IconSearch stroke={2} />}
placeholder="Search"
onChange={(event) => {
setInputValue(event.currentTarget.value);
handleSearch(event.currentTarget.value);
}}
value={inputValue}
/>
</Group>
</div>
<Divider mb="xl" />
<Container className={classes.patientsContainer}>
<LoadingOverlay
visible={isFetching}
zIndex={1000}
overlayProps={{ radius: 'sm', blur: 2 }}
/>
<PatientsTable headers={headers} data={patients} />
<Pagination total={pages} value={page} onChange={setPage} />
</Container>
</Container>
);
}
29 changes: 29 additions & 0 deletions client/src/pages/patients/Patients.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.tableWrapper {
margin-bottom: var(--mantine-spacing-xs);
}

.table {
border-radius: 7px;
overflow: hidden;
}

.title {
font-size: 1.2rem;
font-weight: 600;
color: var(--mantine-color-red-8);
}

.header {
display: flex;
justify-content: space-between;
margin: 1rem 1rem;
}

.patientsContainer {
position: relative;
margin-bottom: var(--mantine-spacing-lg);
}

.button {
margin-top: var(--mantine-spacing-lg);
}
Loading

0 comments on commit 4c5a7c5

Please sign in to comment.