1- import React from 'react' ;
1+ import React , { useEffect } from 'react' ;
22import { useTranslation } from 'react-i18next' ;
33import ActionArea from '@components/common/actionArea/ActionArea' ;
4- import { useCurrentEncounter } from '@hooks/useCurrentEncounter' ;
5- import { useActivePractitioner } from '@hooks/useActivePractitioner' ;
6- import { useEncounterConcepts } from '@hooks/useEncounterConcepts' ;
7- import { useLocations } from '@hooks/useLocations' ;
8- import { Column , Grid , Loading , MenuItemDivider } from '@carbon/react' ;
9- import * as styles from './styles/ConsultationPad.module.scss' ;
4+ import { Column , Grid , MenuItemDivider } from '@carbon/react' ;
105import BasicForm from '@components/clinical/forms/basic/BasicForm' ;
116import DiagnosesForm from '@components/clinical/forms/diagnoses/DiagnosesForm' ;
127import AllergiesForm from '@components/clinical/forms/allergies/AllergiesForm' ;
13- import { Concept } from '@types/encounterConcepts' ;
148import { ConsultationBundle } from '@types/consultationBundle' ;
159import {
1610 postConsultationBundle ,
1711 createDiagnosisBundleEntries ,
1812 createAllergiesBundleEntries ,
1913} from '@services/consultationBundleService' ;
2014import useNotification from '@hooks/useNotification' ;
21- import { formatDate } from '@utils/date' ;
2215import { createEncounterResource } from '@utils/fhir/encounterResourceCreator' ;
2316import {
2417 createBundleEntry ,
@@ -27,16 +20,14 @@ import {
2720import { ERROR_TITLES } from '@constants/errors' ;
2821import { useDiagnosisStore } from '@stores/diagnosisStore' ;
2922import useAllergyStore from '@stores/allergyStore' ;
23+ import { useEncounterDetailsStore } from '@stores/encounterDetailsStore' ;
24+ import * as styles from './styles/ConsultationPad.module.scss' ;
3025
3126interface ConsultationPadProps {
32- patientUUID : string ;
3327 onClose : ( ) => void ;
3428}
3529
36- const ConsultationPad : React . FC < ConsultationPadProps > = ( {
37- patientUUID,
38- onClose,
39- } ) => {
30+ const ConsultationPad : React . FC < ConsultationPadProps > = ( { onClose } ) => {
4031 const [ isSubmitting , setIsSubmitting ] = React . useState ( false ) ;
4132
4233 const { t } = useTranslation ( ) ;
@@ -54,63 +45,55 @@ const ConsultationPad: React.FC<ConsultationPadProps> = ({
5445 validateAllAllergies,
5546 reset : resetAllergies ,
5647 } = useAllergyStore ( ) ;
57-
58- const {
59- locations,
60- loading : loadingLocations ,
61- error : errorLocations ,
62- } = useLocations ( ) ;
63- const {
64- encounterConcepts,
65- loading : loadingEncounterConcepts ,
66- error : errorEncounterConcepts ,
67- } = useEncounterConcepts ( ) ;
68-
48+ // Use the encounter details store
6949 const {
50+ activeVisit,
51+ selectedLocation,
52+ selectedEncounterType,
53+ encounterParticipants,
54+ consultationDate,
55+ isEncounterDetailsFormReady,
7056 practitioner,
7157 user,
72- loading : loadingPractitioner ,
73- error : errorPractitioner ,
74- } = useActivePractitioner ( ) ;
75-
76- const {
77- currentEncounter,
78- loading : loadingEncounter ,
79- error : errorEncounter ,
80- } = useCurrentEncounter ( patientUUID ) ;
81-
82- const encounterTypeSelected = encounterConcepts ?. encounterTypes . find (
83- ( item : Concept ) => item . name === 'Consultation' ,
84- ) ;
85-
86- const currentEncounterId = currentEncounter ?. type [ 0 ] ?. coding [ 0 ] ?. code || '' ;
87-
88- const visitTypeSelected = encounterConcepts ?. visitTypes . find (
89- ( item : Concept ) => item . uuid === currentEncounterId ,
90- ) ;
91-
92- const formattedDate = formatDate ( new Date ( ) ) ;
58+ patientUUID,
59+ hasError,
60+ reset : resetEncounterDetails ,
61+ } = useEncounterDetailsStore ( ) ;
62+
63+ // Clean up on unmount
64+ useEffect ( ( ) => {
65+ return ( ) => {
66+ resetEncounterDetails ( ) ;
67+ resetAllergies ( ) ;
68+ resetDiagnoses ( ) ;
69+ } ;
70+ } , [ resetEncounterDetails , resetAllergies , resetDiagnoses ] ) ;
9371
9472 // Data validation check for consultation submission
9573 const canSubmitConsultation = ! ! (
9674 patientUUID &&
9775 practitioner &&
9876 practitioner . uuid &&
99- currentEncounter &&
100- locations ?. length > 0 &&
101- encounterTypeSelected
77+ activeVisit &&
78+ selectedLocation &&
79+ selectedEncounterType &&
80+ encounterParticipants . length > 0
10281 ) ;
10382
83+ // TODO: Extract Business Logic
84+ // 1. Create a consultationService to handle submission logic
85+ // 2. Extract validation logic into a custom hook
86+ // 3. Create utility functions for bundle creation
10487 const submitConsultation = ( ) => {
10588 const enconterResourceURL = `urn:uuid:${ crypto . randomUUID ( ) } ` ;
10689 const encounterResource = createEncounterResource (
107- encounterTypeSelected ! . uuid ,
108- encounterTypeSelected ! . name ,
109- patientUUID ,
110- [ practitioner ! . uuid ] ,
111- currentEncounter ! . id ,
112- locations [ 0 ] . uuid ,
113- new Date ( ) ,
90+ selectedEncounterType ! . uuid ,
91+ selectedEncounterType ! . name ,
92+ patientUUID ! ,
93+ encounterParticipants . map ( ( p ) => p . uuid ) ,
94+ activeVisit ! . id ,
95+ selectedLocation ! . uuid ,
96+ consultationDate ,
11497 ) ;
11598 const encounterBundleEntry = createBundleEntry (
11699 enconterResourceURL ,
@@ -122,6 +105,7 @@ const ConsultationPad: React.FC<ConsultationPadProps> = ({
122105 encounterSubject : encounterResource . subject ! ,
123106 encounterReference : enconterResourceURL ,
124107 practitionerUUID : user ! . uuid ,
108+ consultationDate,
125109 } ) ;
126110
127111 const allergyEntries = createAllergiesBundleEntries ( {
@@ -154,6 +138,7 @@ const ConsultationPad: React.FC<ConsultationPadProps> = ({
154138 setIsSubmitting ( false ) ;
155139 resetDiagnoses ( ) ;
156140 resetAllergies ( ) ;
141+ resetEncounterDetails ( ) ;
157142 addNotification ( {
158143 title : t ( 'CONSULTATION_SUBMITTED_SUCCESS_TITLE' ) ,
159144 message : t ( 'CONSULTATION_SUBMITTED_SUCCESS_MESSAGE' ) ,
@@ -182,92 +167,50 @@ const ConsultationPad: React.FC<ConsultationPadProps> = ({
182167 onClose ( ) ;
183168 } ;
184169
185- if (
186- loadingEncounterConcepts ||
187- loadingLocations ||
188- loadingPractitioner ||
189- loadingEncounter ||
190- isSubmitting
191- ) {
192- return (
193- < ActionArea
194- title = { t ( 'CONSULTATION_PAD_TITLE' ) }
195- primaryButtonText = { t ( 'CONSULTATION_PAD_DONE_BUTTON' ) }
196- onPrimaryButtonClick = { handleOnPrimaryButtonClick }
197- secondaryButtonText = { t ( 'CONSULTATION_PAD_CANCEL_BUTTON' ) }
198- onSecondaryButtonClick = { handleOnSecondaryButtonClick }
199- content = {
200- < Grid >
201- < Column sm = { 3 } md = { 8 } lg = { 16 } className = { styles . loadingContent } >
202- < Loading
203- description = { t ( 'CONSULTATION_PAD_LOADING' ) }
204- withOverlay = { false }
205- />
206- </ Column >
207- </ Grid >
208- }
209- />
210- ) ;
211- }
212-
213- if (
214- errorLocations ||
215- errorEncounterConcepts ||
216- errorPractitioner ||
217- errorEncounter ||
218- ! practitioner ||
219- ! patientUUID ||
220- ! encounterConcepts ?. encounterTypes ||
221- ! encounterConcepts ?. visitTypes ||
222- ! currentEncounter ||
223- ! visitTypeSelected ||
224- ! encounterTypeSelected ||
225- ! locations ||
226- locations . length === 0 ||
227- formattedDate . error
228- ) {
229- return (
230- < ActionArea
231- title = { t ( 'CONSULTATION_PAD_TITLE' ) }
232- primaryButtonText = { t ( 'CONSULTATION_PAD_DONE_BUTTON' ) }
233- onPrimaryButtonClick = { handleOnPrimaryButtonClick }
234- secondaryButtonText = { t ( 'CONSULTATION_PAD_CANCEL_BUTTON' ) }
235- onSecondaryButtonClick = { handleOnSecondaryButtonClick }
236- content = {
237- < Grid >
238- < Column sm = { 4 } md = { 8 } lg = { 16 } >
239- < h2 > { t ( 'CONSULTATION_PAD_ERROR' ) } </ h2 >
240- </ Column >
241- </ Grid >
242- }
243- />
244- ) ;
245- }
246-
247170 return (
248171 < ActionArea
249- title = { t ( 'CONSULTATION_PAD_TITLE' ) }
172+ title = { hasError ? '' : t ( 'CONSULTATION_PAD_TITLE' ) }
250173 primaryButtonText = { t ( 'CONSULTATION_PAD_DONE_BUTTON' ) }
251174 onPrimaryButtonClick = { handleOnPrimaryButtonClick }
175+ isPrimaryButtonDisabled = {
176+ ! isEncounterDetailsFormReady || ! canSubmitConsultation || isSubmitting
177+ }
252178 secondaryButtonText = { t ( 'CONSULTATION_PAD_CANCEL_BUTTON' ) }
253179 onSecondaryButtonClick = { handleOnSecondaryButtonClick }
254180 content = {
255- < >
256- < BasicForm
257- practitioner = { practitioner }
258- encounterTypes = { encounterConcepts . encounterTypes }
259- encounterTypeSelected = { encounterTypeSelected }
260- visitTypes = { encounterConcepts . visitTypes }
261- visitTypeSelected = { visitTypeSelected }
262- location = { locations [ 0 ] }
263- locationSelected = { locations [ 0 ] }
264- defaultDate = { formattedDate . formattedResult }
265- />
266- < DiagnosesForm />
267- < MenuItemDivider />
268- < AllergiesForm />
269- < MenuItemDivider />
270- </ >
181+ hasError ? (
182+ < >
183+ < Grid className = { styles . emptyState } >
184+ < Column
185+ sm = { 4 }
186+ md = { 8 }
187+ lg = { 16 }
188+ xlg = { 16 }
189+ className = { styles . emptyStateTitle }
190+ >
191+ { t ( 'CONSULTATION_PAD_ERROR_TITLE' ) }
192+ </ Column >
193+ < Column
194+ sm = { 4 }
195+ md = { 8 }
196+ lg = { 16 }
197+ xlg = { 16 }
198+ className = { styles . emptyStateBody }
199+ >
200+ { t ( 'CONSULTATION_PAD_ERROR_BODY' ) }
201+ </ Column >
202+ </ Grid >
203+ </ >
204+ ) : (
205+ < >
206+ < BasicForm />
207+ < MenuItemDivider />
208+ < DiagnosesForm />
209+ < MenuItemDivider />
210+ < AllergiesForm />
211+ < MenuItemDivider />
212+ </ >
213+ )
271214 }
272215 />
273216 ) ;
0 commit comments