-
Notifications
You must be signed in to change notification settings - Fork 3
BN-47 | Add. Patient Allergies Display Control #7
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
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
044ab87
BN-47 | Add. Row Styling For ExpandableDataTable
rahu1ramesh e6bc877
BN-47 | Add. Allergies To HomePage
rahu1ramesh 34474a7
BN-47 | Fix. Default Date Format
rahu1ramesh 42dc791
BN-47 | Add. Capitalize Common Util
rahu1ramesh fbfb74a
BN-47 | Fix. Remove Expanded View For Content Without Additional Data
rahu1ramesh 1cd47ac
Add. Custom Hook For Patient Allergies
rahu1ramesh 31ba27c
Add. Display Control For Patient Allergies
rahu1ramesh aac34bc
Fix. Failing Test Case
rahu1ramesh 8e8e43e
Merge branch 'main' into BN-47
rahu1ramesh 199a5a4
BN-47 | Refactor. Use Import Aliases
rahu1ramesh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,221 @@ | ||
| import { | ||
| FhirAllergyIntolerance, | ||
| FhirAllergyIntoleranceBundle, | ||
| } from '@types/allergy'; | ||
|
|
||
| export const mockAllergyIntolerance: FhirAllergyIntolerance = { | ||
| resourceType: 'AllergyIntolerance', | ||
| id: 'allergy-123', | ||
| meta: { | ||
| versionId: '1', | ||
| lastUpdated: '2023-01-01T12:00:00Z', | ||
| }, | ||
| clinicalStatus: { | ||
| coding: [ | ||
| { | ||
| system: | ||
| 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical', | ||
| code: 'active', | ||
| display: 'Active', | ||
| }, | ||
| ], | ||
| }, | ||
| type: 'allergy', | ||
| category: ['food'], | ||
| criticality: 'high', | ||
| code: { | ||
| coding: [ | ||
| { | ||
| system: 'http://snomed.info/sct', | ||
| code: '91935009', | ||
| display: 'Peanut', | ||
| }, | ||
| ], | ||
| text: 'Peanut Allergy', | ||
| }, | ||
| patient: { | ||
| reference: 'Patient/patient-123', | ||
| display: 'John Doe', | ||
| }, | ||
| recordedDate: '2023-01-01T12:00:00Z', | ||
| recorder: { | ||
| reference: 'Practitioner/practitioner-123', | ||
| display: 'Dr. Smith', | ||
| }, | ||
| reaction: [ | ||
| { | ||
| manifestation: [ | ||
| { | ||
| coding: [ | ||
| { | ||
| system: 'http://snomed.info/sct', | ||
| code: '247472004', | ||
| display: 'Hives', | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| severity: 'moderate', | ||
| }, | ||
| ], | ||
| note: [ | ||
| { | ||
| text: 'Patient experiences severe reaction within minutes of exposure', | ||
| }, | ||
| { | ||
| text: 'Requires immediate medical attention if exposed', | ||
| }, | ||
| ], | ||
| }; | ||
| export const mockAllergyIntoleranceWithoutNote: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| note: undefined, | ||
| }; | ||
|
|
||
| export const mockAllergyIntoleranceBundle: FhirAllergyIntoleranceBundle = { | ||
| resourceType: 'Bundle', | ||
| id: 'bundle-123', | ||
| meta: { | ||
| lastUpdated: '2023-01-01T12:00:00Z', | ||
| }, | ||
| type: 'searchset', | ||
| total: 1, | ||
| link: [ | ||
| { | ||
| relation: 'self', | ||
| url: 'http://example.org/fhir/AllergyIntolerance?patient=patient-123', | ||
| }, | ||
| ], | ||
| entry: [ | ||
| { | ||
| fullUrl: 'http://example.org/fhir/AllergyIntolerance/allergy-123', | ||
| resource: mockAllergyIntolerance, | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| export const mockEmptyAllergyIntoleranceBundle: FhirAllergyIntoleranceBundle = { | ||
| resourceType: 'Bundle', | ||
| id: 'bundle-empty', | ||
| meta: { | ||
| lastUpdated: '2023-01-01T12:00:00Z', | ||
| }, | ||
| type: 'searchset', | ||
| total: 0, | ||
| link: [ | ||
| { | ||
| relation: 'self', | ||
| url: 'http://example.org/fhir/AllergyIntolerance?patient=patient-123', | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| export const mockAllergyIntoleranceBundleWithoutEntries: FhirAllergyIntoleranceBundle = | ||
| { | ||
| resourceType: 'Bundle', | ||
| id: 'bundle-no-entries', | ||
| meta: { | ||
| lastUpdated: '2023-01-01T12:00:00Z', | ||
| }, | ||
| type: 'searchset', | ||
| total: 0, | ||
| link: [ | ||
| { | ||
| relation: 'self', | ||
| url: 'http://example.org/fhir/AllergyIntolerance?patient=patient-123', | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| /** | ||
| * Mock allergy with missing fields (recorder, reactions, note) | ||
| */ | ||
| export const mockAllergyWithMissingFields: FhirAllergyIntolerance = { | ||
| resourceType: 'AllergyIntolerance', | ||
| id: 'allergy-incomplete', | ||
| meta: { | ||
| versionId: '1', | ||
| lastUpdated: '2023-01-01T12:00:00Z', | ||
| }, | ||
| clinicalStatus: { | ||
| coding: [ | ||
| { | ||
| system: | ||
| 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical', | ||
| code: 'active', | ||
| display: 'Active', | ||
| }, | ||
| ], | ||
| }, | ||
| code: { | ||
| coding: [ | ||
| { | ||
| system: 'http://snomed.info/sct', | ||
| code: '91935009', | ||
| display: 'Peanut', | ||
| }, | ||
| ], | ||
| text: 'Peanut Allergy', | ||
| }, | ||
| patient: { | ||
| reference: 'Patient/patient-123', | ||
| display: 'John Doe', | ||
| }, | ||
| recordedDate: '2023-01-01T12:00:00Z', | ||
| }; | ||
|
|
||
| export const mockAllergyWithEmptyReactions: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| id: 'allergy-empty-reactions', | ||
| reaction: [], | ||
| }; | ||
|
|
||
| export const mockAllergyWithIncompleteReactions: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| id: 'allergy-incomplete-reactions', | ||
| reaction: [ | ||
| { | ||
| manifestation: [ | ||
| { | ||
| coding: [], | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| export const mockAllergyWithoutClinicalStatusDisplay: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| id: 'allergy-no-status-display', | ||
| clinicalStatus: { | ||
| coding: [], | ||
| }, | ||
| }; | ||
|
|
||
| /** | ||
| * Mock allergy with multiple detailed notes | ||
| */ | ||
| export const mockAllergyWithMultipleNotes: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| id: 'allergy-with-notes', | ||
| note: [ | ||
| { | ||
| text: 'First documented reaction at age 5', | ||
| }, | ||
| { | ||
| text: 'Carries epinephrine auto-injector', | ||
| }, | ||
| { | ||
| text: 'Family history of similar allergies', | ||
| }, | ||
| ], | ||
| }; | ||
|
|
||
| /** | ||
| * Mock allergy with empty notes array | ||
| */ | ||
| export const mockAllergyWithEmptyNotes: FhirAllergyIntolerance = { | ||
| ...mockAllergyIntolerance, | ||
| id: 'allergy-empty-notes', | ||
| note: [], | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| import React, { useMemo } from 'react'; | ||
| import { Tag } from '@carbon/react'; | ||
| import { ExpandableDataTable } from '@components/expandableDataTable/ExpandableDataTable'; | ||
| import { usePatientUUID } from '@hooks/usePatientUUID'; | ||
| import { useAllergies } from '@hooks/useAllergies'; | ||
| import { formatAllergies } from '@services/allergyService'; | ||
| import { FormattedAllergy } from '@types/allergy'; | ||
| import { formatDateTime } from '@utils/date'; | ||
| import { generateId, capitalize } from '@utils/common'; | ||
|
|
||
| /** | ||
| * Component to display patient allergies in a DataTable with expandable rows | ||
| */ | ||
| const AllergiesTable: React.FC = () => { | ||
| const patientUUID = usePatientUUID(); | ||
| const { allergies, loading, error } = useAllergies(patientUUID); | ||
|
|
||
| // Define table headers | ||
| const headers = useMemo( | ||
| () => [ | ||
| { key: 'display', header: 'Allergy' }, | ||
| { key: 'manifestation', header: 'Reaction(s)' }, | ||
| { key: 'status', header: 'Status' }, | ||
| { key: 'severity', header: 'Severity' }, | ||
| { key: 'recorder', header: 'Provider' }, | ||
| { key: 'recordedDate', header: 'Recorded Date' }, | ||
| ], | ||
| [], | ||
| ); | ||
|
|
||
| // Format allergies for display | ||
| const formattedAllergies = useMemo(() => { | ||
| if (!allergies || allergies.length === 0) return []; | ||
| return formatAllergies(allergies); | ||
| }, [allergies]); | ||
|
|
||
| // Create row class names array for styling rows with severe allergies | ||
| const rowClassNames = useMemo(() => { | ||
| return formattedAllergies.map((allergy) => | ||
| allergy.reactions?.some((reaction) => reaction.severity === 'severe') | ||
| ? 'criticalCell' | ||
| : '', | ||
| ); | ||
| }, [formattedAllergies]); | ||
|
|
||
| // Function to render cell content based on the cell ID | ||
| const renderCell = (allergy: FormattedAllergy, cellId: string) => { | ||
| switch (cellId) { | ||
| case 'display': | ||
| return allergy.display; | ||
| case 'status': | ||
| return ( | ||
| <Tag type={allergy.status === 'Active' ? 'green' : 'gray'}> | ||
| {allergy.status} | ||
| </Tag> | ||
| ); | ||
| case 'manifestation': | ||
| return allergy.reactions | ||
| ? allergy.reactions | ||
| .map((reaction) => reaction.manifestation.join(', ')) | ||
| .join(', ') | ||
| : 'Not available'; | ||
| case 'severity': | ||
| return allergy.reactions | ||
| ? allergy.reactions | ||
| .map((reaction) => reaction.severity) | ||
| .filter((severity): severity is string => !!severity) | ||
| .map((severity) => capitalize(severity)) | ||
| .join(', ') | ||
| : 'Not available'; | ||
| case 'recorder': | ||
| return allergy.recorder || 'Not available'; | ||
| case 'recordedDate': | ||
| return formatDateTime(allergy.recordedDate || ''); | ||
| } | ||
| }; | ||
|
|
||
| // Function to render expanded content for an allergy | ||
| const renderExpandedContent = (allergy: FormattedAllergy) => { | ||
| if (allergy.note && allergy.note.length > 0) { | ||
| return ( | ||
| <p style={{ padding: '0.5rem' }} key={generateId()}> | ||
| {allergy.note.join(', ')} | ||
| </p> | ||
| ); | ||
| } | ||
| return undefined; | ||
| }; | ||
|
|
||
| return ( | ||
| <div | ||
| style={{ width: '100%', paddingTop: '1rem' }} | ||
| data-testid="allergy-table" | ||
| > | ||
| <ExpandableDataTable | ||
| tableTitle="Allergies" | ||
| rows={formattedAllergies} | ||
| headers={headers} | ||
| renderCell={renderCell} | ||
| renderExpandedContent={renderExpandedContent} | ||
| loading={loading} | ||
| error={error} | ||
| ariaLabel="Patient allergies" | ||
| emptyStateMessage="No allergies found" | ||
| rowClassNames={rowClassNames} | ||
| /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default AllergiesTable; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the need for useMemo here ? this is a simple constant with no calculation involved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you defined the headers array directly in the render function (i.e., without useMemo), a new array reference would be created on every render. Even though the contents are the same, React (or child components) may interpret the new reference as a change — especially if the child component (like ExpandableDataTable) is using React.memo() or does deep equality checks to avoid re-renders.