1- import React , { useState } from 'react' ;
1+ import React , { useEffect , useMemo , useState } from 'react' ;
22import { Button , TextInput , InlineLoading , InlineNotification , Dropdown , Modal , ModalBody } from '@carbon/react' ;
3- import { showSnackbar , useSession } from '@openmrs/esm-framework' ;
3+ import { type PatientIdentifier , type PersonAttribute , showSnackbar , usePatient , useSession } from '@openmrs/esm-framework' ;
44import { useFormikContext } from 'formik' ;
55import styles from './client-registry-search.scss' ;
6- import { requestCustomOtp , validateCustomOtp , fetchClientRegistryData } from './client-registry.resource' ;
6+ import {
7+ requestCustomOtp ,
8+ validateCustomOtp ,
9+ fetchClientRegistryData ,
10+ fetchPatientAttributes ,
11+ fetchPatientIdentifiers ,
12+ } from './client-registry.resource' ;
713import NewClientTab from './new-client/new-client-tab.component' ;
814import ExistingClientTab from './existing-client/existing-client-tab.component' ;
9- import { type IdentifierType , type HieClient , IDENTIFIER_TYPES } from './types' ;
15+ import {
16+ type IdentifierType ,
17+ type HieClient ,
18+ IDENTIFIER_TYPES ,
19+ PersonAttributeTypeUuids ,
20+ HieIdentificationType ,
21+ IdentifierTypesUuids ,
22+ } from './types' ;
1023
1124export interface ClientRegistryLookupSectionProps {
1225 onClientVerified ?: ( ) => void ;
@@ -23,7 +36,7 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
2336} ) => {
2437 const { setFieldValue } = useFormikContext < any > ( ) ;
2538 const [ identifierType , setIdentifierType ] = useState < IdentifierType > ( 'National ID' ) ;
26- const [ identifierValue , setIdentifierValue ] = useState ( '' ) ;
39+ const [ identifierValue , setIdentifierValue ] = useState < string > ( '' ) ;
2740 const [ otp , setOtp ] = useState ( '' ) ;
2841 const [ otpSent , setOtpSent ] = useState ( false ) ;
2942 const [ otpVerified , setOtpVerified ] = useState < boolean > ( false ) ;
@@ -33,7 +46,22 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
3346 const [ error , setError ] = useState < string > ( '' ) ;
3447 const { sessionLocation } = useSession ( ) ;
3548 const [ client , setClient ] = useState < HieClient > ( ) ;
36- const locationUuid = sessionLocation ?. uuid ;
49+ const locationUuid = sessionLocation ?. uuid ?? '' ;
50+ const [ patientAttributes , setPatientAttributes ] = useState < PersonAttribute [ ] > ( [ ] ) ;
51+ const [ patientIdentifiers , setPatientIdentifiers ] = useState < PatientIdentifier [ ] > ( [ ] ) ;
52+ const { patient } = usePatient ( ) ;
53+
54+ useEffect ( ( ) => {
55+ if ( patient ) {
56+ getPatientAttributes ( patient . id ) ;
57+ getPatientIdentifiers ( patient . id ) ;
58+ }
59+ } , [ patient ] ) ;
60+
61+ const phoneNumber = useMemo (
62+ ( ) => getPatientAttribute ( patientAttributes , PersonAttributeTypeUuids . CONTACT_PHONE_NUMBER_UUID ) ,
63+ [ patientAttributes ] ,
64+ ) ;
3765
3866 async function withTimeout < T > ( promise : Promise < T > , ms = 10000 ) : Promise < T > {
3967 const controller = new AbortController ( ) ;
@@ -90,6 +118,10 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
90118 setError ( 'Please enter a valid ID value' ) ;
91119 return ;
92120 }
121+ if ( ! phoneNumber ) {
122+ setError ( 'No phone number set. Please add the phone number patient attribute' ) ;
123+ return ;
124+ }
93125
94126 setIsSendingOtp ( true ) ;
95127 setError ( '' ) ;
@@ -98,7 +130,8 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
98130 const payload = {
99131 identificationNumber : identifierValue ,
100132 identificationType : identifierType ,
101- locationUuid,
133+ phoneNumber : phoneNumber ? ( phoneNumber . value ?? '' ) : '' ,
134+ locationUuid : locationUuid ?? '' ,
102135 } ;
103136
104137 const response = await withTimeout ( requestCustomOtp ( payload ) ) ;
@@ -159,6 +192,57 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
159192 const registerOnAfyaYangu = ( ) => {
160193 window . open ( 'https://afyayangu.go.ke/' , '_blank' ) ;
161194 } ;
195+ async function getPatientAttributes ( patientUuid : string ) {
196+ const data = await fetchPatientAttributes ( patientUuid ) ;
197+ if ( data ) {
198+ setPatientAttributes ( data ) ;
199+ }
200+ }
201+ function getPatientAttribute ( patientAttributes : PersonAttribute [ ] , attributeTypeUuid : string ) {
202+ if ( ! patientAttributes || ! attributeTypeUuid ) {
203+ return null ;
204+ }
205+ return patientAttributes . find ( ( a ) => {
206+ return a . attributeType ?. uuid === attributeTypeUuid ;
207+ } ) ;
208+ }
209+ async function getPatientIdentifiers ( patientUuid : string ) {
210+ const data = await fetchPatientIdentifiers ( patientUuid ) ;
211+ if ( data ) {
212+ setPatientIdentifiers ( data ) ;
213+ }
214+ }
215+ function handleIdentifierChange ( value : { selectedItem : IdentifierType } ) {
216+ const selectedValue = value . selectedItem ;
217+ setIdentifierType ( selectedValue ) ;
218+ const identifier = getPatientIdentifier ( selectedValue ) ;
219+ setIdentifierValue ( identifier ?. identifier ?? '' ) ;
220+ }
221+ function getPatientIdentifier ( selectedIdentifierType : IdentifierType ) {
222+ let identifier : PatientIdentifier | undefined ;
223+ switch ( selectedIdentifierType ) {
224+ case HieIdentificationType . NationalID :
225+ identifier = getIdentifier ( patientIdentifiers , IdentifierTypesUuids . NATIONAL_ID_UUID ) ;
226+ break ;
227+ case HieIdentificationType . MandateNumber :
228+ identifier = getIdentifier ( patientIdentifiers , IdentifierTypesUuids . MANDATE_NUMBER_UUID ) ;
229+ break ;
230+ case HieIdentificationType . AlienID :
231+ identifier = getIdentifier ( patientIdentifiers , IdentifierTypesUuids . ALIEN_ID_UUID ) ;
232+ break ;
233+ case HieIdentificationType . RefugeeID :
234+ identifier = getIdentifier ( patientIdentifiers , IdentifierTypesUuids . REFUGEE_ID_UUID ) ;
235+ break ;
236+ default :
237+ identifier = getIdentifier ( patientIdentifiers , IdentifierTypesUuids . NATIONAL_ID_UUID ) ;
238+ }
239+ return identifier ;
240+ }
241+ function getIdentifier ( patientIdentifiers : PatientIdentifier [ ] , identifierTypeUuid : string ) {
242+ return patientIdentifiers . find ( ( i ) => {
243+ return i . identifierType ?. uuid === identifierTypeUuid ;
244+ } ) ;
245+ }
162246
163247 return (
164248 < Modal
@@ -189,20 +273,16 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
189273 label = "Identifier Type"
190274 titleText = "Select Identifier Type"
191275 items = { IDENTIFIER_TYPES }
192- selectedItem = { identifierType }
193- onChange = { ( { selectedItem } ) => setIdentifierType ( selectedItem as IdentifierType ) }
276+ onChange = { handleIdentifierChange }
194277 disabled = { otpSent }
195278 />
196279 </ div >
197-
198280 < div className = { styles . formControl } >
199281 < TextInput
200282 id = "identifier-value"
201283 labelText = { `${ identifierType } Value` }
202284 value = { identifierValue }
203- onChange = { ( e ) => setIdentifierValue ( e . target . value ) }
204- disabled = { otpSent }
205- placeholder = { `Enter ${ identifierType . toLowerCase ( ) } value` }
285+ readonly = { true }
206286 />
207287 </ div >
208288 </ div >
@@ -246,6 +326,11 @@ const ClientRegistryLookupSection: React.FC<ClientRegistryLookupSectionProps> =
246326 Back
247327 </ Button >
248328 </ div >
329+ < div className = { styles . actionBtn } >
330+ < Button kind = "primary" onClick = { ( ) => setOtpVerified ( true ) } >
331+ Skip OTP
332+ </ Button >
333+ </ div >
249334 </ div >
250335 </ >
251336 ) : (
0 commit comments