Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Closes #114, #122] Add checkmark to viewed patient registration form sections #128

Merged
merged 14 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
.control {
background-color: var(--mantine-color-gray-6);
font-weight: 600;

&[data-active] {
background-color: white;
}
}

.label {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 1.5rem;
margin-right: 1rem;
}
80 changes: 39 additions & 41 deletions client/src/pages/patients/PatientRegistration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,7 @@ import { useQuery } from '@tanstack/react-query';
import LifelineAPI from './LifelineAPI.js';
import PatientRegistrationAccordion from './PatientRegistrationAccordion';

const TABS = [
'patientData',
'contactData',
'medicalData',
'healthcareChoices',
'codeStatus',
];

const ERROR_SECTION_MAP = {
const FORM_TABS = {
patientData: 'Patient Data',
contactData: 'Emergency Contact',
medicalData: 'Medical Information',
Expand All @@ -32,13 +24,20 @@ const ERROR_SECTION_MAP = {
*/
export default function PatientRegistration() {
const [loading, setLoading] = useState(false);
const [active, setActive] = useState(0);
const [initialMedicalData, setInitialMedicalData] = useState({});
const [initialHospitalData, setInitialHospitalData] = useState({});
const [initialPhysicianData, setInitialPhysicianData] = useState({});
const [initialHospitalData, setInitialHospitalData] = useState('');
const [initialPhysicianData, setInitialPhysicianData] = useState('');
const [openedSection, setOpenedSection] = useState('patientData');
const [opened, { open, close }] = useDisclosure(false);

const [showCheck, setShowCheck] = useState({
patientData: false,
contactData: false,
medicalData: false,
healthcareChoices: false,
codeStatus: false,
});

const [visitedSections, setVisitedSections] = useState({
patientData: true,
contactData: false,
Expand Down Expand Up @@ -168,15 +167,11 @@ export default function PatientRegistration() {
}),
});

setInitialHospitalData({
id: hospital ? hospital.id : '',
name: hospital ? hospital.name : '',
});
setInitialHospitalData(hospital ? hospital.name : '');

setInitialPhysicianData({
id: physician ? physician.id : '',
name: physician ? `${physician.firstName} ${physician.lastName}` : '',
});
setInitialPhysicianData(
physician ? `${physician.firstName} ${physician.lastName}` : '',
);

const patientData = {
firstName,
Expand Down Expand Up @@ -251,7 +246,7 @@ export default function PatientRegistration() {

const unvisited = Object.entries(visitedSections)
.filter(([_, visited]) => !visited)
.map(([section]) => ERROR_SECTION_MAP[section]);
.map(([section]) => FORM_TABS[section]);

if (unvisited.length > 0) {
setUnvisitedSections(unvisited);
Expand Down Expand Up @@ -324,7 +319,7 @@ export default function PatientRegistration() {

let errorSections = [];
errorSets.forEach((key) => {
errorSections.push(ERROR_SECTION_MAP[key]);
errorSections.push(FORM_TABS[key]);
});

showErrorNotification(
Expand All @@ -343,6 +338,10 @@ export default function PatientRegistration() {
showSuccessNotification(
'Patient basic information has been successfully registered.',
);
setShowCheck((prevShowCheck) => ({
...prevShowCheck,
patientData: true,
}));
return;
}

Expand All @@ -355,6 +354,10 @@ export default function PatientRegistration() {
showSuccessNotification(
'Patient basic information has been successfully updated.',
);
setShowCheck((prevShowCheck) => ({
...prevShowCheck,
patientData: true,
}));
return;
}
throw new Error('Failed to update patient.');
Expand Down Expand Up @@ -382,6 +385,10 @@ export default function PatientRegistration() {
showSuccessNotification(
'Patient information has been successfully updated.',
);
setShowCheck((prevShowCheck) => ({
...prevShowCheck,
[Object.keys(data)[0]]: true,
}));
return;
}
if (res.status === StatusCodes.BAD_REQUEST) {
Expand All @@ -403,25 +410,11 @@ export default function PatientRegistration() {
* @param {string} value
*/
async function handleAccordionChange(value) {
value === null
? navigate('', { replace: true })
: navigate(`#${value}`, { replace: true });

setVisitedSections((prevVisitedSections) => ({
...prevVisitedSections,
[value]: true,
}));

if (!openedSection) {
setOpenedSection(value);
setActive(TABS.indexOf(value));
return;
}

if (TABS.indexOf(value) < active) {
setOpenedSection(value);
setActive(TABS.indexOf(value));
if (value === null) {
navigate('', { replace: true });
return;
} else {
navigate(`#${value}`, { replace: true });
}

let errorFieldCount = 0;
Expand All @@ -437,7 +430,11 @@ export default function PatientRegistration() {

if (errorFieldCount === 0) {
setOpenedSection(value);
setActive(TABS.indexOf(value));

setVisitedSections((prevVisitedSections) => ({
...prevVisitedSections,
[value]: true,
}));

if (openedSection === 'patientData') {
const patientData = {
Expand Down Expand Up @@ -479,6 +476,7 @@ export default function PatientRegistration() {
initialHospitalData={initialHospitalData}
initialPhysicianData={initialPhysicianData}
openedSection={openedSection}
showCheck={showCheck}
handleAccordionChange={handleAccordionChange}
/>
<Flex justify="center" mt="md">
Expand Down
106 changes: 74 additions & 32 deletions client/src/pages/patients/PatientRegistrationAccordion.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PropTypes from 'prop-types';

import { Accordion, TextInput, Select, InputBase } from '@mantine/core';
import { DateInput } from '@mantine/dates';
import { IconCircleCheck } from '@tabler/icons-react';
import { IMaskInput } from 'react-imask';
import MedicalDataSearch from './inputs/MedicalDataSearch';
import HealthcareChoicesSearch from './inputs/HealthcareChoicesSearch';
Expand All @@ -10,13 +11,37 @@ import classes from './PatientRegistationAccordion.module.css';

const PatientRegistrationAccordionProps = {
form: PropTypes.object.isRequired,
openedSection: PropTypes.string,
handleAccordionChange: PropTypes.func.isRequired,
initialMedicalData: PropTypes.object,
initialHospitalData: PropTypes.object,
initialPhysicianData: PropTypes.object,
openedSection: PropTypes.string,
showCheck: PropTypes.object.isRequired,
handleAccordionChange: PropTypes.func.isRequired,
};

const FORM_SELECT_ENUM_VALUES = {
language: [
'CANTONESE',
'ENGLISH',
'MANDARIN',
'RUSSIAN',
'SPANISH',
'TAGALOG',
],
gender: ['FEMALE', 'MALE', 'TRANS_MALE', 'TRANS_FEMALE', 'OTHER', 'UNKNOWN'],
relationship: ['SPOUSE', 'PARENT', 'CHILD', 'SIBLING', 'OTHER', 'UNKNOWN'],
codeStatus: ['COMFORT', 'DNR', 'DNI', 'DNR_DNI', 'FULL'],
};

/**
* Converts a string to title case
* @param {string} string
* @returns {string}
*/
function toTitleCase(string) {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
}

/**
* Patient Registration Accordion component
* @param {PropTypes.InferProps<typeof PatientRegistrationAccordionProps>} props
Expand All @@ -27,6 +52,7 @@ export default function PatientRegistrationAccordion({
initialHospitalData,
initialPhysicianData,
openedSection,
showCheck,
handleAccordionChange,
}) {
return (
Expand All @@ -38,7 +64,12 @@ export default function PatientRegistrationAccordion({
classNames={classes}
>
<Accordion.Item value="patientData">
<Accordion.Control>&#9312; Basic Information</Accordion.Control>
<Accordion.Control chevron={false}>
&#9312; Basic Information{' '}
{showCheck['patientData'] ? (
<IconCircleCheck color="green" size={30} />
) : null}
</Accordion.Control>
<Accordion.Panel>
<TextInput
label="First Name"
Expand All @@ -64,14 +95,10 @@ export default function PatientRegistrationAccordion({
label="Gender"
placeholder="Select Gender"
withAsterisk
data={[
'FEMALE',
'MALE',
'TRANS_MALE',
'TRANS_FEMALE',
'OTHER',
'UNKNOWN',
]}
data={FORM_SELECT_ENUM_VALUES.gender.map((value) => ({
value,
label: toTitleCase(value),
}))}
searchable
key={form.key('patientData.gender')}
{...form.getInputProps('patientData.gender')}
Expand All @@ -80,14 +107,10 @@ export default function PatientRegistrationAccordion({
label="Language"
placeholder="Select Language"
withAsterisk
data={[
'CANTONESE',
'ENGLISH',
'MANDARIN',
'RUSSIAN',
'SPANISH',
'TAGALOG',
]}
data={FORM_SELECT_ENUM_VALUES.language.map((value) => ({
value,
label: toTitleCase(value),
}))}
searchable
key={form.key('patientData.language')}
{...form.getInputProps('patientData.language')}
Expand All @@ -106,7 +129,12 @@ export default function PatientRegistrationAccordion({
</Accordion.Item>

<Accordion.Item value="contactData">
<Accordion.Control>&#9313; Emergency Contact</Accordion.Control>
<Accordion.Control>
&#9313; Emergency Contact{' '}
{showCheck['contactData'] ? (
<IconCircleCheck color="green" size={30} />
) : null}
</Accordion.Control>
<Accordion.Panel>
<TextInput
label="First Name"
Expand Down Expand Up @@ -143,14 +171,10 @@ export default function PatientRegistrationAccordion({
<Select
label="Relationship"
placeholder="Select Relationship"
data={[
'SPOUSE',
'PARENT',
'CHILD',
'SIBLING',
'OTHER',
'UNKNOWN',
]}
data={FORM_SELECT_ENUM_VALUES.relationship.map((value) => ({
value,
label: toTitleCase(value),
}))}
searchable
key={form.key('contactData.relationship')}
{...form.getInputProps('contactData.relationship')}
Expand All @@ -159,7 +183,12 @@ export default function PatientRegistrationAccordion({
</Accordion.Item>

<Accordion.Item value="medicalData">
<Accordion.Control>&#9314; Medical Information</Accordion.Control>
<Accordion.Control>
&#9314; Medical Information{' '}
{showCheck['medicalData'] ? (
<IconCircleCheck color="green" size={30} />
) : null}
</Accordion.Control>
<Accordion.Panel>
{Object.keys(form.getValues().medicalData).map((category) => {
return (
Expand All @@ -175,7 +204,12 @@ export default function PatientRegistrationAccordion({
</Accordion.Item>

<Accordion.Item value="healthcareChoices">
<Accordion.Control>&#9315; Healthcare Choices</Accordion.Control>
<Accordion.Control>
&#9315; Healthcare Choices{' '}
{showCheck['healthcareChoices'] ? (
<IconCircleCheck color="green" size={30} />
) : null}
</Accordion.Control>
<Accordion.Panel>
<HealthcareChoicesSearch
form={form}
Expand All @@ -191,12 +225,20 @@ export default function PatientRegistrationAccordion({
</Accordion.Item>

<Accordion.Item value="codeStatus">
<Accordion.Control>&#9316; Advanced Directive</Accordion.Control>
<Accordion.Control>
&#9316; Advanced Directive{' '}
{showCheck['codeStatus'] ? (
<IconCircleCheck color="green" size={30} />
) : null}
</Accordion.Control>
<Accordion.Panel>
<Select
label="Code Status"
placeholder="Select Code Status"
data={['COMFORT', 'DNR', 'DNI', 'DNR_DNI', 'FULL']}
data={FORM_SELECT_ENUM_VALUES.codeStatus.map((value) => ({
value,
label: toTitleCase(value),
}))}
searchable
key={form.key('codeStatus')}
{...form.getInputProps('codeStatus')}
Expand Down
Loading