diff --git a/client/index.html b/client/index.html index d4d9548d..b0dee087 100644 --- a/client/index.html +++ b/client/index.html @@ -7,7 +7,7 @@ name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> - SF Life line + SF Life Line
diff --git a/client/src/pages/patients/patient-details/PatientDetails.jsx b/client/src/pages/patients/patient-details/PatientDetails.jsx index 82843c4e..ecb941cd 100644 --- a/client/src/pages/patients/patient-details/PatientDetails.jsx +++ b/client/src/pages/patients/patient-details/PatientDetails.jsx @@ -1,9 +1,17 @@ -import { useParams, useNavigate } from 'react-router-dom'; +import { useEffect } from 'react'; +import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; -import LifelineAPI from '../LifelineAPI.js'; import { StatusCodes } from 'http-status-codes'; -import { useEffect } from 'react'; -import { Loader } from '@mantine/core'; +import { humanize } from 'inflection'; +import { QRCode } from 'react-qrcode-logo'; +import { Container, Grid, Loader, Text, Title } from '@mantine/core'; + +import LifelineAPI from '../LifelineAPI.js'; +import ContactInfo from './components/ContactInfo.jsx'; +import MedicalInfo from './components/MedicalInfo.jsx'; +import Preferences from './components/Preferences.jsx'; + +import classes from './PatientDetails.module.css'; /** * @@ -12,8 +20,9 @@ import { Loader } from '@mantine/core'; export default function PatientDetails() { const { patientId } = useParams(); const navigate = useNavigate(); + const location = useLocation(); - const { data, isSuccess, isError, isLoading } = useQuery({ + const { data, isError, isLoading } = useQuery({ queryKey: ['patient'], queryFn: async () => { const res = await LifelineAPI.getPatient(patientId); @@ -23,11 +32,7 @@ export default function PatientDetails() { throw new Error('Failed to fetch patient.'); } }, - - retry: false, - refetchOnWindowFocus: false, }); - console.log(data, isSuccess, isError, isLoading); useEffect(() => { if (isError) { @@ -43,12 +48,37 @@ export default function PatientDetails() { } return ( -
-

Patient

-

This is the patient page

-

Patient ID: {data?.id}

-

Patient First Name: {data?.firstName}

-

Patient Last Name: {data?.lastName}

+
+ + + + + {data?.firstName} {data?.lastName} + +
+ Date of birth + Gender + Preferred language + {data?.dateOfBirth} + {humanize(data?.gender)} + {humanize(data?.language)} +
+
+ + + +
+ + + +
); } diff --git a/client/src/pages/patients/patient-details/PatientDetails.module.css b/client/src/pages/patients/patient-details/PatientDetails.module.css new file mode 100644 index 00000000..33257737 --- /dev/null +++ b/client/src/pages/patients/patient-details/PatientDetails.module.css @@ -0,0 +1,71 @@ +.boldText { + font-weight: 600; + margin-top: var(--mantine-spacing-sm); + margin-bottom: var(--mantine-spacing-sm); +} + +.patientInfoContainer { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: auto auto; + text-align: center; + gap: var(--mantine-spacing-sm); +} + +.patientInfoContainer p:nth-child(-n + 3) { + font-weight: 600; + margin-bottom: 0; +} + +.patientInfoContainer p:nth-child(n + 4) { + margin-top: 0; +} + +.sectionTitle { + font-size: var(--mantine-font-size-xl); + font-weight: 600; + margin-top: var(--mantine-spacing-md); + margin-bottom: var(--mantine-spacing-md); +} + +.titleRow { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--mantine-spacing-xl); + margin-bottom: var(--mantine-spacing-md); +} + +.twoColumnGrid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--mantine-spacing-xl); +} + +.contactRow { + gap: var(--mantine-spacing-md); + margin-bottom: var(--mantine-spacing-xs); +} + +.contactInfoColumnTitle { + font-weight: 600; + font-size: var(--mantine-font-size-lg); +} + +.medicalInfoPills { + margin-right: var(--mantine-spacing-sm); + margin-bottom: var(--mantine-spacing-sm); + user-select: text; +} + +@media (min-width: 768px) { + .patientInfoContainer { + text-align: left; + width: 70%; + } + + .details { + max-height: 100vh; + max-height: 100dvh; + overflow-y: auto; + } +} diff --git a/client/src/pages/patients/patient-details/components/ContactInfo.jsx b/client/src/pages/patients/patient-details/components/ContactInfo.jsx new file mode 100644 index 00000000..fe21a9fe --- /dev/null +++ b/client/src/pages/patients/patient-details/components/ContactInfo.jsx @@ -0,0 +1,82 @@ +import PropTypes from 'prop-types'; + +import { Paper, Text } from '@mantine/core'; +import { humanize } from 'inflection'; +import classes from '../PatientDetails.module.css'; + +const contactInfoProps = { + emergencyContact: PropTypes.object, + physician: PropTypes.object, +}; + +ContactInfo.propTypes = contactInfoProps; + +/** + * + * @param {PropTypes.InferProps} props + */ +export default function ContactInfo({ emergencyContact, physician }) { + return ( +
+ Contact Information + +
+ + Emergency Contact + + + Primary care physician (PCP) contact + +
+
+
+
+ Name + + {emergencyContact + ? `${emergencyContact?.firstName} ${emergencyContact?.lastName}` + : '-'} + +
+
+ Phone + + {emergencyContact?.phone ? emergencyContact?.phone : '-'} + +
+
+ Relationship + + {emergencyContact?.relationship + ? humanize(emergencyContact?.relationship) + : '-'} + +
+
+
+
+ Name + + {physician + ? `${physician?.firstName} ${physician?.lastName}` + : '-'} + +
+
+ Phone + {physician?.phone ? physician?.phone : '-'} +
+
+ Hospital + + {physician?.hospitals[0]?.name + ? physician?.hospitals[0]?.name + : '-'} + +
+
+
+
+
+ ); +} diff --git a/client/src/pages/patients/patient-details/components/MedicalInfo.jsx b/client/src/pages/patients/patient-details/components/MedicalInfo.jsx new file mode 100644 index 00000000..6916c2f8 --- /dev/null +++ b/client/src/pages/patients/patient-details/components/MedicalInfo.jsx @@ -0,0 +1,70 @@ +import PropTypes from 'prop-types'; + +import { Paper, Text, Pill } from '@mantine/core'; +import classes from '../PatientDetails.module.css'; + +const medicalInfoProps = { + allergies: PropTypes.array, + medications: PropTypes.array, + conditions: PropTypes.array, +}; + +MedicalInfo.propTypes = medicalInfoProps; + +/** + * + * @param {PropTypes.InferProps} props + */ +export default function MedicalInfo({ allergies, medications, conditions }) { + return ( +
+ Medical Information + +
+ Allergies + {allergies.length === 0 ? ( + None + ) : ( + allergies.map((entry) => ( + + {entry.allergy.name} + + )) + )} +
+
+ Medications + {medications.length === 0 ? ( + None + ) : ( + medications.map((entry) => ( + + {entry.medication.name} + + )) + )} +
+
+ Conditions + {conditions?.length === 0 ? ( + None + ) : ( +
    + {conditions.map((entry) => ( +
  • {entry.condition.name}
  • + ))} +
+ )} +
+
+
+ ); +} diff --git a/client/src/pages/patients/patient-details/components/Preferences.jsx b/client/src/pages/patients/patient-details/components/Preferences.jsx new file mode 100644 index 00000000..26ed2a43 --- /dev/null +++ b/client/src/pages/patients/patient-details/components/Preferences.jsx @@ -0,0 +1,30 @@ +import PropTypes from 'prop-types'; +import { Paper, Text } from '@mantine/core'; +import classes from '../PatientDetails.module.css'; +import { humanize } from 'inflection'; +const preferencesProps = { + codeStatus: PropTypes.string, + hospital: PropTypes.object, +}; + +Preferences.propTypes = preferencesProps; + +/** + * Preferences section of patient details + * @param {PropTypes.InferProps} props + */ +export default function Preferences({ codeStatus, hospital }) { + return ( +
+ Preferences + +
+ Code status + {codeStatus ? humanize(codeStatus) : 'Not provided'} + Hospital + {hospital ? hospital.name : 'Not provided'} +
+
+
+ ); +} diff --git a/client/src/pages/patients/register/PatientRegistration.jsx b/client/src/pages/patients/register/PatientRegistration.jsx index 926cdde2..e0718260 100644 --- a/client/src/pages/patients/register/PatientRegistration.jsx +++ b/client/src/pages/patients/register/PatientRegistration.jsx @@ -279,7 +279,7 @@ export default function PatientRegistration() { ); if (updateRes.status === StatusCodes.OK) { showSuccessNotification('Successfully registered patient.'); - navigate('/dashboard', { replace: true }); + navigate(`/patients/${patientId}`, { replace: true }); return; } } @@ -299,7 +299,7 @@ export default function PatientRegistration() { showSuccessNotification( 'Patient basic information has been successfully updated.', ); - navigate('/dashboard', { replace: true }); + navigate(`/patients/${patientId}`, { replace: true }); return; } }