ui-soxo-bootstrap-core 2.4.24 → 2.4.25-dev.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.github/workflows/npm-publish.yml +37 -15
  2. package/core/components/extra-info/extra-info-details.js +109 -126
  3. package/core/components/landing-api/landing-api.js +22 -30
  4. package/core/lib/Store.js +20 -18
  5. package/core/lib/components/index.js +4 -1
  6. package/core/lib/components/sidemenu/sidemenu.js +153 -256
  7. package/core/lib/components/sidemenu/sidemenu.scss +39 -26
  8. package/core/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +119 -42
  9. package/core/lib/elements/basic/rangepicker/rangepicker.js +118 -29
  10. package/core/lib/elements/basic/switch/switch.js +35 -25
  11. package/core/lib/hooks/index.js +2 -12
  12. package/core/lib/hooks/use-otp-timer.js +99 -0
  13. package/core/lib/pages/login/login.js +255 -139
  14. package/core/lib/pages/login/login.scss +140 -32
  15. package/core/models/dashboard/dashboard.js +14 -0
  16. package/core/models/doctor/components/doctor-add/doctor-add.js +403 -0
  17. package/core/models/doctor/components/doctor-add/doctor-add.scss +32 -0
  18. package/core/models/menus/components/menu-add/menu-add.js +220 -267
  19. package/core/models/menus/components/menu-lists/menu-lists.js +366 -211
  20. package/core/models/menus/components/menu-lists/menu-lists.scss +6 -2
  21. package/core/models/menus/menus.js +256 -267
  22. package/core/models/roles/components/role-add/role-add.js +265 -228
  23. package/core/models/roles/components/role-list/role-list.js +326 -348
  24. package/core/models/roles/roles.js +191 -174
  25. package/core/models/staff/components/staff-add/staff-add.js +352 -0
  26. package/core/models/staff/components/staff-add/staff-add.scss +0 -0
  27. package/core/models/users/components/user-add/user-add.js +723 -367
  28. package/core/models/users/components/user-add/user-edit.js +90 -0
  29. package/core/models/users/users.js +318 -165
  30. package/core/modules/index.js +5 -8
  31. package/core/modules/reporting/components/index.js +5 -0
  32. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +65 -2
  33. package/core/modules/steps/action-buttons.js +79 -0
  34. package/core/modules/steps/steps.js +553 -0
  35. package/core/modules/steps/steps.scss +158 -0
  36. package/core/modules/steps/timeline.js +49 -0
  37. package/package.json +2 -2
@@ -2,360 +2,693 @@ import React, { useState, useEffect, useContext } from 'react';
2
2
 
3
3
  import { useLocation } from 'react-router-dom';
4
4
 
5
- import { Skeleton, Typography, message, Switch, Form, Input, Select, Checkbox } from 'antd';
6
-
5
+ import { Skeleton, Typography, message, Switch, Form, Input, Select, Checkbox, Row, Col } from 'antd';
7
6
 
8
7
  import AsyncSelect from 'react-select/async';
9
8
 
10
9
  import { Table, Card, Button, JSONInput, GlobalContext } from './../../../../lib/';
11
10
 
12
- import { ModelsAPI, PagesAPI } from '../../..';
11
+ import { ModelsAPI, PagesAPI, RolesAPI } from '../../..';
13
12
 
14
13
  import { UsersAPI } from '../../..';
14
+ import DoctorAdd from '../../../doctor/components/doctor-add/doctor-add';
15
+ import StaffAdd from '../../../staff/components/staff-add/staff-add';
15
16
 
16
17
  const { Title } = Typography;
17
18
 
18
19
  const { Option } = Select;
19
20
 
20
- const UserAdd = ({ model, callback, edit, history, formContent, match, additional_queries, props }) => {
21
-
22
- /**Getting user data */
23
- const { user = {} } = useContext(GlobalContext);
24
- let mode = 'Add';
25
-
26
- const [disabled, setDisabled] = useState(true);
27
-
28
- const [selectedOption, setSelectedOption] = useState(null);
29
-
30
- //Need to check this condition
31
- const [authentication, setAuthentication] = useState(false);
32
-
33
- /**To store user values */
34
- const [users, setUsers] = useState([]);
35
-
36
- /**Converting to JSON */
37
- let firmDetails = JSON.parse(user.firm.f_otherdetails1);
38
-
39
- /**Variable for cheaking mandatory condition of mobile*/
40
- let mobileRequired;
41
-
42
- /**If mode is mobile and fa is 'MND' or 'USR' then mobile is mandatory */
43
- if ((firmDetails && firmDetails.FA === 'MND' || firmDetails && firmDetails.FA === 'USR') && (firmDetails.mode === 'mobile')) {
44
-
45
- mobileRequired = true
46
-
47
- } else {
48
-
49
- mobileRequired = false
50
- }
51
-
52
- if (formContent.id) {
53
- mode = 'Edit'
54
- } else if (formContent.copy) {
55
- mode = 'Copy'
56
- }
57
-
58
- if (formContent.attributes) {
59
-
60
- if (typeof formContent.attributes === 'string') {
61
-
62
- if (formContent.attributes !== '') {
63
-
64
- formContent.attributes = JSON.parse(formContent.attributes);
65
-
66
- } else {
67
-
68
- formContent.attributes = {};
69
-
70
- }
21
+ const UserAdd = ({ model, callback, edit, history, formContent, match, additional_queries, props, mode = 'Add', attributes }) => {
22
+ /**Getting user data */
23
+ const { user = {} } = useContext(GlobalContext);
24
+ // let mode = 'Add';
25
+
26
+ const [disabled, setDisabled] = useState(true);
27
+
28
+ const [selectedOption, setSelectedOption] = useState(null);
29
+ // for selected branches
30
+ const [selectedBranches, setSelectedBranches] = useState([]);
31
+
32
+ // for default branch
33
+ const [defaultBranch, setDefaultBranch] = useState(null);
34
+ //Need to check this condition
35
+ const [authentication, setAuthentication] = useState(false);
36
+
37
+ /**To store user values */
38
+ const [users, setUsers] = useState([]);
39
+ const [doctorID, setDoctorID] = useState(false);
40
+ const [selectedDoctor, setSelectedDoctor] = useState(null);
41
+ const [staffID, setStaffID] = useState(false);
42
+ const [selectedStaff, setSelectedStaff] = useState(null);
43
+ const [staffList, setStaffList] = useState([]);
44
+ /**Converting to JSON */
45
+ let firmDetails = JSON.parse(user.firm.f_otherdetails1);
46
+
47
+ /**Variable for cheaking mandatory condition of mobile*/
48
+ let mobileRequired;
49
+
50
+ /**If mode is mobile and fa is 'MND' or 'USR' then mobile is mandatory */
51
+ if (((firmDetails && firmDetails.FA === 'MND') || (firmDetails && firmDetails.FA === 'USR')) && firmDetails.mode === 'mobile') {
52
+ mobileRequired = true;
53
+ } else {
54
+ mobileRequired = false;
55
+ }
56
+
57
+ if (formContent?.id) {
58
+ mode = 'Edit';
59
+ } else if (formContent?.copy) {
60
+ mode = 'Copy';
61
+ }
62
+
63
+ if (formContent?.attributes) {
64
+ if (typeof formContent.attributes === 'string') {
65
+ if (formContent.attributes !== '') {
66
+ formContent.attributes = JSON.parse(formContent.attributes);
67
+ } else {
68
+ if (formContent) {
69
+ formContent.attributes = {};
71
70
  }
72
- } else {
73
- formContent.attributes = {}
71
+ }
74
72
  }
75
-
76
- const [loading, setLoading] = useState(true);
77
-
78
- const [form] = Form.useForm();
79
-
80
- const [body, setBody] = useState(formContent);
81
-
82
- const [isPasswordVisible, setIsPasswordVisible] = useState(false);
83
-
84
- const formData = {
85
- ...body,
86
- /**If panel is open then takes password in body */
87
- password: !isPasswordVisible ? "" : body.password
73
+ } else {
74
+ if (formContent) {
75
+ formContent.attributes = {};
88
76
  }
89
-
90
-
91
- let passwordRegex
92
- let passwordRegexMessage
93
-
94
- if (props && props?.passwordRegex && props?.passwordRegexMessage) {
95
- passwordRegex = props.passwordRegex
96
- passwordRegexMessage = props.passwordRegexMessage
97
- } else if (process.env.REACT_APP_PASSWORD_REGEX && process.env.REACT_APP_PASSWORD_REGEX_MESSAGE) {
98
- passwordRegex = process.env.REACT_APP_PASSWORD_REGEX
99
- passwordRegexMessage = process.env.REACT_APP_PASSWORD_REGEX_MESSAGE
100
- } else {
101
- passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>])[A-Za-z\d!@#$%^&*(),.?":{}|<>]{8,}$/
102
- passwordRegexMessage = "Password must be at least 8 characters long and contain atleast one uppercase letter, one lowercase letter, one digit and one special character"
77
+ }
78
+
79
+ const [loading, setLoading] = useState(true);
80
+ // user type state
81
+ const [userType, setUserType] = useState('general');
82
+ // state for branches list
83
+ const [branches, setBranches] = useState([]);
84
+ // designation list state
85
+ const [designations, setDesignations] = useState([]);
86
+ // department list state
87
+ const [departments, setDepartments] = useState([]);
88
+ // doctor list state
89
+ const [doctorList, setDoctorList] = useState([]);
90
+ // for role list
91
+ const [roles, setRoles] = useState([]);
92
+
93
+ const [form] = Form.useForm();
94
+
95
+ const [body, setBody] = useState(formContent);
96
+
97
+ const [isPasswordVisible, setIsPasswordVisible] = useState(false);
98
+ const [visible, setVisible] = useState(false);
99
+
100
+ const formData = {
101
+ ...body,
102
+ /**If panel is open then takes password in body */
103
+ password: !isPasswordVisible ? '' : body.password,
104
+ };
105
+
106
+ let passwordRegex;
107
+ let passwordRegexMessage;
108
+
109
+ if (props && props?.passwordRegex && props?.passwordRegexMessage) {
110
+ passwordRegex = props.passwordRegex;
111
+ passwordRegexMessage = props.passwordRegexMessage;
112
+ } else if (process.env.REACT_APP_PASSWORD_REGEX && process.env.REACT_APP_PASSWORD_REGEX_MESSAGE) {
113
+ passwordRegex = process.env.REACT_APP_PASSWORD_REGEX;
114
+ passwordRegexMessage = process.env.REACT_APP_PASSWORD_REGEX_MESSAGE;
115
+ } else {
116
+ passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>])[A-Za-z\d!@#$%^&*(),.?":{}|<>]{8,}$/;
117
+ passwordRegexMessage =
118
+ 'Password must be at least 8 characters long and contain atleast one uppercase letter, one lowercase letter, one digit and one special character';
119
+ }
120
+
121
+ useEffect(() => {
122
+ if (!loading && formContent) {
123
+ form.resetFields(); // clear previous values
124
+ form.setFieldsValue(formContent);
103
125
  }
126
+ }, [loading, formContent]);
127
+
128
+ useEffect(() => {
129
+ if (formContent?.auth_user) {
130
+ setSelectedOption({
131
+ value: formContent.auth_user,
132
+ label: formContent.auth_user, // Add a helper function to capitalize
133
+ });
134
+ }
135
+ }, [formContent?.auth_user]);
104
136
 
137
+ useEffect(() => {
138
+ loadUsers();
105
139
 
140
+ setLoading(false);
106
141
 
142
+ if (firmDetails) {
143
+ /**if firmmas.otherdetails - 2FA == MND, then, 2FA option will be enabled by default and read-only */
144
+ if (firmDetails.FA == 'MND') {
145
+ setAuthentication(true);
107
146
 
108
- useEffect(() => {
109
- if (formContent.auth_user) {
110
- setSelectedOption({
111
- value: formContent.auth_user,
112
- label: formContent.auth_user, // Add a helper function to capitalize
113
- });
114
- }
115
- }, [formContent.auth_user]);
116
-
117
-
118
- useEffect(() => {
119
-
120
- loadUsers()
121
- setLoading(false);
122
-
123
- if (firmDetails) {
124
-
125
- /**if firmmas.otherdetails - 2FA == MND, then, 2FA option will be enabled by default and read-only */
126
- if (firmDetails.FA == 'MND') {
127
-
128
- setAuthentication(true)
129
-
130
- setDisabled(true)
131
-
132
- /**if firmmas.otherdetails - 2FA == OPT, then, 2FA option will be enabled by default and editable */
133
- } else if (firmDetails.FA == 'USR') {
134
-
135
- setAuthentication(true)
136
-
137
- setDisabled(true)
138
-
139
- /**if firmmas.otherdetails - 2FA == NAP, then, 2FA option will be disabled by default and read-only*/
140
- } else if (firmDetails.FA == 'NAP') {
141
-
142
- setAuthentication(false)
143
-
144
- setDisabled(true)
145
- }
146
-
147
- }
147
+ setDisabled(true);
148
148
 
149
+ /**if firmmas.otherdetails - 2FA == OPT, then, 2FA option will be enabled by default and editable */
150
+ } else if (firmDetails.FA == 'USR') {
151
+ setAuthentication(true);
149
152
 
150
- }, []);
153
+ setDisabled(true);
151
154
 
152
- /**
153
- * Submit values
154
- */
155
- const onSubmit = (values) => {
155
+ /**if firmmas.otherdetails - 2FA == NAP, then, 2FA option will be disabled by default and read-only*/
156
+ } else if (firmDetails.FA == 'NAP') {
157
+ setAuthentication(false);
156
158
 
157
- /**If PanelOpen is open and edit mode then password will be existing password else new password*/
158
- if (!isPasswordVisible && mode === 'Edit') {
159
- values.password = body.password;
159
+ setDisabled(true);
160
+ }
161
+ }
162
+ }, []);
163
+ /**
164
+ *Define the options dynamically
165
+ */
166
+ const getUserTypeOptions = () => [
167
+ { label: 'General', value: 'GEN' },
168
+ { label: 'Doctor', value: 'RAD' },
169
+ { label: 'Radiographer', value: 'TECH' },
170
+ { label: 'Staff', value: 'STAFF' },
171
+ ];
172
+
173
+ /**
174
+ * Get Branch List
175
+ */
176
+ const getBranches = () => {
177
+ setLoading(true);
178
+ UsersAPI.getBranches().then(async (result) => {
179
+ const details = await result.result.map((ele) => {
180
+ return {
181
+ ...ele,
182
+ ...(ele.br_otherdet1 ? JSON.parse(ele.br_otherdet1) : {}),
183
+ };
184
+ });
185
+ setBranches(details);
186
+ setLoading(false);
187
+ });
188
+ };
189
+
190
+ /** Get Designation List */
191
+ const getDesignations = () => {
192
+ setLoading(true);
193
+ UsersAPI.getDesignations()
194
+ .then((result) => {
195
+ if (result?.success && Array.isArray(result.result)) {
196
+ const details = result.result.map((ele) => ({
197
+ label: ele.dg_desc?.trim() || '',
198
+ value: ele.dg_code,
199
+ }));
200
+ setDesignations(details);
201
+ } else {
202
+ setDesignations([]);
160
203
  }
161
-
162
- values = {
163
- ...values,
164
- auth_type: 'LDAP',
165
- FA: authentication
204
+ })
205
+ .catch((error) => {
206
+ console.error('Error fetching designations:', error);
207
+ setDesignations([]);
208
+ })
209
+ .finally(() => setLoading(false));
210
+ };
211
+
212
+ /**
213
+ * get role lists
214
+ */
215
+ function getRoles() {
216
+ RolesAPI.getRole()
217
+ .then((res) => {
218
+ // if API returns { statusCode: 200, result: [...] }
219
+ if (Array.isArray(res.result)) {
220
+ setRoles(res.result.filter((r) => r.active === 'Y')); // optional: only active roles
221
+ } else {
222
+ setRoles([]);
166
223
  }
167
-
168
- setLoading(true);
169
-
170
- let id = formContent.id;
171
- if (props.ldap && selectedOption && selectedOption.value) {
172
- values = {
173
- ...values,
174
- addAllBranches: props.ldap.addAllBranches,
175
- auth_user: selectedOption.value,
176
- auth_type: 'LDAP',
177
- FA: authentication
178
- }
224
+ })
225
+ .catch((err) => {
226
+ setRoles([]);
227
+ });
228
+ }
229
+
230
+ /** Get Department List */
231
+ const getDepartments = () => {
232
+ setLoading(true);
233
+ UsersAPI.getDepartments()
234
+ .then((result) => {
235
+ if (result?.success && Array.isArray(result.result)) {
236
+ const details = result.result.map((ele) => ({
237
+ label: ele.dp_desc?.trim() || '',
238
+ value: ele.dp_id,
239
+ }));
240
+ setDepartments(details);
241
+ } else {
242
+ setDepartments([]);
179
243
  }
180
-
181
- if (values.attributes && typeof values === 'object') {
182
-
183
- values = {
184
- ...values,
185
- auth_type: 'LDAP',
186
-
187
- attributes: JSON.stringify(values.attributes)
188
- }
244
+ })
245
+ .catch((error) => {
246
+ console.error('Error fetching departments:', error);
247
+ setDepartments([]);
248
+ })
249
+ .finally(() => setLoading(false));
250
+ };
251
+
252
+ /** Get Doctor List */
253
+ const getDoctors = () => {
254
+ UsersAPI.getDoctors()
255
+ .then((res) => {
256
+ if (res?.success && Array.isArray(res.result)) {
257
+ const list = res.result.map((doc) => ({
258
+ label: `${doc.do_name} (${doc.do_code})`,
259
+ value: doc.do_code,
260
+ }));
261
+ setDoctorList(list);
189
262
  }
190
-
191
- if (id) {
192
-
193
- // Update of model
194
- UsersAPI.updateUser({ id, formBody: values }).then((result) => {
195
-
196
- if (result.success)
197
-
198
- message.success(result.message);
199
-
200
- else
201
- message.error(result.message)
202
-
203
- setLoading(false);
204
-
205
- callback();
206
-
207
- });
208
-
263
+ })
264
+ .catch((err) => console.error('Doctor API Error:', err));
265
+ };
266
+ /** Get staff List */
267
+ const getStaff = () => {
268
+ UsersAPI.getAllStaff()
269
+ .then((res) => {
270
+ console.log('Staff List Response:', res);
271
+
272
+ if (Array.isArray(res)) {
273
+ const list = res.map((staff) => ({
274
+ label: `${staff.shortName || 'No Name'} (${staff.id})`,
275
+ value: staff.id,
276
+ }));
277
+
278
+ setStaffList(list);
209
279
  } else {
210
-
211
- // Append the additional queries to the object
212
- additional_queries.forEach(({ field, value }) => {
213
-
214
- values[field] = value;
215
-
216
- })
217
-
218
- // add new model
219
- UsersAPI.create(values).then((result) => {
220
-
221
- // callback();
222
- if (result.success)
223
-
224
- message.success(result.message);
225
-
226
- else
227
- message.error(result.message)
228
-
229
- setLoading(false);
230
-
231
- callback();
232
-
233
- });
280
+ console.error('API did not return an array!');
234
281
  }
235
- };
282
+ })
283
+ .catch((err) => console.error('staff API Error:', err));
284
+ };
236
285
 
237
- /**
238
- * Function on handle change
239
- * @param {*} selected
286
+ // Function to handle user type change
287
+ const handleUserTypeChange = (value) => {
288
+ setUserType(value);
289
+
290
+ if (value === 'RAD') {
291
+ getDoctors(); // load doctor list
292
+ } else {
293
+ form.setFieldsValue({ default_code: undefined });
294
+ }
295
+ if (value === 'STAFF') {
296
+ getStaff(); // load staff list
297
+ } else {
298
+ form.setFieldsValue({ staff_code: undefined });
299
+ }
300
+ };
301
+
302
+ useEffect(() => {
303
+ getBranches();
304
+ getDesignations();
305
+ getDepartments();
306
+ getRoles();
307
+ getDoctors(); // load doctor list
308
+ getStaff();
309
+ }, []);
310
+
311
+ useEffect(() => {
312
+ if (formContent && formContent.user_type) {
313
+ form.setFieldsValue({ user_type: formContent.user_type });
314
+ setUserType(formContent.user_type);
315
+
316
+ if (formContent.user_type === 'RAD' && formContent.doctor_code) {
317
+ form.setFieldsValue({ default_code: formContent.doctor_code });
318
+ }
319
+ if (formContent.user_type === 'STAFF' && formContent.staff_code) {
320
+ form.setFieldsValue({ staff_code: formContent.staff_code });
321
+ }
322
+ }
323
+ if (formContent?.id && formContent?.organization_details) {
324
+ try {
325
+ const org = JSON.parse(formContent.organization_details);
326
+ const branchIds = org.branch_ids?.map((b) => b.id) || [];
327
+ const defaultBranchObj = org.branch_ids?.find((b) => b.DefaultBranch === 'true');
328
+ const defaultBr = defaultBranchObj?.id || null;
329
+
330
+ setSelectedBranches(branchIds);
331
+ setDefaultBranch(defaultBr);
332
+
333
+ form.setFieldsValue({
334
+ selectedBranches: branchIds,
335
+ defaultBranch: defaultBr,
336
+ });
337
+ } catch (err) {
338
+ console.error('Invalid organization_details JSON', err);
339
+ }
340
+ }
341
+ }, [formContent]);
342
+ // Generate branch options for Select component
343
+ const branchOptions = branches.map((branch) => ({
344
+ label: branch.br_desc,
345
+ value: branch.br_code,
346
+ }));
347
+
348
+ /**
349
+ * Submit values
240
350
  */
241
- const handleCheackChange = (e) => {
351
+ const onSubmit = (values) => {
352
+ /**If PanelOpen is open and edit mode then password will be existing password else new password*/
353
+ if (!isPasswordVisible && mode === 'Edit') {
354
+ values.password = body.password;
355
+ }
356
+ values.user_type = values.user_type;
242
357
 
243
- setIsPasswordVisible(e.target.checked);
358
+ if (values.user_type === 'RAD') {
359
+ values.doctor_code = values.default_code;
360
+ } else {
361
+ values.doctor_code = null;
362
+ }
363
+ if (values.user_type === 'STAFF') {
364
+ values.staff_code = values.staff_code;
365
+ } else {
366
+ values.staff_code = null;
367
+ }
368
+ values = {
369
+ ...values,
370
+ auth_type: 'LDAP',
371
+ FA: authentication,
244
372
  };
245
373
 
374
+ setLoading(true);
375
+
376
+ let id = formContent?.id;
377
+ if (props?.ldap && selectedOption && selectedOption.value) {
378
+ values = {
379
+ ...values,
380
+ addAllBranches: props.ldap.addAllBranches,
381
+ auth_user: selectedOption.value,
382
+ auth_type: 'LDAP',
383
+ FA: authentication,
384
+ };
385
+ }
246
386
 
247
- function changeView(result) {
387
+ if (values.attributes && typeof values === 'object') {
388
+ values = {
389
+ ...values,
390
+ auth_type: 'LDAP',
248
391
 
249
- setAuthentication(result);
392
+ attributes: JSON.stringify(values.attributes),
393
+ };
250
394
  }
251
395
 
252
- /**
253
- * Function to add load userrs
254
- */
255
- function loadUsers() {
396
+ if (id) {
397
+ // Update of model
256
398
 
257
- // UsersAPI.getLdapUsers().then((result) => {
399
+ UsersAPI.updateUser({ id, formBody: values }).then((result) => {
400
+ if (result.success) message.success(result.message);
401
+ else message.error(result.message);
258
402
 
259
- // setUsers(result.result);
403
+ setLoading(false);
260
404
 
261
- // });
405
+ callback();
406
+ });
407
+ } else {
408
+ // Append the additional queries to the object
409
+ // additional_queries.forEach(({ field, value }) => {
410
+ // values[field] = value;
411
+ // });
412
+ if (Array.isArray(additional_queries)) {
413
+ additional_queries.forEach(({ field, value }) => {
414
+ values[field] = value;
415
+ });
416
+ }
417
+
418
+ // add new model
419
+ UsersAPI.create(values).then((result) => {
420
+ // callback();
421
+ if (result.success) message.success(result.message);
422
+ else message.error(result.message);
262
423
 
263
- }
424
+ setLoading(false);
264
425
 
265
- // Transform array into react-select options
266
- let options = users.map(item => ({
267
- value: item.name,
268
- label: item.name// Capitalize the first letter
269
- }));
270
-
271
- /**
272
- * Function on handle change
273
- * @param {*} selected
274
- */
275
- const handleChange = (selected) => {
276
- setSelectedOption(selected);
277
- };
278
- /**
279
- *
280
- * @param {*} inputValue
281
- * @param {*} callback
282
- */
283
-
284
- const loadOptions = (inputValue, callback) => {
285
- // Filter options based on input
286
- const filteredOptions = options.filter(option =>
287
- option.label.toLowerCase().includes(inputValue.toLowerCase())
288
- );
289
- callback(filteredOptions);
290
- };
426
+ callback();
427
+ });
428
+ }
429
+ };
291
430
 
292
- return (
293
- <section className="collection-add">
294
- <Title level={4}>{mode} User</Title>
431
+ /**
432
+ * Function on handle change
433
+ * @param {*} selected
434
+ */
435
+ const handleCheackChange = (e) => {
436
+ setIsPasswordVisible(e.target.checked);
437
+ };
295
438
 
296
- {loading ? (
297
- <Skeleton />
298
- ) : (
299
- <Form initialValues={formData} form={form} layout="vertical" onFinish={onSubmit}>
439
+ function changeView(result) {
440
+ setAuthentication(result);
441
+ }
300
442
 
301
- {/* Caption */}
302
- <Form.Item name={"name"} label="Name" required>
303
- <Input placeholder="Enter name" />
304
- </Form.Item>
305
- {/* Caption Ends */}
443
+ /**
444
+ * Function to add load userrs
445
+ */
446
+ function loadUsers() {
447
+ // UsersAPI.getLdapUsers().then((result) => {
448
+ // setUsers(result.result);
449
+ // });
450
+ }
451
+
452
+ // Transform array into react-select options
453
+ let options = users.map((item) => ({
454
+ value: item.name,
455
+ label: item.name, // Capitalize the first letter
456
+ }));
457
+
458
+ /**
459
+ * Function on handle change
460
+ * @param {*} selected
461
+ */
462
+ const handleChange = (selected) => {
463
+ setSelectedOption(selected);
464
+ };
465
+ /**
466
+ *
467
+ * @param {*} inputValue
468
+ * @param {*} callback
469
+ */
306
470
 
307
- {/* Name */}
308
- <Form.Item name={"email"} label="Email" required>
309
- <Input placeholder="Enter email" />
310
- </Form.Item>
311
- {/* Name Ends */}
312
-
313
- {formContent.id ? (
314
- <>
315
- <Form.Item>
316
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
317
- <Checkbox onChange={handleCheackChange} />
318
- <span>Select the option if you want to change the password</span>
319
- </div>
320
- </Form.Item>
321
-
322
- {isPasswordVisible && (
323
- <Form.Item
324
- name="password"
325
- label="Password"
326
- rules={[
327
- { required: true, message: 'Please enter your password' },
328
- { pattern: passwordRegex, message: passwordRegexMessage },
329
- ]}
330
- >
331
- <Input.Password placeholder="Enter password" autoComplete="new-password" />
332
- </Form.Item>
333
- )}
334
- </>
335
- ) : (
336
- <Form.Item
337
- name="password"
338
- label="Password"
339
- rules={[
340
- {
341
- required: true,
342
- message: 'Please enter your password',
343
- },
344
- {
345
- pattern: new RegExp(passwordRegex),
346
- message: passwordRegexMessage,
347
- },
348
- ]}
471
+ const loadOptions = (inputValue, callback) => {
472
+ // Filter options based on input
473
+ const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(inputValue.toLowerCase()));
474
+ callback(filteredOptions);
475
+ };
476
+
477
+ return (
478
+ <section className="collection-add">
479
+ <Title level={4}>{mode} User</Title>
480
+
481
+ {loading ? (
482
+ <Skeleton />
483
+ ) : (
484
+ <Form initialValues={formData} form={form} layout="vertical" onFinish={onSubmit}>
485
+ {/* user type */}
486
+ <Row gutter={16}>
487
+ <Col span={6}>
488
+ <Form.Item
489
+ name="user_type"
490
+ label="User Type"
491
+ allowClear
492
+ showSearch
493
+ initialValue="GEN"
494
+ rules={[{ required: true, message: 'Please select a user type' }]}
495
+ >
496
+ <Select options={getUserTypeOptions()} onChange={handleUserTypeChange} />
497
+ </Form.Item>
498
+ </Col>
499
+ <Col span={12}>
500
+ {/* username */}
501
+ <Form.Item name={'name'} label="Name" rules={[{ required: true, message: 'Please enter your user name' }]}>
502
+ <Input placeholder="Enter Name" autoFocus />
503
+ </Form.Item>
504
+ </Col>
505
+ <Col span={6}>
506
+ {' '}
507
+ {/* Show extra dropdown only if user type is Doctor */}
508
+ {userType === 'RAD' && (
509
+ <Form.Item name="default_code" label="Default Code" rules={[{ required: true, message: 'Please select a default code' }]}>
510
+ <Select
511
+ placeholder="Select Code"
512
+ options={doctorList}
513
+ showSearch
514
+ optionFilterProp="label"
515
+ dropdownRender={(menu) => (
516
+ <>
517
+ {menu}
518
+ <div
519
+ style={{
520
+ padding: '8px',
521
+ cursor: 'pointer',
522
+ borderTop: '1px solid #f0f0f0',
523
+ color: '#1890ff',
524
+ }}
525
+ onClick={() => setVisible(true)}
349
526
  >
350
- <Input.Password visibilityToggle={false} placeholder="Enter password" autoComplete="new-password" />
351
- </Form.Item>
527
+ + Add New Doctor
528
+ </div>
529
+ </>
352
530
  )}
353
-
354
- {/* </Form.Item> */}
355
-
356
-
357
- {/* Path */}
358
- {/* <Form.Item name="password" label="Password"
531
+ />
532
+ {/* Render DoctorAdd OUTSIDE the Select */}
533
+ <DoctorAdd
534
+ visible={visible}
535
+ onCancel={() => setVisible(false)}
536
+ attributes={attributes}
537
+ doctorData={selectedDoctor}
538
+ doctorId={doctorID}
539
+ onSuccess={getDoctors}
540
+ />
541
+ </Form.Item>
542
+ )}
543
+ {userType === 'STAFF' && (
544
+ <Form.Item name="staff_code" label="Staff Code" rules={[{ required: true, message: 'Please select a staff code' }]}>
545
+ <Select
546
+ placeholder="Select Code"
547
+ options={staffList}
548
+ showSearch
549
+ optionFilterProp="label"
550
+ dropdownRender={(menu) => (
551
+ <>
552
+ {menu}
553
+ <div
554
+ style={{
555
+ padding: '8px',
556
+ cursor: 'pointer',
557
+ borderTop: '1px solid #f0f0f0',
558
+ color: '#1890ff',
559
+ }}
560
+ onClick={() => setVisible(true)}
561
+ >
562
+ + Add New Staff
563
+ </div>
564
+ </>
565
+ )}
566
+ />
567
+ {/* Render DoctorAdd OUTSIDE the Select */}
568
+
569
+ <StaffAdd visible={visible} onCancel={() => setVisible(false)} staffData={selectedStaff} staffId={staffID} onSuccess={getStaff} />
570
+
571
+ <></>
572
+ </Form.Item>
573
+ )}
574
+ </Col>
575
+ </Row>
576
+ <Row gutter={16}>
577
+ <Col span={8}>
578
+ {/* email */}
579
+ <Form.Item name={'email'} label="User Name / Email" rules={[{ required: true, message: 'Please enter your email' }]}>
580
+ <Input placeholder="Enter Email Address" />
581
+ </Form.Item>
582
+ </Col>
583
+
584
+ <Col span={8}>
585
+ {/* Mobile */}
586
+ <Form.Item name="mobile" label="Mobile" rules={[{ required: true, message: 'Please enter your mobile number' }]}>
587
+ <Input placeholder="Enter Mobile" />
588
+ </Form.Item>
589
+ </Col>
590
+ <Col span={8}>
591
+ {/* Designation */}
592
+ <Form.Item name="designation" label="Designation">
593
+ <Select placeholder="Select Designation" options={designations} allowClear showSearch optionFilterProp="label" />
594
+ </Form.Item>
595
+ </Col>
596
+ </Row>
597
+ <Row gutter={16}>
598
+ {' '}
599
+ <Col span={8}>
600
+ {/* Department */}
601
+ <Form.Item name="department" label="Department">
602
+ <Select placeholder="Select Department" options={departments} allowClear showSearch optionFilterProp="label" />
603
+ </Form.Item>
604
+ </Col>
605
+ <Col span={8}>
606
+ {/* Branch */}
607
+ <Form.Item label="Branches" name="selectedBranches" rules={[{ required: true, message: 'Please select at least one branch' }]}>
608
+ <Select
609
+ mode="multiple"
610
+ placeholder="Select Branches"
611
+ value={selectedBranches}
612
+ onChange={(value) => {
613
+ setSelectedBranches(value);
614
+
615
+ // ⬅NEW: remove defaultBranch if it’s not in selectedBranches
616
+ if (!value.includes(defaultBranch)) {
617
+ setDefaultBranch(undefined);
618
+ form.setFieldsValue({ defaultBranch: undefined });
619
+ }
620
+ }}
621
+ options={branchOptions}
622
+ allowClear
623
+ showSearch
624
+ optionFilterProp="label"
625
+ maxTagCount={5} // Show only 5 tags
626
+ maxTagPlaceholder={(omittedValues) => `+${omittedValues.length}`} // Show "+n"
627
+ />
628
+ </Form.Item>
629
+ </Col>
630
+ <Col span={8}>
631
+ {/* Default Branch */}
632
+ <Form.Item label="Default Branch" name="defaultBranch" rules={[{ required: true, message: 'Please select default branch' }]}>
633
+ <Select placeholder="Select Default Branch" onChange={setDefaultBranch}>
634
+ {branchOptions
635
+ .filter((opt) => selectedBranches.includes(opt.value))
636
+ .map((opt) => (
637
+ <Option key={opt.value} value={opt.value}>
638
+ {opt.label}
639
+ </Option>
640
+ ))}
641
+ </Select>
642
+ </Form.Item>
643
+ </Col>
644
+ </Row>
645
+ <Row gutter={16}>
646
+ <Col span={8}>
647
+ {formContent?.id ? (
648
+ <>
649
+ <Form.Item>
650
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
651
+ <Checkbox onChange={handleCheackChange} />
652
+ <span>Select the option if you want to change the password</span>
653
+ </div>
654
+ </Form.Item>
655
+
656
+ {isPasswordVisible && (
657
+ <Form.Item
658
+ name="password"
659
+ label="Password"
660
+ rules={[
661
+ { required: true, message: 'Please enter your password' },
662
+ { pattern: passwordRegex, message: passwordRegexMessage },
663
+ ]}
664
+ >
665
+ <Input.Password placeholder="Enter password" autoComplete="new-password" />
666
+ </Form.Item>
667
+ )}
668
+ </>
669
+ ) : (
670
+ <Form.Item
671
+ name="password"
672
+ label="Password"
673
+ rules={[
674
+ {
675
+ required: true,
676
+ message: 'Please enter your password',
677
+ },
678
+ {
679
+ pattern: new RegExp(passwordRegex),
680
+ message: passwordRegexMessage,
681
+ },
682
+ ]}
683
+ >
684
+ <Input.Password visibilityToggle={false} placeholder="Enter password" autoComplete="new-password" />
685
+ </Form.Item>
686
+ )}
687
+ </Col>
688
+ {/* </Form.Item> */}
689
+
690
+ {/* Path */}
691
+ {/* <Form.Item name="password" label="Password"
359
692
  rules={[
360
693
  {
361
694
  required: true,
@@ -368,25 +701,36 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
368
701
  ]}>
369
702
  <Input.Password visibilityToggle={false} placeholder="Enter password" autoComplete='new-password' />
370
703
  </Form.Item> */}
371
- {/* Path Ends */}
372
-
373
-
374
- {/* Path */}
375
- <Form.Item name="user_group" label="User Group" required>
376
- <Input placeholder="Enter User Group" />
377
- </Form.Item>
378
-
379
- <Form.Item name="mobile" label="Mobile" required={mobileRequired}>
380
- <Input placeholder="Enter Mobile" />
381
- </Form.Item>
382
-
383
- {props.ldap && (
384
- <>
385
- <Form.Item name="auth_type" label="auth_type">
386
- <Input placeholder="Enter auth_type" value={"LDAP"} disabled />
387
-
388
-
389
- {/* <Select
704
+ {/* Path Ends */}
705
+
706
+ {/* Path */}
707
+ <Col span={8}>
708
+ <Form.Item name="user_group" label="User Group" rules={[{ required: true, message: 'Please enter your user group' }]}>
709
+ <Input placeholder="Enter User Group" />
710
+ </Form.Item>
711
+ </Col>
712
+ <Col span={8}>
713
+ <Form.Item name="role_id" label="Role" rules={[{ required: true, message: 'Please Input Role' }]}>
714
+ <Select placeholder="Select Role" style={{ width: '100%' }}>
715
+ {roles.map((role) => (
716
+ <Option key={role.id} value={role.id}>
717
+ {role.name}
718
+ </Option>
719
+ ))}
720
+ </Select>
721
+ </Form.Item>
722
+ </Col>
723
+
724
+ {/* <Form.Item name="mobile" label="Mobile" required={mobileRequired}>
725
+ <Input placeholder="Enter Mobile" />
726
+ </Form.Item> */}
727
+
728
+ {props?.ldap && (
729
+ <>
730
+ <Form.Item name="auth_type" label="auth_type">
731
+ <Input placeholder="Enter auth_type" value={'LDAP'} disabled />
732
+
733
+ {/* <Select
390
734
 
391
735
  placeholder="Auth Type"
392
736
  defaultValue={'LDAP'}
@@ -399,7 +743,7 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
399
743
  </Option>
400
744
  </Select> */}
401
745
 
402
- {/* <div style={{ display: 'flex', justifyContent: 'space-between' }}>
746
+ {/* <div style={{ display: 'flex', justifyContent: 'space-between' }}>
403
747
 
404
748
  <div style={{ width: '40%' }}>
405
749
 
@@ -408,51 +752,63 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
408
752
 
409
753
 
410
754
  </div> */}
411
- </Form.Item>
412
-
413
- {/* Path */}
414
- <Form.Item name="auth_user" label="User Name" required>
415
- <Input placeholder="Enter User Name" />
416
- </Form.Item>
417
- </>
418
- )}
419
-
420
-
421
- <Form.Item>
422
-
423
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
424
- <Switch
425
- disabled={disabled}
426
- // defaultChecked={view}
427
- onChange={changeView}
428
- checked={authentication}
429
- // disabled={disabled}
430
- defaultChecked
431
- // checkedChildren={<OrderedListOutlined />}
432
- // unCheckedChildren={<PicCenterOutlined />}
433
- />
434
- <span>Enable Two Factor Authentication</span>
435
-
436
- </div>
437
- </Form.Item>
438
- {/* Path Ends */}
439
-
440
- {/* Path */}
441
- {/* <Form.Item name="active" label="Active" required>
755
+ </Form.Item>
756
+
757
+ {/* Path */}
758
+ <Form.Item name="auth_user" label="User Name" required>
759
+ <Input placeholder="Enter User Name" />
760
+ </Form.Item>
761
+ </>
762
+ )}
763
+ </Row>
764
+ <Row gutter={16}>
765
+ <Col span={8}>
766
+ <Form.Item>
767
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
768
+ <Switch
769
+ disabled={disabled}
770
+ // defaultChecked={view}
771
+ onChange={changeView}
772
+ checked={authentication}
773
+ // disabled={disabled}
774
+ defaultChecked
775
+ // checkedChildren={<OrderedListOutlined />}
776
+ // unCheckedChildren={<PicCenterOutlined />}
777
+ />
778
+ <span>Enable Two Factor Authentication</span>
779
+ </div>
780
+ </Form.Item>
781
+ </Col>
782
+ <Col span={8}>
783
+ {/* <label>User Status</label> */}
784
+ <Form.Item
785
+ name="active"
786
+ valuePropName="checked"
787
+ getValueFromEvent={(e) => (e.target.checked ? true : false)}
788
+ getValueProps={(value) => ({ checked: value === true })}
789
+ style={{ marginBottom: 0 }}
790
+ >
791
+ <Checkbox>Active</Checkbox>
792
+ </Form.Item>
793
+ </Col>
794
+ </Row>
795
+ {/* Path Ends */}
796
+
797
+ {/* Path */}
798
+ {/* <Form.Item name="active" label="Active" required>
442
799
  <Switch />
443
800
  </Form.Item> */}
444
- {/* Path Ends */}
445
-
446
- <Form.Item>
447
- <Button loading={loading} htmlType={'submit'} type="primary">
448
- Submit
449
- </Button>
450
- </Form.Item>
451
- </Form>
452
- )
453
- }
454
- </section >
455
- );
801
+ {/* Path Ends */}
802
+
803
+ <Form.Item>
804
+ <Button loading={loading} htmlType={'submit'} type="primary">
805
+ Submit
806
+ </Button>
807
+ </Form.Item>
808
+ </Form>
809
+ )}
810
+ </section>
811
+ );
456
812
  };
457
813
 
458
814
  export default UserAdd;