Skip to content

Commit 768737f

Browse files
authored
BN-75 | Add. Sort Based On Certainty For DiagnosesTable OnMount (#33)
* BN-75 | Fix. Change No Diagnoses i18n Translation * BN-75 | Add. Sort Diagnoses By Certainty On Mount In DiagnosesTable * BN-75 | Fix. Change Recorder i18n Translation In DiagnosesTable Recorder -> Recorder By
1 parent 6c1873f commit 768737f

File tree

7 files changed

+425
-11
lines changed

7 files changed

+425
-11
lines changed

public/locales/locale_en.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"DIAGNOSES_SELECT_CERTAINTY": "Select Certainty",
6565
"DIAGNOSIS_ALREADY_SELECTED": "(Already selected)",
6666
"DIAGNOSIS_LIST_DIAGNOSIS": "Diagnosis",
67-
"DIAGNOSIS_LIST_RECORDER": "Recorder",
67+
"DIAGNOSIS_LIST_RECORDED_BY": "Recorded By",
6868
"DIAGNOSIS_TABLE_NOT_AVAILABLE": "Not available",
6969
"DROPDOWN_VALUE_REQUIRED": "Please select a value",
7070
"ENCOUNTER_DATE": "Encounter Date",
@@ -124,7 +124,7 @@
124124
"LOCATION": "Location",
125125
"NETWORK_ERROR": "A network error occurred",
126126
"NO_ALLERGIES": "No Allergies recorded for this patient.",
127-
"NO_DIAGNOSES": "No diagnoses found for this patient",
127+
"NO_DIAGNOSES": "No diagnoses recorded",
128128
"NO_MATCHING_ALLERGEN_FOUND": "No matching allergen found",
129129
"NO_MATCHING_DIAGNOSIS_FOUND": "No matching diagnosis found.",
130130
"PARTICIPANT": "Participant(s)",

public/locales/locale_es.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"DIAGNOSES_SELECT_CERTAINTY": "Seleccionar Certeza",
6565
"DIAGNOSIS_ALREADY_SELECTED": "(Ya seleccionado)",
6666
"DIAGNOSIS_LIST_DIAGNOSIS": "Diagnóstico",
67-
"DIAGNOSIS_LIST_RECORDER": "Registrador",
67+
"DIAGNOSIS_LIST_RECORDED_BY": "Grabado por",
6868
"DIAGNOSIS_TABLE_NOT_AVAILABLE": "No disponible",
6969
"DROPDOWN_VALUE_REQUIRED": "Por favor seleccione un valor",
7070
"ENCOUNTER_DATE": "Fecha de Encuentro",
@@ -124,7 +124,7 @@
124124
"LOCATION": "Ubicación",
125125
"NETWORK_ERROR": "Se produjo un error de red",
126126
"NO_ALLERGIES": "No hay alergias registradas para este paciente",
127-
"NO_DIAGNOSES": "No se encontraron diagnósticos para este paciente",
127+
"NO_DIAGNOSES": "No hay diagnósticos registrados",
128128
"NO_MATCHING_ALLERGEN_FOUND": "No se encontró ningún alérgeno coincidente",
129129
"NO_MATCHING_DIAGNOSIS_FOUND": "No se encontraron diagnósticos coincidentes",
130130
"PARTICIPANT": "Partícipe(es)",

src/displayControls/diagnoses/DiagnosesTable.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useDiagnoses } from '@hooks/useDiagnoses';
66
import { FormattedDiagnosis } from '@types/diagnosis';
77
import { formatDate } from '@utils/date';
88
import { FULL_MONTH_DATE_FORMAT } from '@constants/date';
9+
import { sortDiagnosesByCertainty } from '@utils/diagnosis';
910
import * as styles from './styles/DiagnosesTable.module.scss';
1011

1112
/**
@@ -20,7 +21,7 @@ const DiagnosesTable: React.FC = () => {
2021
const headers = useMemo(
2122
() => [
2223
{ key: 'display', header: t('DIAGNOSIS_LIST_DIAGNOSIS') },
23-
{ key: 'recorder', header: t('DIAGNOSIS_LIST_RECORDER') },
24+
{ key: 'recorder', header: t('DIAGNOSIS_LIST_RECORDED_BY') },
2425
],
2526
[t],
2627
);
@@ -33,6 +34,14 @@ const DiagnosesTable: React.FC = () => {
3334
[],
3435
);
3536

37+
// Sort diagnoses within each date group by certainty: confirmed → provisional
38+
const sortedDiagnoses = useMemo(() => {
39+
return diagnoses.map((diagnosisByDate) => ({
40+
...diagnosisByDate,
41+
diagnoses: sortDiagnosesByCertainty(diagnosisByDate.diagnoses),
42+
}));
43+
}, [diagnoses]);
44+
3645
// Function to render cell content based on the cell ID
3746
const renderCell = (diagnosis: FormattedDiagnosis, cellId: string) => {
3847
switch (cellId) {
@@ -84,7 +93,7 @@ const DiagnosesTable: React.FC = () => {
8493
{!loading && !error && diagnoses.length === 0 && (
8594
<p className={styles.diagnosesTableBodyError}>{t('NO_DIAGNOSES')}</p>
8695
)}
87-
{diagnoses.map((diagnosisByDate, index) => {
96+
{sortedDiagnoses.map((diagnosisByDate, index) => {
8897
const { date, diagnoses: diagnosisList } = diagnosisByDate;
8998

9099
// Format the date for display

src/displayControls/diagnoses/__tests__/DiagnosesTable.integration.test.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,7 @@ describe('DiagnosesTable Integration', () => {
385385
expect(screen.getByText('January 31, 2024')).toBeInTheDocument();
386386

387387
// Verify empty state message
388-
expect(
389-
screen.getByText('No diagnoses found for this patient'),
390-
).toBeInTheDocument();
388+
expect(screen.getByText('No diagnoses recorded')).toBeInTheDocument();
391389

392390
// Verify the main component is still rendered
393391
expect(

src/displayControls/diagnoses/__tests__/DiagnosesTable.test.tsx

Lines changed: 222 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ describe('DiagnosesTable Component', () => {
357357
const headers = JSON.parse(headerElement.textContent || '[]');
358358
expect(headers).toEqual([
359359
{ key: 'display', header: 'Diagnosis' },
360-
{ key: 'recorder', header: 'Recorder' },
360+
{ key: 'recorder', header: 'Recorded By' },
361361
]);
362362
});
363363
});
@@ -406,7 +406,7 @@ describe('DiagnosesTable Component', () => {
406406
expect(loadingElements[index]).toHaveTextContent('false');
407407
expect(errorElements[index]).toHaveTextContent('null');
408408
expect(emptyMessageElements[index]).toHaveTextContent(
409-
'No diagnoses found for this patient',
409+
'No diagnoses recorded',
410410
);
411411
});
412412
});
@@ -656,6 +656,226 @@ describe('DiagnosesTable Component', () => {
656656
});
657657
});
658658

659+
describe('Diagnosis Sorting', () => {
660+
it('should sort diagnoses by certainty - confirmed before provisional', () => {
661+
const provisionalFirst: FormattedDiagnosis = {
662+
id: 'diagnosis-1',
663+
display: 'Provisional Diagnosis',
664+
certainty: { ...CERTAINITY_CONCEPTS[1], code: 'provisional' },
665+
recordedDate: '2024-01-15T10:30:00Z',
666+
recorder: 'Dr. Smith',
667+
};
668+
669+
const confirmedSecond: FormattedDiagnosis = {
670+
id: 'diagnosis-2',
671+
display: 'Confirmed Diagnosis',
672+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
673+
recordedDate: '2024-01-15T11:00:00Z',
674+
recorder: 'Dr. Johnson',
675+
};
676+
677+
const unsortedDiagnoses: DiagnosesByDate[] = [
678+
{
679+
date: '2024-01-15',
680+
diagnoses: [provisionalFirst, confirmedSecond], // Provisional first, should be reordered
681+
},
682+
];
683+
684+
mockUseDiagnoses.mockReturnValue({
685+
diagnoses: unsortedDiagnoses,
686+
loading: false,
687+
error: null,
688+
refetch: jest.fn(),
689+
});
690+
691+
render(<DiagnosesTable />);
692+
693+
const rowElements = screen.getAllByTestId('table-rows');
694+
const rows = JSON.parse(rowElements[0].textContent || '[]');
695+
696+
// After sorting, confirmed should come first
697+
expect(rows[0].certainty.code).toBe('confirmed');
698+
expect(rows[0].display).toBe('Confirmed Diagnosis');
699+
expect(rows[1].certainty.code).toBe('provisional');
700+
expect(rows[1].display).toBe('Provisional Diagnosis');
701+
});
702+
703+
it('should maintain stable sorting for same certainty level', () => {
704+
const firstConfirmed: FormattedDiagnosis = {
705+
id: 'diagnosis-1',
706+
display: 'First Confirmed',
707+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
708+
recordedDate: '2024-01-15T10:00:00Z',
709+
recorder: 'Dr. A',
710+
};
711+
712+
const secondConfirmed: FormattedDiagnosis = {
713+
id: 'diagnosis-2',
714+
display: 'Second Confirmed',
715+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
716+
recordedDate: '2024-01-15T11:00:00Z',
717+
recorder: 'Dr. B',
718+
};
719+
720+
const thirdConfirmed: FormattedDiagnosis = {
721+
id: 'diagnosis-3',
722+
display: 'Third Confirmed',
723+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
724+
recordedDate: '2024-01-15T12:00:00Z',
725+
recorder: 'Dr. C',
726+
};
727+
728+
const sameCertaintyDiagnoses: DiagnosesByDate[] = [
729+
{
730+
date: '2024-01-15',
731+
diagnoses: [firstConfirmed, secondConfirmed, thirdConfirmed],
732+
},
733+
];
734+
735+
mockUseDiagnoses.mockReturnValue({
736+
diagnoses: sameCertaintyDiagnoses,
737+
loading: false,
738+
error: null,
739+
refetch: jest.fn(),
740+
});
741+
742+
render(<DiagnosesTable />);
743+
744+
const rowElements = screen.getAllByTestId('table-rows');
745+
const rows = JSON.parse(rowElements[0].textContent || '[]');
746+
747+
// Order should be maintained
748+
expect(rows[0].id).toBe('diagnosis-1');
749+
expect(rows[1].id).toBe('diagnosis-2');
750+
expect(rows[2].id).toBe('diagnosis-3');
751+
});
752+
753+
it('should sort diagnoses within each date group independently', () => {
754+
const dateGroup1: DiagnosesByDate = {
755+
date: '2024-01-15',
756+
diagnoses: [
757+
{
758+
id: 'diagnosis-1',
759+
display: 'Group 1 Provisional',
760+
certainty: { ...CERTAINITY_CONCEPTS[1], code: 'provisional' },
761+
recordedDate: '2024-01-15T10:00:00Z',
762+
recorder: 'Dr. A',
763+
},
764+
{
765+
id: 'diagnosis-2',
766+
display: 'Group 1 Confirmed',
767+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
768+
recordedDate: '2024-01-15T11:00:00Z',
769+
recorder: 'Dr. B',
770+
},
771+
],
772+
};
773+
774+
const dateGroup2: DiagnosesByDate = {
775+
date: '2024-01-10',
776+
diagnoses: [
777+
{
778+
id: 'diagnosis-3',
779+
display: 'Group 2 Provisional',
780+
certainty: { ...CERTAINITY_CONCEPTS[1], code: 'provisional' },
781+
recordedDate: '2024-01-10T10:00:00Z',
782+
recorder: 'Dr. C',
783+
},
784+
{
785+
id: 'diagnosis-4',
786+
display: 'Group 2 Confirmed',
787+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
788+
recordedDate: '2024-01-10T11:00:00Z',
789+
recorder: 'Dr. D',
790+
},
791+
],
792+
};
793+
794+
mockUseDiagnoses.mockReturnValue({
795+
diagnoses: [dateGroup1, dateGroup2],
796+
loading: false,
797+
error: null,
798+
refetch: jest.fn(),
799+
});
800+
801+
render(<DiagnosesTable />);
802+
803+
const rowElements = screen.getAllByTestId('table-rows');
804+
805+
// First date group - confirmed should come first
806+
const group1Rows = JSON.parse(rowElements[0].textContent || '[]');
807+
expect(group1Rows[0].certainty.code).toBe('confirmed');
808+
expect(group1Rows[0].display).toBe('Group 1 Confirmed');
809+
expect(group1Rows[1].certainty.code).toBe('provisional');
810+
expect(group1Rows[1].display).toBe('Group 1 Provisional');
811+
812+
// Second date group - confirmed should come first
813+
const group2Rows = JSON.parse(rowElements[1].textContent || '[]');
814+
expect(group2Rows[0].certainty.code).toBe('confirmed');
815+
expect(group2Rows[0].display).toBe('Group 2 Confirmed');
816+
expect(group2Rows[1].certainty.code).toBe('provisional');
817+
expect(group2Rows[1].display).toBe('Group 2 Provisional');
818+
});
819+
820+
it('should handle unknown certainty codes by placing them last', () => {
821+
const confirmedDiagnosis: FormattedDiagnosis = {
822+
id: 'diagnosis-1',
823+
display: 'Confirmed Diagnosis',
824+
certainty: { ...CERTAINITY_CONCEPTS[0], code: 'confirmed' },
825+
recordedDate: '2024-01-15T10:00:00Z',
826+
recorder: 'Dr. A',
827+
};
828+
829+
const unknownDiagnosis: FormattedDiagnosis = {
830+
id: 'diagnosis-2',
831+
display: 'Unknown Diagnosis',
832+
certainty: {
833+
code: 'unknown',
834+
display: 'unknown',
835+
system: 'http://terminology.hl7.org/CodeSystem/condition-ver-status',
836+
},
837+
recordedDate: '2024-01-15T11:00:00Z',
838+
recorder: 'Dr. B',
839+
};
840+
841+
const provisionalDiagnosis: FormattedDiagnosis = {
842+
id: 'diagnosis-3',
843+
display: 'Provisional Diagnosis',
844+
certainty: { ...CERTAINITY_CONCEPTS[1], code: 'provisional' },
845+
recordedDate: '2024-01-15T12:00:00Z',
846+
recorder: 'Dr. C',
847+
};
848+
849+
const mixedCertaintyDiagnoses: DiagnosesByDate[] = [
850+
{
851+
date: '2024-01-15',
852+
diagnoses: [
853+
unknownDiagnosis,
854+
provisionalDiagnosis,
855+
confirmedDiagnosis,
856+
],
857+
},
858+
];
859+
860+
mockUseDiagnoses.mockReturnValue({
861+
diagnoses: mixedCertaintyDiagnoses,
862+
loading: false,
863+
error: null,
864+
refetch: jest.fn(),
865+
});
866+
867+
render(<DiagnosesTable />);
868+
869+
const rowElements = screen.getAllByTestId('table-rows');
870+
const rows = JSON.parse(rowElements[0].textContent || '[]');
871+
872+
// Order should be: confirmed, provisional, unknown
873+
expect(rows[0].certainty.code).toBe('confirmed');
874+
expect(rows[1].certainty.code).toBe('provisional');
875+
expect(rows[2].certainty.code).toBe('unknown');
876+
});
877+
});
878+
659879
describe('Hook Integration', () => {
660880
it('should call useDiagnoses hook', () => {
661881
mockUseDiagnoses.mockReturnValue({

0 commit comments

Comments
 (0)