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

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