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
@@ -1,14 +1,14 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
- import { Typography, Modal, Space, Switch, Popconfirm, Skeleton, Input, Drawer, Collapse, Button, Card } from 'antd';
3
- import { ReloadOutlined, OrderedListOutlined, PicCenterOutlined, DeleteOutlined, EditOutlined, CopyOutlined, PlusCircleFilled } from '@ant-design/icons';
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
- // ... existing states
41
- const [dragMode, setDragMode] = useState(true); // NEW STATE
40
+ // DEFAULT DRAG MODE: OFF
41
+ const [dragMode, setDragMode] = useState(false); // for drag (default OFF)
42
42
 
43
- const toggleDragMode = (checked) => setDragMode(checked);
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
- setView(result);
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
- setRecords(res.result || []);
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
- return menus.map((menu, index) => {
129
- const payload = {
130
- id: menu.id,
131
- order: index + 1,
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 payload;
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
- .post('/update-order', payload) // Adjust endpoint to your backend
149
- .then(() => {
150
- message.success('Order saved successfully');
151
- loadMenus(); // reload menus with new order
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
- message.error('Failed to save order');
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
- <Switch
195
- checked={dragMode}
196
- onChange={toggleDragMode}
197
- checkedChildren="Order On"
198
- unCheckedChildren="Order Off"
199
- />
200
-
201
- {dragMode && (
202
- <Button
203
- type="primary"
204
- size="small"
205
- // onClick={saveOrder}
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='small'
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
- id={item.id}
248
- index={index}
249
- movePanel={(from, to) => {
250
- if (!dragMode) return; // prevent moving if drag mode off
251
- const updated = [...filtered];
252
- const [moved] = updated.splice(from, 1);
253
- updated.splice(to, 0, moved);
254
- setRecords(updated);
255
- }}
256
- title={item.name}
257
- dragEnabled={dragMode} // pass dragMode to wrapper
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, // new record
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
- function NestedMenu({ parentId, step, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord }) {
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 menusWithSub = res.result.map((menu) => ({ ...menu, sub_menus: [] }));
382
- setItems(menusWithSub || []);
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={moveSubMenu}
437
+ movePanel={(from, to) => {
438
+ if (!dragMode) return; // block drag when OFF
439
+ moveSubMenu(from, to);
440
+ }}
408
441
  title={child.name}
409
- dragEnabled={true}
442
+ dragEnabled={dragMode}
410
443
  />
411
444
  }
412
445
  extra={panelActions(child, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord)}
413
446
  >
414
- {child.hasChildren && (
415
- <NestedMenu
416
- parentId={child.id}
417
- step={step + 1}
418
- model={model}
419
- setSelectedRecord={setSelectedRecord}
420
- setDrawerTitle={setDrawerTitle}
421
- setDrawerVisible={setDrawerVisible}
422
- deleteRecord={deleteRecord}
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