11import React , { useCallback , useState } from "react" ;
22import {
33 Button ,
4- ContentSwitcher ,
4+ Dropdown ,
55 Form ,
6- Hospital ,
76 Layer ,
87 ModalHeader ,
98 ModalBody ,
109 ModalFooter ,
1110 Select ,
1211 SelectItem ,
12+ showSnackbar ,
1313 Stack ,
14- Switch ,
15- TaskLocation ,
1614 InlineNotification ,
1715 InlineLoading ,
1816} from "@carbon/react" ;
1917import {
2018 DefaultWorkspaceProps ,
21- showSnackbar ,
2219 useLayoutType ,
2320 useSession ,
2421} from "@openmrs/esm-framework" ;
@@ -27,7 +24,14 @@ import styles from "./change-location-link.scss";
2724import { useTranslation } from "react-i18next" ;
2825import { zodResolver } from "@hookform/resolvers/zod" ;
2926import z from "zod" ;
30- import { Provider , saveProvider , useClinicLocations , useRoomLocations } from "./change-location.resource" ;
27+ import {
28+ getProvider ,
29+ Provider ,
30+ saveProvider ,
31+ useRoomLocations ,
32+ } from "./change-location.resource" ;
33+ import { DEFAULT_LOCATION_ATTRIBUTE_TYPE_UUID , locationChangerList } from "../constants" ;
34+ import { LocationOption } from "../types" ;
3135
3236type ChangeLocationProps = DefaultWorkspaceProps ;
3337
@@ -36,21 +40,24 @@ const ChangeLocationModal: React.FC<ChangeLocationProps> = ({
3640} ) => {
3741 const { t } = useTranslation ( ) ;
3842 const isTablet = useLayoutType ( ) === "tablet" ;
39- const [ tabType , setTabType ] = useState ( "Change room" ) ;
4043 const session = useSession ( ) ;
44+ const sessionUser = useSession ( ) ;
4145 const currentLocation = session ?. sessionLocation ?. uuid ;
46+ const locationList = locationChangerList . map ( ( item ) => ( {
47+ id : item . id ,
48+ label : item . label ,
49+ } ) ) ;
50+ const [ selectedLocationOption , setSelectedLocationOption ] = useState < LocationOption | undefined > ( ) ;
4251 const [ isChangingRoom , setIsChangingRoom ] = useState ( false ) ;
43- const [ selectedClinicRoom , setselectedClinicRoom ] = useState < string | undefined > ( ) ;
52+ const [ selectedClinicRoom , setselectedClinicRoom ] = useState <
53+ string | undefined
54+ > ( ) ;
4455 const [ selectedClinic , setSelectedClinic ] = useState < string | undefined > ( ) ;
45- const { roomLocations, error : errorFetchingRooms } = useRoomLocations ( selectedClinic ) ;
46- const { clinicsList, error : errorFetchingClinics } = useClinicLocations ( ) ;
47-
48- const handleTabTypeChange = ( { name } ) => {
49- setTabType ( name ) ;
50- } ;
56+ const { roomLocations, error : errorFetchingRooms } =
57+ useRoomLocations ( sessionUser ?. sessionLocation ?. uuid ) ;
5158
5259 const changeLocationSchema = z . object ( {
53- clinicRoom : z . string ( ) . optional ( ) ,
60+ clinicRoom : z . string ( ) . min ( 1 , "Room is required" ) ,
5461 } ) ;
5562
5663 const {
@@ -61,104 +68,99 @@ const ChangeLocationModal: React.FC<ChangeLocationProps> = ({
6168 resolver : zodResolver ( changeLocationSchema ) ,
6269 } ) ;
6370
64- const onSubmit : SubmitHandler < any > = useCallback (
71+ const onSubmit : SubmitHandler < z . infer < typeof changeLocationSchema > > = useCallback (
6572 ( data ) => {
6673 setIsChangingRoom ( true ) ;
6774
68- const newLocationUuid = data . clinicRoom ?? data . clinic ;
69- const providerUuid = session ?. currentProvider ?. uuid ;
70- const personUuid = session ?. user ?. person ?. uuid ;
75+ const userUuid = sessionUser ?. user ?. uuid ;
76+ const roomUuid = data . clinicRoom ;
77+
78+ if ( ! userUuid || ! roomUuid ) return ;
79+
80+ getProvider ( userUuid )
81+ . then ( ( response ) => {
82+ const provider = response ?. data ?. results ?. [ 0 ] ;
83+ const providerUuid = provider ?. uuid ;
84+
85+ if ( ! providerUuid ) throw new Error ( "Provider not found" ) ;
7186
72- const payload : Provider = {
73- uuid : providerUuid ,
74- person : { uuid : personUuid } ,
75- attributes : [
76- {
77- attributeType : {
78- uuid : "13a721e4-68e5-4f7a-8aee-3cbcec127179" ,
79- display : "Default Location" ,
80- } ,
81- value : {
82- uuid : newLocationUuid ,
83- display : roomLocations . find ( loc => loc . uuid === newLocationUuid ) ?. display || "Selected Location"
84- }
85- }
86- ] ,
87- } ;
87+ // find the existing location attribute (if any)
88+ const existingLocationAttr = provider . attributes ?. find (
89+ ( attr ) => attr . attributeType ?. uuid === DEFAULT_LOCATION_ATTRIBUTE_TYPE_UUID
90+ ) ;
8891
89- saveProvider ( payload )
90- . then ( ( ) => {
91- closeWorkspace ( ) ;
92- showSnackbar ( {
93- title : t ( "locationChanged" , "Default location updated" ) ,
94- kind : "success" ,
95- } ) ;
96- } )
97- . catch ( ( error ) => {
98- const errorMessage =
99- error ?. responseBody ?. message || error ?. message || "An unexpected error occurred" ;
100- console . error ( "Provider update failed:" , errorMessage ) ;
101- } )
102- . finally ( ( ) => {
103- setIsChangingRoom ( false ) ;
104- } ) ;
92+ // keep all other attributes
93+ const otherAttributes = provider . attributes ?. filter (
94+ ( attr ) => attr . attributeType ?. uuid !== DEFAULT_LOCATION_ATTRIBUTE_TYPE_UUID
95+ ) ?? [ ] ;
96+
97+ // include the updated one with its UUID (if it exists)
98+ const updatedAttributes = [
99+ ...otherAttributes ,
100+ {
101+ ...( existingLocationAttr ?. uuid && { uuid : existingLocationAttr . uuid } ) ,
102+ attributeType : { uuid : DEFAULT_LOCATION_ATTRIBUTE_TYPE_UUID } ,
103+ value : roomUuid , // ✅ plain string
104+ }
105+ ] ;
106+
107+
108+
109+
110+ return saveProvider ( providerUuid , updatedAttributes ) ;
111+ } )
112+ . then ( ( ) => {
113+ close ( ) ;
114+ showSnackbar ( {
115+ title : t ( "locationChangedSuccessfully" , "Location changed successfully" ) ,
116+ kind : "success" ,
117+ } ) ;
118+ } )
119+ . catch ( ( error ) => {
120+ const errorMessage = error ?. responseBody ?. message ?? error ?. message ;
121+ showSnackbar ( {
122+ title : t ( "locationChangeFailed" , "Location change failed" ) ,
123+ subtitle : errorMessage ,
124+ kind : "error" ,
125+ } ) ;
126+ } )
127+ . finally ( ( ) => {
128+ setIsChangingRoom ( false ) ;
129+ } ) ;
105130 } ,
106- [ session , closeWorkspace , t , roomLocations ]
131+ [ sessionUser ?. user ?. uuid , close , t ]
107132) ;
108133
109134
135+
136+ const onError = ( ) => setIsChangingRoom ( false ) ;
137+
138+
110139 return (
111- < Form onSubmit = { handleSubmit ( onSubmit ) } >
140+ < Form onSubmit = { handleSubmit ( onSubmit , onError ) } >
112141 < ModalHeader
113142 closeModal = { close }
114143 title = { t ( "changeLocation" , "Change location" ) }
115144 />
116145 < ModalBody >
117-
118- < ContentSwitcher onChange = { handleTabTypeChange } >
119- < Switch name = "Change room" text = { t ( "changeRoom" , "Switch room" ) } />
120- < Switch name = "Change clinic" text = { t ( "changeClinic" , "Switch only clinic" ) } />
121- </ ContentSwitcher >
122-
123146 < Stack gap = { 5 } className = { styles . languageOptionsContainer } >
124147 < ResponsiveWrapper isTablet = { isTablet } >
125- { tabType === "Change room" && (
126- < > < Controller
127- name = "clinicLocation"
128- control = { control }
129- defaultValue = ""
130- render = { ( { field } ) => (
131- < Select
132- { ...field }
133- id = "clinicLocation"
134- name = "clinicLocation"
135- labelText = "Select clinic"
136- disabled = { errorFetchingClinics }
137- invalidText = { errors . root ?. message }
138- value = { field . value }
139- onChange = { ( e ) => {
140- const selectedValue = e . target . value ;
141- field . onChange ( selectedValue ) ;
142- setSelectedClinic ( selectedValue ) ;
143- } }
144- >
145- { ! field . value && (
146- < SelectItem
147- value = ""
148- text = { t (
149- "selectClinic" ,
150- "Choose clinic"
151- ) }
152- />
153- ) }
154-
155- { clinicsList . map ( ( { uuid, display } ) => (
156- < SelectItem key = { uuid } value = { uuid } text = { display } />
157- ) ) }
158- </ Select >
148+ < Dropdown
149+ id = "location-options"
150+ titleText = { t (
151+ "locationChangerOptions" ,
152+ "Select location change option"
159153 ) }
154+ itemToString = { ( item ) => ( item ? item . label : "" ) }
155+ items = { locationList }
156+ label = "Choose option"
157+ selectedItem = { selectedLocationOption }
158+ onChange = { ( event ) =>
159+ setSelectedLocationOption ( event . selectedItem )
160+ }
160161 />
161- < Controller
162+ { selectedLocationOption ?. id === "switchRoom" && (
163+ < Controller
162164 name = "clinicRoom"
163165 control = { control }
164166 defaultValue = { currentLocation }
@@ -168,7 +170,7 @@ const onSubmit: SubmitHandler<any> = useCallback(
168170 id = "clinicRoom"
169171 name = "clinicRoom"
170172 labelText = "Select room to change to"
171- disabled = { ! selectedClinic || errorFetchingRooms }
173+ disabled = { errorFetchingRooms }
172174 invalidText = { errors . locationTo ?. message }
173175 value = { field . value }
174176 onChange = { ( e ) => {
@@ -180,10 +182,7 @@ const onSubmit: SubmitHandler<any> = useCallback(
180182 { ! field . value && (
181183 < SelectItem
182184 value = ""
183- text = { t (
184- "selectRoom" ,
185- "Choose room"
186- ) }
185+ text = { t ( "selectRoom" , "Choose room" ) }
187186 />
188187 ) }
189188
@@ -192,20 +191,19 @@ const onSubmit: SubmitHandler<any> = useCallback(
192191 ) ) }
193192 </ Select >
194193 ) }
195- /> </ >
196- ) }
197- { tabType === "Change clinic" && (
194+ /> ) }
195+ { selectedLocationOption ?. id === "" && (
198196 < Controller
199- name = "clinic "
197+ name = "clinicLocation "
200198 control = { control }
201- defaultValue = { currentLocation }
199+ defaultValue = ""
202200 render = { ( { field } ) => (
203201 < Select
204202 { ...field }
205- id = "clinic "
206- name = "clinic "
207- labelText = "Select clinic to change to "
208- disabled = { errorFetchingClinics }
203+ id = "clinicLocation "
204+ name = "clinicLocation "
205+ labelText = "Select clinic"
206+ // disabled={errorFetchingClinics}
209207 invalidText = { errors . root ?. message }
210208 value = { field . value }
211209 onChange = { ( e ) => {
@@ -217,16 +215,13 @@ const onSubmit: SubmitHandler<any> = useCallback(
217215 { ! field . value && (
218216 < SelectItem
219217 value = ""
220- text = { t (
221- "selectClinic" ,
222- "Choose clinic"
223- ) }
218+ text = { t ( "selectClinic" , "Choose clinic" ) }
224219 />
225220 ) }
226221
227- { clinicsList . map ( ( { uuid, display } ) => (
222+ { /* { clinicsList.map(({ uuid, display }) => (
228223 <SelectItem key={uuid} value={uuid} text={display} />
229- ) ) }
224+ ))} */ }
230225 </ Select >
231226 ) }
232227 /> ) }
0 commit comments