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.
- package/.github/workflows/npm-publish.yml +37 -15
- package/core/components/extra-info/extra-info-details.js +109 -126
- package/core/components/landing-api/landing-api.js +22 -30
- package/core/lib/Store.js +20 -18
- package/core/lib/components/index.js +4 -1
- package/core/lib/components/sidemenu/sidemenu.js +153 -256
- package/core/lib/components/sidemenu/sidemenu.scss +39 -26
- package/core/lib/elements/basic/rangepicker/rangepicker.js +118 -29
- package/core/lib/elements/basic/switch/switch.js +34 -24
- package/core/lib/hooks/index.js +2 -12
- package/core/lib/hooks/use-otp-timer.js +99 -0
- package/core/lib/pages/login/login.js +255 -139
- package/core/lib/pages/login/login.scss +140 -32
- package/core/models/dashboard/dashboard.js +14 -0
- package/core/models/doctor/components/doctor-add/doctor-add.js +403 -0
- package/core/models/doctor/components/doctor-add/doctor-add.scss +32 -0
- package/core/models/menus/components/menu-add/menu-add.js +230 -268
- package/core/models/menus/components/menu-lists/menu-lists.js +126 -89
- package/core/models/menus/components/menu-lists/menu-lists.scss +9 -0
- package/core/models/menus/menus.js +247 -267
- package/core/models/roles/components/role-add/role-add.js +269 -227
- package/core/models/roles/components/role-list/role-list.js +8 -6
- package/core/models/roles/roles.js +182 -174
- package/core/models/staff/components/staff-add/staff-add.js +352 -0
- package/core/models/staff/components/staff-add/staff-add.scss +0 -0
- package/core/models/users/components/user-add/user-add.js +686 -364
- package/core/models/users/components/user-add/user-edit.js +90 -0
- package/core/models/users/users.js +318 -165
- package/core/modules/index.js +5 -8
- package/core/modules/reporting/components/index.js +5 -0
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +65 -2
- package/core/modules/steps/action-buttons.js +79 -0
- package/core/modules/steps/steps.js +553 -0
- package/core/modules/steps/steps.scss +158 -0
- package/core/modules/steps/timeline.js +49 -0
- package/package.json +2 -2
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { ReloadOutlined,
|
|
2
|
+
import { Space, Switch, Popconfirm, Skeleton, Input, Drawer, Collapse } from 'antd';
|
|
3
|
+
import { ReloadOutlined, DeleteOutlined, EditOutlined, CopyOutlined, PlusCircleFilled } from '@ant-design/icons';
|
|
4
4
|
import { Link, useParams, useLocation } from 'react-router-dom';
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
// for draggable menu list import { DndProvider } from "react-dnd";
|
|
8
7
|
import { DndProvider } from 'react-dnd';
|
|
9
8
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
10
9
|
import { DraggableWrapper } from '../../../../lib';
|
|
11
|
-
import './menu-lists.scss'
|
|
10
|
+
import './menu-lists.scss';
|
|
11
|
+
import { Button, Card } from '../../../../lib';
|
|
12
12
|
|
|
13
13
|
const { Search } = Input;
|
|
14
14
|
const { Panel } = Collapse;
|
|
@@ -37,11 +37,13 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
37
37
|
|
|
38
38
|
const [query, setQuery] = useState('');
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
const [dragMode, setDragMode] = useState(
|
|
40
|
+
// DEFAULT DRAG MODE: OFF
|
|
41
|
+
const [dragMode, setDragMode] = useState(false); // for drag (default OFF)
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
// to detect drag changes
|
|
44
|
+
const [orderChanged, setOrderChanged] = useState(false);
|
|
44
45
|
|
|
46
|
+
const toggleDragMode = (checked) => setDragMode(checked);
|
|
45
47
|
|
|
46
48
|
useEffect(() => {
|
|
47
49
|
loadMenus();
|
|
@@ -79,7 +81,7 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
79
81
|
var result = res.result;
|
|
80
82
|
|
|
81
83
|
if (Array.isArray(result)) {
|
|
82
|
-
setRecords(result);
|
|
84
|
+
setRecords(result.sort((a, b) => a.order - b.order));
|
|
83
85
|
// } else {
|
|
84
86
|
// setRecords([])
|
|
85
87
|
}
|
|
@@ -93,9 +95,9 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
93
95
|
});
|
|
94
96
|
};
|
|
95
97
|
|
|
96
|
-
function changeView(result) {
|
|
97
|
-
|
|
98
|
-
}
|
|
98
|
+
// function changeView(result) {
|
|
99
|
+
// setView(result);
|
|
100
|
+
// }
|
|
99
101
|
const loadMenus = () => {
|
|
100
102
|
setLoading(true);
|
|
101
103
|
|
|
@@ -104,7 +106,8 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
104
106
|
queries: [...additional_queries, { field: 'step', value: step }, { field: 'header_id', value: null }],
|
|
105
107
|
})
|
|
106
108
|
.then((res) => {
|
|
107
|
-
|
|
109
|
+
const sorted = (res.result || []).sort((a, b) => a.order - b.order);
|
|
110
|
+
setRecords(sorted);
|
|
108
111
|
setLoading(false);
|
|
109
112
|
})
|
|
110
113
|
.catch(() => setLoading(false));
|
|
@@ -124,41 +127,47 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
124
127
|
// ------------------------
|
|
125
128
|
// Recursive function to build payload
|
|
126
129
|
// ------------------------
|
|
127
|
-
const buildOrderPayload = (menus) =>
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (menu.sub_menus && menu.sub_menus.length) {
|
|
135
|
-
payload.sub_menus = buildOrderPayload(menu.sub_menus);
|
|
130
|
+
const buildOrderPayload = (menus) =>
|
|
131
|
+
menus.map((menu, index) => {
|
|
132
|
+
const item = { id: menu.id, order: index + 1 };
|
|
133
|
+
|
|
134
|
+
// FIX: use sub_menus instead of children
|
|
135
|
+
if (menu.sub_menus && menu.sub_menus.length > 0) {
|
|
136
|
+
item.sub_menus = buildOrderPayload(menu.sub_menus);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
return
|
|
139
|
+
return item;
|
|
139
140
|
});
|
|
140
|
-
};
|
|
141
141
|
|
|
142
142
|
// ------------------------
|
|
143
143
|
// Save order function
|
|
144
144
|
// ------------------------
|
|
145
145
|
const saveOrder = () => {
|
|
146
146
|
const payload = { menus: buildOrderPayload(records) };
|
|
147
|
+
|
|
147
148
|
model
|
|
148
|
-
.
|
|
149
|
-
.then(() => {
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
.saveOrder({ formBody: payload })
|
|
150
|
+
.then((res) => {
|
|
151
|
+
setOrderChanged(false);
|
|
152
|
+
|
|
153
|
+
loadMenus(); // force refresh
|
|
152
154
|
})
|
|
155
|
+
// const { updated_ids, same_order_ids } = res.result;
|
|
156
|
+
|
|
157
|
+
// Combine the updated order
|
|
158
|
+
// const newOrder = [...updated_ids, ...same_order_ids];
|
|
159
|
+
// const reorderedRecords = newOrder.map((id) => records.find((r) => r.id === id)).filter(Boolean); // remove undefined if not found
|
|
160
|
+
|
|
161
|
+
// setRecords(reorderedRecords);
|
|
162
|
+
// loadMenus(); // <-- reload from backend
|
|
163
|
+
// setOrderChanged(false);
|
|
164
|
+
// })
|
|
153
165
|
.catch((err) => {
|
|
154
166
|
console.error(err);
|
|
155
|
-
|
|
167
|
+
|
|
156
168
|
});
|
|
157
169
|
};
|
|
158
170
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
171
|
return (
|
|
163
172
|
<Card className="generic-list">
|
|
164
173
|
<div className="table-header">
|
|
@@ -179,41 +188,29 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
179
188
|
<div className="table-actions">
|
|
180
189
|
<div className="button-container">
|
|
181
190
|
<Space size="small">
|
|
182
|
-
<Button onClick={getRecords} size={'small'}>
|
|
191
|
+
<Button onClick={getRecords} size={'small'} type="default">
|
|
183
192
|
<ReloadOutlined />
|
|
184
193
|
</Button>
|
|
185
194
|
|
|
186
|
-
{/* <Switch
|
|
187
|
-
defaultChecked
|
|
188
|
-
onChange={changeView}
|
|
189
|
-
checked={view}
|
|
190
|
-
checkedChildren={<OrderedListOutlined />}
|
|
191
|
-
unCheckedChildren={<PicCenterOutlined />}
|
|
192
|
-
/> */}
|
|
193
195
|
{/* NEW SWITCH: Drag Mode */}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
Save Order
|
|
208
|
-
</Button>
|
|
209
|
-
)}
|
|
210
|
-
|
|
211
|
-
|
|
196
|
+
<Switch
|
|
197
|
+
checked={dragMode}
|
|
198
|
+
onChange={toggleDragMode}
|
|
199
|
+
checkedChildren="Order On"
|
|
200
|
+
unCheckedChildren="Order Off"
|
|
201
|
+
className="custom-switch"
|
|
202
|
+
/>
|
|
203
|
+
{/* Only show Save Order button when a change happens */}
|
|
204
|
+
{dragMode && orderChanged && (
|
|
205
|
+
<Button type="primary" size="small" onClick={saveOrder}>
|
|
206
|
+
Save Order
|
|
207
|
+
</Button>
|
|
208
|
+
)}
|
|
212
209
|
|
|
213
210
|
{disableAddModal || !model.ModalAddComponent ? null : (
|
|
214
211
|
<Button
|
|
215
212
|
type="primary"
|
|
216
|
-
size=
|
|
213
|
+
size="small"
|
|
217
214
|
onClick={() => {
|
|
218
215
|
setSelectedRecord({}); // empty record for creation
|
|
219
216
|
setDrawerTitle('Create New Menu');
|
|
@@ -244,18 +241,20 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
244
241
|
className="custom-panel"
|
|
245
242
|
header={
|
|
246
243
|
<DraggableWrapper
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
244
|
+
id={item.id}
|
|
245
|
+
index={index}
|
|
246
|
+
movePanel={(from, to) => {
|
|
247
|
+
if (!dragMode) return;
|
|
248
|
+
|
|
249
|
+
const updated = [...records];
|
|
250
|
+
const [moved] = updated.splice(from, 1);
|
|
251
|
+
updated.splice(to, 0, moved);
|
|
252
|
+
|
|
253
|
+
setRecords(updated);
|
|
254
|
+
setOrderChanged(true); // <-- mark as changed
|
|
255
|
+
}}
|
|
256
|
+
title={item.name}
|
|
257
|
+
dragEnabled={dragMode} // pass dragMode to wrapper
|
|
259
258
|
/>
|
|
260
259
|
}
|
|
261
260
|
extra={panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord)}
|
|
@@ -264,10 +263,16 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
264
263
|
parentId={item.id}
|
|
265
264
|
step={step + 1}
|
|
266
265
|
model={model}
|
|
266
|
+
dragMode={dragMode}
|
|
267
267
|
setSelectedRecord={setSelectedRecord}
|
|
268
268
|
setDrawerTitle={setDrawerTitle}
|
|
269
269
|
setDrawerVisible={setDrawerVisible}
|
|
270
270
|
deleteRecord={deleteRecord}
|
|
271
|
+
onChange={(subMenus) => {
|
|
272
|
+
const updated = records.map((r) => (r.id === item.id ? { ...r, sub_menus: subMenus } : r));
|
|
273
|
+
setRecords(updated);
|
|
274
|
+
setOrderChanged(true);
|
|
275
|
+
}}
|
|
271
276
|
/>
|
|
272
277
|
</Panel>
|
|
273
278
|
))}
|
|
@@ -319,7 +324,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
319
324
|
setSelectedRecord({
|
|
320
325
|
header_id: item.id, // parent menu id
|
|
321
326
|
step: item.step + 1,
|
|
322
|
-
id: null,
|
|
327
|
+
id: null, // new record
|
|
323
328
|
});
|
|
324
329
|
setDrawerTitle(`Add Submenu to "${item.name}"`);
|
|
325
330
|
setDrawerVisible(true);
|
|
@@ -332,6 +337,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
332
337
|
{model.ModalAddComponent && (
|
|
333
338
|
<Button
|
|
334
339
|
size="small"
|
|
340
|
+
type="default"
|
|
335
341
|
onClick={() => {
|
|
336
342
|
setSelectedRecord(item);
|
|
337
343
|
setDrawerTitle('Edit Menu');
|
|
@@ -344,6 +350,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
344
350
|
|
|
345
351
|
<Button
|
|
346
352
|
size="small"
|
|
353
|
+
type="default"
|
|
347
354
|
onClick={() => {
|
|
348
355
|
setSelectedRecord({ ...item, id: null, copy: true });
|
|
349
356
|
setDrawerTitle('Copy Menu');
|
|
@@ -354,7 +361,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
354
361
|
</Button>
|
|
355
362
|
|
|
356
363
|
<Popconfirm title="Are you sure?" onConfirm={() => deleteRecord(item)}>
|
|
357
|
-
<Button danger size="small">
|
|
364
|
+
<Button danger size="small" type="default">
|
|
358
365
|
<DeleteOutlined />
|
|
359
366
|
</Button>
|
|
360
367
|
</Popconfirm>
|
|
@@ -365,11 +372,27 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
365
372
|
// ------------------------
|
|
366
373
|
// NestedMenu: Pass sub_menus recursively
|
|
367
374
|
// ------------------------
|
|
368
|
-
|
|
375
|
+
// ------------------------
|
|
376
|
+
|
|
377
|
+
function NestedMenu({
|
|
378
|
+
parentId,
|
|
379
|
+
step,
|
|
380
|
+
model,
|
|
381
|
+
dragMode,
|
|
382
|
+
|
|
383
|
+
setSelectedRecord,
|
|
384
|
+
setDrawerTitle,
|
|
385
|
+
setDrawerVisible,
|
|
386
|
+
deleteRecord,
|
|
387
|
+
onChange, // callback to propagate changes to parent
|
|
388
|
+
}) {
|
|
369
389
|
const [items, setItems] = useState([]);
|
|
370
390
|
const [loading, setLoading] = useState(true);
|
|
371
391
|
|
|
392
|
+
// Load child menus
|
|
393
|
+
// NestedMenu
|
|
372
394
|
useEffect(() => {
|
|
395
|
+
setLoading(true);
|
|
373
396
|
model
|
|
374
397
|
.get({
|
|
375
398
|
queries: [
|
|
@@ -378,18 +401,25 @@ function NestedMenu({ parentId, step, model, setSelectedRecord, setDrawerTitle,
|
|
|
378
401
|
],
|
|
379
402
|
})
|
|
380
403
|
.then((res) => {
|
|
381
|
-
const
|
|
382
|
-
|
|
404
|
+
const sortedMenus = (res.result || [])
|
|
405
|
+
.sort((a, b) => a.order - b.order) // sort top-level in this submenu
|
|
406
|
+
.map((menu) => ({
|
|
407
|
+
...menu,
|
|
408
|
+
sub_menus: menu.sub_menus ? menu.sub_menus.sort((a, b) => a.order - b.order) : [],
|
|
409
|
+
}));
|
|
410
|
+
setItems(sortedMenus);
|
|
383
411
|
setLoading(false);
|
|
384
412
|
})
|
|
385
413
|
.catch(() => setLoading(false));
|
|
386
|
-
}, [parentId]);
|
|
414
|
+
}, [parentId, step]);
|
|
387
415
|
|
|
416
|
+
// Move submenu
|
|
388
417
|
const moveSubMenu = (from, to) => {
|
|
389
418
|
const updated = [...items];
|
|
390
419
|
const [moved] = updated.splice(from, 1);
|
|
391
420
|
updated.splice(to, 0, moved);
|
|
392
421
|
setItems(updated);
|
|
422
|
+
onChange?.(updated); // propagate to parent
|
|
393
423
|
};
|
|
394
424
|
|
|
395
425
|
if (loading) return <Skeleton active />;
|
|
@@ -404,24 +434,31 @@ function NestedMenu({ parentId, step, model, setSelectedRecord, setDrawerTitle,
|
|
|
404
434
|
<DraggableWrapper
|
|
405
435
|
id={child.id}
|
|
406
436
|
index={index}
|
|
407
|
-
movePanel={
|
|
437
|
+
movePanel={(from, to) => {
|
|
438
|
+
if (!dragMode) return; // block drag when OFF
|
|
439
|
+
moveSubMenu(from, to);
|
|
440
|
+
}}
|
|
408
441
|
title={child.name}
|
|
409
|
-
dragEnabled={
|
|
442
|
+
dragEnabled={dragMode}
|
|
410
443
|
/>
|
|
411
444
|
}
|
|
412
445
|
extra={panelActions(child, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord)}
|
|
413
446
|
>
|
|
414
|
-
{
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
447
|
+
{/* Recursively render submenus */}
|
|
448
|
+
<NestedMenu
|
|
449
|
+
parentId={child.id}
|
|
450
|
+
step={step + 1}
|
|
451
|
+
model={model}
|
|
452
|
+
setSelectedRecord={setSelectedRecord}
|
|
453
|
+
setDrawerTitle={setDrawerTitle}
|
|
454
|
+
setDrawerVisible={setDrawerVisible}
|
|
455
|
+
deleteRecord={deleteRecord}
|
|
456
|
+
onChange={(submenus) => {
|
|
457
|
+
const updated = items.map((item) => (item.id === child.id ? { ...item, sub_menus: submenus } : item));
|
|
458
|
+
setItems(updated);
|
|
459
|
+
onChange?.(updated);
|
|
460
|
+
}}
|
|
461
|
+
/>
|
|
425
462
|
</Panel>
|
|
426
463
|
))}
|
|
427
464
|
</Collapse>
|
|
@@ -38,4 +38,13 @@
|
|
|
38
38
|
padding: 10px 14px;
|
|
39
39
|
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
|
40
40
|
}
|
|
41
|
+
/* OFF state */
|
|
42
|
+
.custom-switch.ant-switch {
|
|
43
|
+
background-color: #bfbfbf !important; /* gray */
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ON state */
|
|
47
|
+
.custom-switch.ant-switch-checked {
|
|
48
|
+
background-color: #446AA9 !important; /* blue */
|
|
49
|
+
}
|
|
41
50
|
|