ui-soxo-bootstrap-core 2.4.25-dev.14 β 2.4.25-dev.16
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.
- package/core/models/menus/components/menu-lists/menu-lists.scss +1 -1
- package/core/models/roles/components/role-add/role-add.js +54 -85
- package/core/models/users/components/user-add/user-add.js +48 -45
- package/core/models/users/components/user-add/user-edit.js +4 -5
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +2 -1
- package/package.json +1 -1
|
@@ -34,7 +34,8 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
|
|
|
34
34
|
const [models, setModels] = useState([]);
|
|
35
35
|
const [menuList, setMenuList] = useState([]);
|
|
36
36
|
const [showMenus, setShowMenus] = useState(false);
|
|
37
|
-
|
|
37
|
+
// for deselected menu for editing
|
|
38
|
+
const [originalMenus, setOriginalMenus] = useState([]);
|
|
38
39
|
|
|
39
40
|
// Selected menus (array of IDs)
|
|
40
41
|
const [selectedMenus, setSelectedMenus] = useState([]);
|
|
@@ -57,7 +58,8 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
|
|
|
57
58
|
let menus = formContent.menu_ids;
|
|
58
59
|
|
|
59
60
|
setSelectedMenus(menus);
|
|
60
|
-
|
|
61
|
+
// keep original copy for deselect comparison
|
|
62
|
+
setOriginalMenus(menus);
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
setLoading(false);
|
|
@@ -174,58 +176,18 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
|
|
|
174
176
|
<Input placeholder="Enter description" />
|
|
175
177
|
</Form.Item>
|
|
176
178
|
|
|
177
|
-
{/*
|
|
179
|
+
{/* MENU TREE */}
|
|
178
180
|
{showMenus && menuList.length > 0 && (
|
|
179
181
|
<div style={{ marginTop: 30 }}>
|
|
180
|
-
<Title level={5}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
<Collapse expandIconPosition="left" style={{ marginBottom: '4px' }}>
|
|
186
|
-
{menuList.map((item) => {
|
|
187
|
-
const hasChildren = item.sub_menus && item.sub_menus.length > 0;
|
|
188
|
-
|
|
189
|
-
if (!hasChildren) {
|
|
190
|
-
// π NO collapse icon
|
|
191
|
-
return (
|
|
192
|
-
<div
|
|
193
|
-
key={item.id}
|
|
194
|
-
style={{
|
|
195
|
-
padding: '12px 16px',
|
|
196
|
-
display: 'flex',
|
|
197
|
-
alignItems: 'center',
|
|
198
|
-
gap: 8,
|
|
199
|
-
borderBottom: '1px solid #f0f0f0',
|
|
200
|
-
}}
|
|
201
|
-
>
|
|
202
|
-
<Checkbox checked={selectedMenus.includes(item.id)} onChange={(e) => toggleMenu(item.id, e.target.checked)} />
|
|
203
|
-
<span>{item.title || item.caption}</span>
|
|
204
|
-
</div>
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// π WITH collapse icon
|
|
209
|
-
return (
|
|
210
|
-
<Panel
|
|
211
|
-
key={item.id}
|
|
212
|
-
header={
|
|
213
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 8, borderBottom: '1px solid #f0f0f0' }}>
|
|
214
|
-
<Checkbox checked={selectedMenus.includes(item.id)} onChange={(e) => toggleMenu(item.id, e.target.checked)} />
|
|
215
|
-
<span>{item.title || item.caption}</span>
|
|
216
|
-
</div>
|
|
217
|
-
}
|
|
218
|
-
>
|
|
219
|
-
<NestedMenu parentId={item.id} step={step + 1} selectedMenus={selectedMenus} toggleMenu={toggleMenu} />
|
|
220
|
-
</Panel>
|
|
221
|
-
);
|
|
222
|
-
})}
|
|
223
|
-
</Collapse>
|
|
182
|
+
<Title level={5}>Menu List</Title>
|
|
183
|
+
<p style={{ color: '#999' }}>Choose menus and set permissions</p>
|
|
184
|
+
|
|
185
|
+
<MenuTree menus={menuList} selectedMenus={selectedMenus} toggleMenu={toggleMenu} />
|
|
224
186
|
</div>
|
|
225
187
|
)}
|
|
226
188
|
|
|
227
189
|
{/* Submit Button */}
|
|
228
|
-
<Form.Item>
|
|
190
|
+
<Form.Item style={{ marginTop: 20 }}>
|
|
229
191
|
<Button loading={loading} htmlType="submit" type="primary">
|
|
230
192
|
Save
|
|
231
193
|
</Button>
|
|
@@ -241,45 +203,52 @@ export default RoleAdd;
|
|
|
241
203
|
// ------------------------
|
|
242
204
|
// Recursive Nested Menu Component
|
|
243
205
|
// ------------------------
|
|
244
|
-
const
|
|
245
|
-
const [items, setItems] = useState([]);
|
|
246
|
-
const [loading, setLoading] = useState(true);
|
|
247
|
-
|
|
248
|
-
useEffect(() => {
|
|
249
|
-
MenusAPI.get({
|
|
250
|
-
queries: [
|
|
251
|
-
{ field: 'header_id', value: parentId },
|
|
252
|
-
{ field: 'step', value: step },
|
|
253
|
-
],
|
|
254
|
-
})
|
|
255
|
-
.then((res) => {
|
|
256
|
-
setItems(res.result || []);
|
|
257
|
-
setLoading(false);
|
|
258
|
-
})
|
|
259
|
-
.catch(() => setLoading(false));
|
|
260
|
-
}, [parentId, step]);
|
|
261
|
-
|
|
262
|
-
if (loading) return <Skeleton active />;
|
|
263
|
-
if (!items.length) return null;
|
|
264
|
-
|
|
206
|
+
const MenuTree = ({ menus, selectedMenus, toggleMenu }) => {
|
|
265
207
|
return (
|
|
266
|
-
|
|
267
|
-
{
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
208
|
+
<>
|
|
209
|
+
{menus.map((menu) => {
|
|
210
|
+
const hasChildren = Array.isArray(menu.sub_menus) && menu.sub_menus.length > 0;
|
|
211
|
+
|
|
212
|
+
// NO CHILD β SIMPLE ROW (NO COLLAPSE)
|
|
213
|
+
if (!hasChildren) {
|
|
214
|
+
return (
|
|
215
|
+
<div
|
|
216
|
+
key={menu.id}
|
|
217
|
+
style={{
|
|
218
|
+
padding: '10px 16px',
|
|
219
|
+
display: 'flex',
|
|
220
|
+
alignItems: 'center',
|
|
221
|
+
gap: 8,
|
|
222
|
+
borderBottom: '1px solid #f0f0f0',
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
<Checkbox checked={selectedMenus.includes(menu.id)} onChange={(e) => toggleMenu(menu.id, e.target.checked)} />
|
|
276
226
|
<span>{menu.title || menu.caption}</span>
|
|
277
227
|
</div>
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// HAS CHILD β COLLAPSE WITH ICON
|
|
232
|
+
return (
|
|
233
|
+
<Collapse key={menu.id} collapsible="icon" style={{ marginBottom: '4px' }}>
|
|
234
|
+
<Panel
|
|
235
|
+
key={menu.id}
|
|
236
|
+
header={
|
|
237
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
238
|
+
<Checkbox
|
|
239
|
+
checked={selectedMenus.includes(menu.id)}
|
|
240
|
+
onClick={(e) => e.stopPropagation()}
|
|
241
|
+
onChange={(e) => toggleMenu(menu.id, e.target.checked)}
|
|
242
|
+
/>
|
|
243
|
+
<span>{menu.title || menu.caption}</span>
|
|
244
|
+
</div>
|
|
245
|
+
}
|
|
246
|
+
>
|
|
247
|
+
<MenuTree menus={menu.sub_menus} selectedMenus={selectedMenus} toggleMenu={toggleMenu} />
|
|
248
|
+
</Panel>
|
|
249
|
+
</Collapse>
|
|
250
|
+
);
|
|
251
|
+
})}
|
|
252
|
+
</>
|
|
284
253
|
);
|
|
285
254
|
};
|
|
@@ -160,6 +160,17 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}, []);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (!loading && formContent?.role_id && roles.length > 0) {
|
|
166
|
+
const roleId = Number(formContent.role_id);
|
|
167
|
+
|
|
168
|
+
if (!Number.isNaN(roleId)) {
|
|
169
|
+
form.setFieldsValue({ role_id: roleId });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}, [loading, formContent, roles]);
|
|
173
|
+
|
|
163
174
|
/**
|
|
164
175
|
*Define the options dynamically
|
|
165
176
|
*/
|
|
@@ -203,7 +214,6 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
203
214
|
}
|
|
204
215
|
})
|
|
205
216
|
.catch((error) => {
|
|
206
|
-
console.error('Error fetching designations:', error);
|
|
207
217
|
setDesignations([]);
|
|
208
218
|
})
|
|
209
219
|
.finally(() => setLoading(false));
|
|
@@ -215,16 +225,10 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
215
225
|
function getRoles() {
|
|
216
226
|
RolesAPI.getRole()
|
|
217
227
|
.then((res) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
setRoles(res.result.filter((r) => r.active === 'Y')); // optional: only active roles
|
|
221
|
-
} else {
|
|
222
|
-
setRoles([]);
|
|
223
|
-
}
|
|
228
|
+
const activeRoles = Array.isArray(res.result) ? res.result.filter((r) => r.active === 'Y') : [];
|
|
229
|
+
setRoles(activeRoles);
|
|
224
230
|
})
|
|
225
|
-
.catch((
|
|
226
|
-
setRoles([]);
|
|
227
|
-
});
|
|
231
|
+
.catch(() => setRoles([]));
|
|
228
232
|
}
|
|
229
233
|
|
|
230
234
|
/** Get Department List */
|
|
@@ -243,7 +247,6 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
243
247
|
}
|
|
244
248
|
})
|
|
245
249
|
.catch((error) => {
|
|
246
|
-
console.error('Error fetching departments:', error);
|
|
247
250
|
setDepartments([]);
|
|
248
251
|
})
|
|
249
252
|
.finally(() => setLoading(false));
|
|
@@ -320,25 +323,24 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
320
323
|
form.setFieldsValue({ staff_code: formContent.staff_code });
|
|
321
324
|
}
|
|
322
325
|
}
|
|
323
|
-
if (formContent
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}, [formContent]);
|
|
326
|
+
if (!formContent) return;
|
|
327
|
+
|
|
328
|
+
// normalize branch ids to NUMBER
|
|
329
|
+
const org =
|
|
330
|
+
typeof formContent.organization_details === 'string' ? JSON.parse(formContent.organization_details) : formContent.organization_details;
|
|
331
|
+
|
|
332
|
+
const branchIds = (org?.branch_ids || []).map(Number);
|
|
333
|
+
const defaultBr = formContent.defaultBranch ? Number(formContent.defaultBranch) : null;
|
|
334
|
+
|
|
335
|
+
// state (for filtering)
|
|
336
|
+
setSelectedBranches(branchIds);
|
|
337
|
+
|
|
338
|
+
// form (source of truth)
|
|
339
|
+
form.setFieldsValue({
|
|
340
|
+
selectedBranches: branchIds,
|
|
341
|
+
defaultBranch: defaultBr,
|
|
342
|
+
});
|
|
343
|
+
}, [formContent, form]);
|
|
342
344
|
// Generate branch options for Select component
|
|
343
345
|
const branchOptions = branches.map((branch) => ({
|
|
344
346
|
label: branch.br_desc,
|
|
@@ -349,6 +351,8 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
349
351
|
* Submit values
|
|
350
352
|
*/
|
|
351
353
|
const onSubmit = (values) => {
|
|
354
|
+
values.defaultBranch = String(values.defaultBranch);
|
|
355
|
+
|
|
352
356
|
/**If PanelOpen is open and edit mode then password will be existing password else new password*/
|
|
353
357
|
if (!isPasswordVisible && mode === 'Edit') {
|
|
354
358
|
values.password = body.password;
|
|
@@ -377,6 +381,7 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
377
381
|
if (props?.ldap && selectedOption && selectedOption.value) {
|
|
378
382
|
values = {
|
|
379
383
|
...values,
|
|
384
|
+
|
|
380
385
|
addAllBranches: props.ldap.addAllBranches,
|
|
381
386
|
auth_user: selectedOption.value,
|
|
382
387
|
auth_type: 'LDAP',
|
|
@@ -387,6 +392,7 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
387
392
|
if (values.attributes && typeof values === 'object') {
|
|
388
393
|
values = {
|
|
389
394
|
...values,
|
|
395
|
+
|
|
390
396
|
auth_type: 'LDAP',
|
|
391
397
|
|
|
392
398
|
attributes: JSON.stringify(values.attributes),
|
|
@@ -624,22 +630,19 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
624
630
|
<Select
|
|
625
631
|
mode="multiple"
|
|
626
632
|
placeholder="Select Branches"
|
|
627
|
-
|
|
633
|
+
options={branchOptions}
|
|
634
|
+
allowClear
|
|
635
|
+
showSearch
|
|
636
|
+
optionFilterProp="label"
|
|
628
637
|
onChange={(value) => {
|
|
629
|
-
|
|
638
|
+
const normalized = value.map(Number);
|
|
639
|
+
setSelectedBranches(normalized);
|
|
630
640
|
|
|
631
|
-
|
|
632
|
-
if (!
|
|
633
|
-
setDefaultBranch(undefined);
|
|
641
|
+
const currentDefault = form.getFieldValue('defaultBranch');
|
|
642
|
+
if (currentDefault && !normalized.includes(currentDefault)) {
|
|
634
643
|
form.setFieldsValue({ defaultBranch: undefined });
|
|
635
644
|
}
|
|
636
645
|
}}
|
|
637
|
-
options={branchOptions}
|
|
638
|
-
allowClear
|
|
639
|
-
showSearch
|
|
640
|
-
optionFilterProp="label"
|
|
641
|
-
maxTagCount={5} // Show only 5 tags
|
|
642
|
-
maxTagPlaceholder={(omittedValues) => `+${omittedValues.length}`} // Show "+n"
|
|
643
646
|
/>
|
|
644
647
|
</Form.Item>
|
|
645
648
|
</Col>
|
|
@@ -648,9 +651,9 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
648
651
|
<Form.Item label="Default Branch" name="defaultBranch" rules={[{ required: true, message: 'Please select default branch' }]}>
|
|
649
652
|
<Select placeholder="Select Default Branch" onChange={setDefaultBranch}>
|
|
650
653
|
{branchOptions
|
|
651
|
-
.filter((opt) => selectedBranches.includes(opt.value))
|
|
654
|
+
.filter((opt) => selectedBranches.includes(Number(opt.value)))
|
|
652
655
|
.map((opt) => (
|
|
653
|
-
<Option key={opt.value} value={opt.value}>
|
|
656
|
+
<Option key={opt.value} value={Number(opt.value)}>
|
|
654
657
|
{opt.label}
|
|
655
658
|
</Option>
|
|
656
659
|
))}
|
|
@@ -726,8 +729,8 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
726
729
|
</Form.Item>
|
|
727
730
|
</Col>
|
|
728
731
|
<Col span={8}>
|
|
729
|
-
<Form.Item name="role_id" label="Role" rules={[{ required: true, message: 'Please
|
|
730
|
-
<Select placeholder="Select Role"
|
|
732
|
+
<Form.Item name="role_id" label="Role" rules={[{ required: true, message: 'Please select a Role' }]}>
|
|
733
|
+
<Select placeholder="Select Role">
|
|
731
734
|
{roles.map((role) => (
|
|
732
735
|
<Option key={role.id} value={role.id}>
|
|
733
736
|
{role.name}
|
|
@@ -11,7 +11,6 @@ export default function UserEdit(record) {
|
|
|
11
11
|
// Handle edit button click
|
|
12
12
|
const handleEditClick = () => {
|
|
13
13
|
if (!record.id) {
|
|
14
|
-
console.warn('Invalid record: Missing ID');
|
|
15
14
|
return;
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -29,9 +28,7 @@ export default function UserEdit(record) {
|
|
|
29
28
|
// Try parsing other_details, handle error if invalid JSON
|
|
30
29
|
try {
|
|
31
30
|
otherDetails = JSON.parse(apiData.other_details);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
console.warn('Failed to parse other_details:', apiData.other_details);
|
|
34
|
-
}
|
|
31
|
+
} catch (err) {}
|
|
35
32
|
}
|
|
36
33
|
let orgDetails = {};
|
|
37
34
|
try {
|
|
@@ -50,8 +47,10 @@ export default function UserEdit(record) {
|
|
|
50
47
|
designation: apiData.designation_code,
|
|
51
48
|
department: apiData.department_id,
|
|
52
49
|
// Handle selected branches and default branch
|
|
50
|
+
organization_details: orgDetails,
|
|
53
51
|
selectedBranches: orgDetails.branch_ids || [],
|
|
54
|
-
defaultBranch: apiData.
|
|
52
|
+
defaultBranch: apiData.branch_id || null,
|
|
53
|
+
role_id: apiData.role_id,
|
|
55
54
|
password: apiData.password,
|
|
56
55
|
user_group: apiData.user_group,
|
|
57
56
|
// Handle doctor codes
|
|
@@ -1042,7 +1042,8 @@ function GuestList({
|
|
|
1042
1042
|
) : (
|
|
1043
1043
|
<TableComponent
|
|
1044
1044
|
size="small"
|
|
1045
|
-
scroll={{ x: true }}
|
|
1045
|
+
scroll={{ x: true, y: '60vh' }}
|
|
1046
|
+
sticky
|
|
1046
1047
|
rowKey={(record) => record.OpNo}
|
|
1047
1048
|
dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
|
|
1048
1049
|
columns={cols}
|