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.
- 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/dragabble-wrapper/draggable-wrapper.js +119 -42
- package/core/lib/elements/basic/rangepicker/rangepicker.js +118 -29
- package/core/lib/elements/basic/switch/switch.js +35 -25
- 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 +220 -267
- package/core/models/menus/components/menu-lists/menu-lists.js +366 -211
- package/core/models/menus/components/menu-lists/menu-lists.scss +6 -2
- package/core/models/menus/menus.js +256 -267
- package/core/models/roles/components/role-add/role-add.js +265 -228
- package/core/models/roles/components/role-list/role-list.js +326 -348
- package/core/models/roles/roles.js +191 -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 +723 -367
- 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,13 @@
|
|
|
1
|
-
import React, { useState,
|
|
2
|
-
import {
|
|
3
|
-
import { ReloadOutlined,
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { Space, Popconfirm, Input, Drawer, Skeleton, Collapse, message } from 'antd';
|
|
3
|
+
import { ReloadOutlined, DeleteOutlined, EditOutlined, PlusCircleFilled, CopyOutlined } from '@ant-design/icons';
|
|
4
|
+
import { Button, Card, Switch, DraggableWrapper } from '../../../../lib';
|
|
7
5
|
// for draggable menu list import { DndProvider } from "react-dnd";
|
|
8
6
|
import { DndProvider } from 'react-dnd';
|
|
7
|
+
import { Link, useParams, useLocation } from 'react-router-dom';
|
|
9
8
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
10
|
-
|
|
11
|
-
import './menu-lists.scss'
|
|
9
|
+
|
|
10
|
+
import './menu-lists.scss';
|
|
12
11
|
|
|
13
12
|
const { Search } = Input;
|
|
14
13
|
const { Panel } = Collapse;
|
|
@@ -18,34 +17,45 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
18
17
|
|
|
19
18
|
match = useParams();
|
|
20
19
|
const id = match.id;
|
|
21
|
-
const location = useLocation();
|
|
22
|
-
|
|
20
|
+
// const location = useLocation();
|
|
23
21
|
const step = parseInt(new URLSearchParams(location.search).get('step')) || 1;
|
|
24
22
|
|
|
25
23
|
const [records, setRecords] = useState([]);
|
|
24
|
+
const [originalRecords, setOriginalRecords] = useState([]);
|
|
26
25
|
const [loading, setLoading] = useState(false);
|
|
27
|
-
|
|
28
26
|
const [drawerVisible, setDrawerVisible] = useState(false);
|
|
29
|
-
|
|
30
|
-
const [view, setView] = useState(false);
|
|
31
|
-
|
|
32
|
-
const [visible, setVisible] = useState(false);
|
|
33
|
-
|
|
34
27
|
const [single, setSingle] = useState({});
|
|
35
28
|
const [drawerTitle, setDrawerTitle] = useState('');
|
|
36
29
|
const [selectedRecord, setSelectedRecord] = useState(null);
|
|
37
|
-
|
|
38
30
|
const [query, setQuery] = useState('');
|
|
31
|
+
const [dragMode, setDragMode] = useState(false);
|
|
32
|
+
const [orderChanged, setOrderChanged] = useState(false);
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
const [dragMode, setDragMode] = useState(true); // NEW STATE
|
|
42
|
-
|
|
43
|
-
const toggleDragMode = (checked) => setDragMode(checked);
|
|
44
|
-
|
|
34
|
+
const [nextId, setNextId] = useState(10000);
|
|
45
35
|
|
|
46
36
|
useEffect(() => {
|
|
47
37
|
loadMenus();
|
|
48
38
|
}, [id]);
|
|
39
|
+
|
|
40
|
+
const loadMenus = () => {
|
|
41
|
+
setLoading(true);
|
|
42
|
+
|
|
43
|
+
model
|
|
44
|
+
.getCoreMenuLists
|
|
45
|
+
// {
|
|
46
|
+
// queries: [...additional_queries, { field: 'step', value: step }, { field: 'header_id', value: null }],
|
|
47
|
+
// }
|
|
48
|
+
()
|
|
49
|
+
.then((res) => {
|
|
50
|
+
const sorted = (res.result || []).sort((a, b) => a.order - b.order);
|
|
51
|
+
setRecords(sorted);
|
|
52
|
+
setOriginalRecords(sorted);
|
|
53
|
+
setLoading(false);
|
|
54
|
+
})
|
|
55
|
+
.catch(() => setLoading(false));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
console.log('record', records);
|
|
49
59
|
/**
|
|
50
60
|
*
|
|
51
61
|
*/
|
|
@@ -79,7 +89,7 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
79
89
|
var result = res.result;
|
|
80
90
|
|
|
81
91
|
if (Array.isArray(result)) {
|
|
82
|
-
setRecords(result);
|
|
92
|
+
setRecords(result.sort((a, b) => a.order - b.order));
|
|
83
93
|
// } else {
|
|
84
94
|
// setRecords([])
|
|
85
95
|
}
|
|
@@ -93,195 +103,321 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
93
103
|
});
|
|
94
104
|
};
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
const toggleDragMode = (checked) => {
|
|
107
|
+
setDragMode(checked);
|
|
108
|
+
if (checked) {
|
|
109
|
+
message.info('Drag mode enabled - Drag items anywhere, including the "Drop here" zones!');
|
|
110
|
+
}
|
|
111
|
+
};
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
// Function to find and remove an item from anywhere in the tree
|
|
114
|
+
const findAndRemoveItem = (items, itemId) => {
|
|
115
|
+
let foundItem = null;
|
|
116
|
+
|
|
117
|
+
const removeRecursive = (arr) => {
|
|
118
|
+
for (let i = 0; i < arr.length; i++) {
|
|
119
|
+
if (arr[i].id === itemId) {
|
|
120
|
+
foundItem = { ...arr[i] };
|
|
121
|
+
arr.splice(i, 1);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (arr[i].sub_menus && arr[i].sub_menus.length > 0) {
|
|
125
|
+
if (removeRecursive(arr[i].sub_menus)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const newItems = JSON.parse(JSON.stringify(items));
|
|
134
|
+
removeRecursive(newItems);
|
|
135
|
+
return { newItems, foundItem };
|
|
111
136
|
};
|
|
112
137
|
|
|
138
|
+
// Function to insert item at specific location
|
|
139
|
+
const insertItemAt = (items, item, targetLevel, targetParentId, targetIndex) => {
|
|
140
|
+
const newItems = JSON.parse(JSON.stringify(items));
|
|
141
|
+
|
|
142
|
+
// Update item properties for new location
|
|
143
|
+
const updatedItem = {
|
|
144
|
+
...item,
|
|
145
|
+
step: targetLevel,
|
|
146
|
+
header_id: targetParentId,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (targetLevel === 1) {
|
|
150
|
+
// Insert at main level
|
|
151
|
+
newItems.splice(targetIndex, 0, updatedItem);
|
|
152
|
+
} else {
|
|
153
|
+
// Insert into nested level
|
|
154
|
+
const insertRecursive = (arr) => {
|
|
155
|
+
for (let i = 0; i < arr.length; i++) {
|
|
156
|
+
if (arr[i].id === targetParentId) {
|
|
157
|
+
if (!arr[i].sub_menus) arr[i].sub_menus = [];
|
|
158
|
+
arr[i].sub_menus.splice(targetIndex, 0, updatedItem);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (arr[i].sub_menus && arr[i].sub_menus.length > 0) {
|
|
162
|
+
if (insertRecursive(arr[i].sub_menus)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return false;
|
|
168
|
+
};
|
|
169
|
+
insertRecursive(newItems);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return newItems;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const handleCrossLevelMove = useCallback(
|
|
176
|
+
(draggedItem, dropTarget) => {
|
|
177
|
+
const { targetLevel, targetParentId, targetIndex } = dropTarget;
|
|
178
|
+
|
|
179
|
+
// Prevent moving item into itself or its children
|
|
180
|
+
if (draggedItem.id === targetParentId) {
|
|
181
|
+
message.warning('Cannot move item into itself');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Remove item from original location
|
|
186
|
+
const { newItems: itemsAfterRemove, foundItem } = findAndRemoveItem(records, draggedItem.id);
|
|
187
|
+
|
|
188
|
+
if (!foundItem) {
|
|
189
|
+
message.error('Could not find item to move');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Insert item at new location
|
|
194
|
+
const finalItems = insertItemAt(itemsAfterRemove, foundItem, targetLevel, targetParentId, targetIndex);
|
|
195
|
+
|
|
196
|
+
setRecords(finalItems);
|
|
197
|
+
setOrderChanged(true);
|
|
198
|
+
message.success(`Moved "${foundItem.name}" to level ${targetLevel}`);
|
|
199
|
+
},
|
|
200
|
+
[records]
|
|
201
|
+
);
|
|
202
|
+
|
|
113
203
|
const deleteRecord = (rec) => {
|
|
114
204
|
model.delete(rec).then(loadMenus);
|
|
115
205
|
};
|
|
116
206
|
|
|
117
|
-
const filtered = records.filter((r) => r.name?.toUpperCase().includes(query.toUpperCase()));
|
|
118
|
-
|
|
119
|
-
|
|
207
|
+
const filtered = records.filter((r) => r.name?.toUpperCase().includes(query.toUpperCase()));
|
|
208
|
+
|
|
209
|
+
const visibleItems = dragMode ? records : filtered;
|
|
210
|
+
|
|
120
211
|
const onSearch = (event) => {
|
|
121
|
-
setQuery(event.target.value);
|
|
212
|
+
setQuery(event.target.value);
|
|
122
213
|
};
|
|
123
214
|
|
|
124
215
|
// ------------------------
|
|
125
216
|
// Recursive function to build payload
|
|
126
217
|
// ------------------------
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
const payload = {
|
|
130
|
-
id: menu.id,
|
|
131
|
-
order: index + 1,
|
|
132
|
-
};
|
|
218
|
+
const buildUpdatedOrderPayload = (menus, originalMenus) => {
|
|
219
|
+
const result = [];
|
|
133
220
|
|
|
134
|
-
|
|
135
|
-
|
|
221
|
+
menus.forEach((menu, index) => {
|
|
222
|
+
const original = findMenuById(originalMenus, menu.id);
|
|
223
|
+
|
|
224
|
+
const newOrder = index + 1;
|
|
225
|
+
const oldOrder = original ? original.order : null;
|
|
226
|
+
|
|
227
|
+
const orderChanged = oldOrder !== newOrder;
|
|
228
|
+
const parentChanged = original?.header_id !== menu.header_id;
|
|
229
|
+
|
|
230
|
+
// check sub menus
|
|
231
|
+
let updatedSubMenus = [];
|
|
232
|
+
if (menu.sub_menus?.length) {
|
|
233
|
+
updatedSubMenus = buildUpdatedOrderPayload(menu.sub_menus, originalMenus);
|
|
136
234
|
}
|
|
137
235
|
|
|
138
|
-
|
|
236
|
+
// include only if changed OR has changed children
|
|
237
|
+
if (orderChanged || parentChanged || updatedSubMenus.length) {
|
|
238
|
+
result.push({
|
|
239
|
+
id: menu.id,
|
|
240
|
+
order: newOrder,
|
|
241
|
+
header_id: menu.header_id,
|
|
242
|
+
name: menu.name,
|
|
243
|
+
...(updatedSubMenus.length && { sub_menus: updatedSubMenus }),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
139
246
|
});
|
|
247
|
+
|
|
248
|
+
return result;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// ------------------------
|
|
252
|
+
// Find menu by id (recursive)
|
|
253
|
+
// ------------------------
|
|
254
|
+
const findMenuById = (menus, id) => {
|
|
255
|
+
for (const menu of menus || []) {
|
|
256
|
+
if (menu.id === id) return menu;
|
|
257
|
+
|
|
258
|
+
if (menu.sub_menus?.length) {
|
|
259
|
+
const found = findMenuById(menu.sub_menus, id);
|
|
260
|
+
if (found) return found;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
140
264
|
};
|
|
141
265
|
|
|
142
266
|
// ------------------------
|
|
143
267
|
// Save order function
|
|
144
268
|
// ------------------------
|
|
145
269
|
const saveOrder = () => {
|
|
146
|
-
const
|
|
270
|
+
const updatedMenus = buildUpdatedOrderPayload(records, originalRecords);
|
|
271
|
+
|
|
272
|
+
if (!updatedMenus.length) {
|
|
273
|
+
message.info('No order changes to save');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const payload = { menus: updatedMenus };
|
|
278
|
+
|
|
147
279
|
model
|
|
148
|
-
.
|
|
280
|
+
.saveOrder({ formBody: payload })
|
|
149
281
|
.then(() => {
|
|
150
|
-
|
|
151
|
-
loadMenus(); //
|
|
282
|
+
setOrderChanged(false);
|
|
283
|
+
loadMenus(); // refresh from backend
|
|
152
284
|
})
|
|
153
|
-
.catch(
|
|
154
|
-
console.error(err);
|
|
155
|
-
message.error('Failed to save order');
|
|
156
|
-
});
|
|
285
|
+
.catch(console.error);
|
|
157
286
|
};
|
|
158
287
|
|
|
288
|
+
const movePanel = useCallback(
|
|
289
|
+
(from, to) => {
|
|
290
|
+
if (!dragMode) return;
|
|
291
|
+
if (from === to) return;
|
|
159
292
|
|
|
293
|
+
setRecords((prevRecords) => {
|
|
294
|
+
const updated = [...prevRecords];
|
|
295
|
+
const [moved] = updated.splice(from, 1);
|
|
296
|
+
updated.splice(to, 0, moved);
|
|
297
|
+
return updated;
|
|
298
|
+
});
|
|
160
299
|
|
|
300
|
+
setOrderChanged(true);
|
|
301
|
+
},
|
|
302
|
+
[dragMode]
|
|
303
|
+
);
|
|
161
304
|
|
|
162
305
|
return (
|
|
163
306
|
<Card className="generic-list">
|
|
164
|
-
<div
|
|
165
|
-
<div
|
|
307
|
+
<div style={{ marginBottom: 16 }}>
|
|
308
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
|
166
309
|
<Search placeholder="Enter Search Value" allowClear style={{ width: 300, marginBottom: '0px' }} onChange={onSearch} />
|
|
167
|
-
{/* <Title level={4}>{model.name}</Title> */}
|
|
168
310
|
|
|
169
|
-
|
|
311
|
+
<Space size="small">
|
|
312
|
+
<Button onClick={getRecords} size={'small'} type="default">
|
|
313
|
+
<ReloadOutlined />
|
|
314
|
+
</Button>
|
|
315
|
+
|
|
316
|
+
<Switch checked={dragMode} onChange={toggleDragMode} checkedChildren="Order On" unCheckedChildren="Order Off" />
|
|
317
|
+
|
|
318
|
+
{dragMode && orderChanged && (
|
|
319
|
+
<Button onClick={saveOrder} type="primary" size="small">
|
|
320
|
+
Save Order
|
|
321
|
+
</Button>
|
|
322
|
+
)}
|
|
323
|
+
|
|
324
|
+
<Button
|
|
325
|
+
type="primary"
|
|
326
|
+
size="small"
|
|
327
|
+
onClick={() => {
|
|
328
|
+
setSelectedRecord({ step: 1, header_id: null });
|
|
329
|
+
setDrawerTitle('Create New Menu');
|
|
330
|
+
setDrawerVisible(true);
|
|
331
|
+
}}
|
|
332
|
+
>
|
|
333
|
+
Create New Menu
|
|
334
|
+
</Button>
|
|
335
|
+
</Space>
|
|
170
336
|
</div>
|
|
171
337
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
onChange={changeView}
|
|
189
|
-
checked={view}
|
|
190
|
-
checkedChildren={<OrderedListOutlined />}
|
|
191
|
-
unCheckedChildren={<PicCenterOutlined />}
|
|
192
|
-
/> */}
|
|
193
|
-
{/* 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
|
-
|
|
212
|
-
|
|
213
|
-
{disableAddModal || !model.ModalAddComponent ? null : (
|
|
214
|
-
<Button
|
|
215
|
-
type="primary"
|
|
216
|
-
size='small'
|
|
217
|
-
onClick={() => {
|
|
218
|
-
setSelectedRecord({}); // empty record for creation
|
|
219
|
-
setDrawerTitle('Create New Menu');
|
|
220
|
-
setDrawerVisible(true); // this controls Drawer visibility
|
|
221
|
-
}}
|
|
222
|
-
>
|
|
223
|
-
Create New Menu
|
|
224
|
-
</Button>
|
|
225
|
-
)}
|
|
226
|
-
</Space>
|
|
227
|
-
</div>
|
|
338
|
+
{dragMode && (
|
|
339
|
+
<div
|
|
340
|
+
style={{
|
|
341
|
+
padding: '8px 12px',
|
|
342
|
+
backgroundColor: '#e6f7ff',
|
|
343
|
+
borderRadius: 4,
|
|
344
|
+
border: '1px solid #91d5ff',
|
|
345
|
+
fontSize: 13,
|
|
346
|
+
}}
|
|
347
|
+
>
|
|
348
|
+
<strong>💡 Tips:</strong>
|
|
349
|
+
<ul style={{ margin: '4px 0', paddingLeft: 20 }}>
|
|
350
|
+
<li>Drag between items to reorder at the same level</li>
|
|
351
|
+
<li>Drop on the green "↳ Drop here" zone to make it a child of that item</li>
|
|
352
|
+
<li>Works at all levels - unlimited nesting supported!</li>
|
|
353
|
+
</ul>
|
|
228
354
|
</div>
|
|
229
|
-
|
|
355
|
+
)}
|
|
230
356
|
</div>
|
|
231
|
-
|
|
232
357
|
{loading ? (
|
|
233
358
|
<Skeleton active />
|
|
234
359
|
) : (
|
|
235
360
|
<>
|
|
236
361
|
<>
|
|
237
|
-
{!view ? (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
362
|
+
{/* {!view ? ( */}
|
|
363
|
+
<Card>
|
|
364
|
+
<DndProvider backend={HTML5Backend}>
|
|
365
|
+
<Collapse accordion>
|
|
366
|
+
{visibleItems.map((item, index) => (
|
|
367
|
+
<Panel
|
|
368
|
+
key={item.id}
|
|
369
|
+
header={
|
|
370
|
+
<DraggableWrapper
|
|
371
|
+
id={item.id}
|
|
372
|
+
index={index}
|
|
373
|
+
movePanel={movePanel}
|
|
374
|
+
item={item}
|
|
375
|
+
dragEnabled={dragMode}
|
|
376
|
+
level={1}
|
|
377
|
+
parentId={null}
|
|
378
|
+
onCrossLevelMove={handleCrossLevelMove}
|
|
379
|
+
canAcceptChildren={true}
|
|
380
|
+
/>
|
|
381
|
+
}
|
|
382
|
+
// only show arrow if sub_menus exist
|
|
383
|
+
showArrow={item.sub_menus && item.sub_menus.length > 0}
|
|
384
|
+
// disable panel
|
|
385
|
+
collapsible={item.sub_menus && item.sub_menus.length > 0 ? 'header' : 'disabled'}
|
|
386
|
+
extra={panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord)}
|
|
387
|
+
>
|
|
388
|
+
{item.sub_menus && item.sub_menus.length > 0 && (
|
|
263
389
|
<NestedMenu
|
|
264
390
|
parentId={item.id}
|
|
265
|
-
step={step + 1}
|
|
391
|
+
step={item.step + 1}
|
|
392
|
+
items={item.sub_menus || []}
|
|
266
393
|
model={model}
|
|
394
|
+
dragMode={dragMode}
|
|
267
395
|
setSelectedRecord={setSelectedRecord}
|
|
268
396
|
setDrawerTitle={setDrawerTitle}
|
|
269
397
|
setDrawerVisible={setDrawerVisible}
|
|
270
398
|
deleteRecord={deleteRecord}
|
|
399
|
+
level={2}
|
|
400
|
+
onCrossLevelMove={handleCrossLevelMove}
|
|
401
|
+
onChange={(subMenus) => {
|
|
402
|
+
const updated = records.map((r) => (r.id === item.id ? { ...r, sub_menus: subMenus } : r));
|
|
403
|
+
setRecords(updated);
|
|
404
|
+
setOrderChanged(true);
|
|
405
|
+
}}
|
|
271
406
|
/>
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
</
|
|
276
|
-
</
|
|
277
|
-
|
|
407
|
+
)}
|
|
408
|
+
</Panel>
|
|
409
|
+
))}
|
|
410
|
+
</Collapse>
|
|
411
|
+
</DndProvider>
|
|
412
|
+
</Card>
|
|
413
|
+
{/* ) : (
|
|
278
414
|
<CardList model={model} data={filtered ? filtered : records} />
|
|
279
|
-
)}
|
|
415
|
+
)} */}
|
|
280
416
|
</>
|
|
281
417
|
</>
|
|
282
418
|
)}
|
|
283
|
-
|
|
284
|
-
<Drawer title={drawerTitle} open={drawerVisible} width="
|
|
419
|
+
|
|
420
|
+
<Drawer title={drawerTitle} open={drawerVisible} width="80%" destroyOnClose onClose={() => setDrawerVisible(false)}>
|
|
285
421
|
{model.ModalAddComponent && (
|
|
286
422
|
<model.ModalAddComponent
|
|
287
423
|
formContent={selectedRecord}
|
|
@@ -298,15 +434,8 @@ const MenuLists = ({ model, match, relativeAdd = false, additional_queries = [],
|
|
|
298
434
|
</Card>
|
|
299
435
|
);
|
|
300
436
|
};
|
|
301
|
-
function CardList({ model, data, url, ...props }) {
|
|
302
|
-
return data.map((record, index) => {
|
|
303
|
-
return <model.Card record={record} model={model} index={index} key={index} {...record} {...props} />;
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
export default MenuLists;
|
|
307
|
-
|
|
308
437
|
/* -----------------------------------------------------------------------
|
|
309
|
-
PANEL ACTIONS
|
|
438
|
+
PANEL ACTIONS
|
|
310
439
|
------------------------------------------------------------------------ */
|
|
311
440
|
function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord) {
|
|
312
441
|
return (
|
|
@@ -317,21 +446,24 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
317
446
|
type="dashed"
|
|
318
447
|
onClick={() => {
|
|
319
448
|
setSelectedRecord({
|
|
320
|
-
|
|
449
|
+
// parent menu id
|
|
450
|
+
header_id: item.id,
|
|
321
451
|
step: item.step + 1,
|
|
322
|
-
|
|
452
|
+
// new record
|
|
453
|
+
id: null,
|
|
323
454
|
});
|
|
324
455
|
setDrawerTitle(`Add Submenu to "${item.name}"`);
|
|
325
456
|
setDrawerVisible(true);
|
|
326
457
|
}}
|
|
327
458
|
>
|
|
328
459
|
<PlusCircleFilled />
|
|
329
|
-
|
|
460
|
+
Add Sub Menu
|
|
330
461
|
</Button>
|
|
331
462
|
|
|
332
463
|
{model.ModalAddComponent && (
|
|
333
464
|
<Button
|
|
334
465
|
size="small"
|
|
466
|
+
type="default"
|
|
335
467
|
onClick={() => {
|
|
336
468
|
setSelectedRecord(item);
|
|
337
469
|
setDrawerTitle('Edit Menu');
|
|
@@ -344,6 +476,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
344
476
|
|
|
345
477
|
<Button
|
|
346
478
|
size="small"
|
|
479
|
+
type="default"
|
|
347
480
|
onClick={() => {
|
|
348
481
|
setSelectedRecord({ ...item, id: null, copy: true });
|
|
349
482
|
setDrawerTitle('Copy Menu');
|
|
@@ -354,7 +487,7 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
354
487
|
</Button>
|
|
355
488
|
|
|
356
489
|
<Popconfirm title="Are you sure?" onConfirm={() => deleteRecord(item)}>
|
|
357
|
-
<Button danger size="small">
|
|
490
|
+
<Button danger size="small" type="default">
|
|
358
491
|
<DeleteOutlined />
|
|
359
492
|
</Button>
|
|
360
493
|
</Popconfirm>
|
|
@@ -362,42 +495,50 @@ function panelActions(item, model, setSelectedRecord, setDrawerTitle, setDrawerV
|
|
|
362
495
|
);
|
|
363
496
|
}
|
|
364
497
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
498
|
+
function NestedMenu({
|
|
499
|
+
parentId,
|
|
500
|
+
step,
|
|
501
|
+
items,
|
|
502
|
+
model,
|
|
503
|
+
dragMode,
|
|
504
|
+
setSelectedRecord,
|
|
505
|
+
setDrawerTitle,
|
|
506
|
+
setDrawerVisible,
|
|
507
|
+
deleteRecord,
|
|
508
|
+
level,
|
|
509
|
+
onCrossLevelMove,
|
|
510
|
+
onChange,
|
|
511
|
+
}) {
|
|
512
|
+
// do not render Collapse
|
|
513
|
+
if (!items || items.length === 0) return null;
|
|
514
|
+
|
|
515
|
+
const [localItems, setLocalItems] = useState(items);
|
|
371
516
|
|
|
372
517
|
useEffect(() => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
queries: [
|
|
376
|
-
{ field: 'header_id', value: parentId },
|
|
377
|
-
{ field: 'step', value: step },
|
|
378
|
-
],
|
|
379
|
-
})
|
|
380
|
-
.then((res) => {
|
|
381
|
-
const menusWithSub = res.result.map((menu) => ({ ...menu, sub_menus: [] }));
|
|
382
|
-
setItems(menusWithSub || []);
|
|
383
|
-
setLoading(false);
|
|
384
|
-
})
|
|
385
|
-
.catch(() => setLoading(false));
|
|
386
|
-
}, [parentId]);
|
|
518
|
+
setLocalItems(items);
|
|
519
|
+
}, [items]);
|
|
387
520
|
|
|
388
|
-
const moveSubMenu = (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
521
|
+
const moveSubMenu = useCallback(
|
|
522
|
+
(from, to) => {
|
|
523
|
+
if (!dragMode || from === to) return;
|
|
524
|
+
|
|
525
|
+
const updated = [...localItems];
|
|
526
|
+
const [moved] = updated.splice(from, 1);
|
|
527
|
+
updated.splice(to, 0, moved);
|
|
394
528
|
|
|
395
|
-
|
|
396
|
-
|
|
529
|
+
setLocalItems(updated);
|
|
530
|
+
onChange?.(updated);
|
|
531
|
+
},
|
|
532
|
+
[dragMode, localItems, onChange]
|
|
533
|
+
);
|
|
534
|
+
if (!localItems || localItems.length === 0) {
|
|
535
|
+
// <-- don’t render anything if no submenus
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
397
538
|
|
|
398
539
|
return (
|
|
399
|
-
<Collapse accordion
|
|
400
|
-
{
|
|
540
|
+
<Collapse accordion>
|
|
541
|
+
{localItems.map((child, index) => (
|
|
401
542
|
<Panel
|
|
402
543
|
key={child.id}
|
|
403
544
|
header={
|
|
@@ -405,25 +546,39 @@ function NestedMenu({ parentId, step, model, setSelectedRecord, setDrawerTitle,
|
|
|
405
546
|
id={child.id}
|
|
406
547
|
index={index}
|
|
407
548
|
movePanel={moveSubMenu}
|
|
408
|
-
|
|
409
|
-
dragEnabled={
|
|
549
|
+
item={child}
|
|
550
|
+
dragEnabled={dragMode}
|
|
551
|
+
level={level}
|
|
552
|
+
parentId={parentId}
|
|
553
|
+
onCrossLevelMove={onCrossLevelMove}
|
|
554
|
+
canAcceptChildren={true}
|
|
410
555
|
/>
|
|
411
556
|
}
|
|
557
|
+
// only show arrow if sub_menus exist
|
|
558
|
+
showArrow={child.sub_menus && child.sub_menus.length > 0}
|
|
412
559
|
extra={panelActions(child, model, setSelectedRecord, setDrawerTitle, setDrawerVisible, deleteRecord)}
|
|
413
560
|
>
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
561
|
+
<NestedMenu
|
|
562
|
+
parentId={child.id}
|
|
563
|
+
step={step + 1}
|
|
564
|
+
items={child.sub_menus || []}
|
|
565
|
+
dragMode={dragMode}
|
|
566
|
+
setSelectedRecord={setSelectedRecord}
|
|
567
|
+
setDrawerTitle={setDrawerTitle}
|
|
568
|
+
setDrawerVisible={setDrawerVisible}
|
|
569
|
+
deleteRecord={deleteRecord}
|
|
570
|
+
level={level + 1}
|
|
571
|
+
onCrossLevelMove={onCrossLevelMove}
|
|
572
|
+
onChange={(submenus) => {
|
|
573
|
+
const updated = localItems.map((item) => (item.id === child.id ? { ...item, sub_menus: submenus } : item));
|
|
574
|
+
setLocalItems(updated);
|
|
575
|
+
onChange?.(updated);
|
|
576
|
+
}}
|
|
577
|
+
/>
|
|
425
578
|
</Panel>
|
|
426
579
|
))}
|
|
427
580
|
</Collapse>
|
|
428
581
|
);
|
|
429
582
|
}
|
|
583
|
+
|
|
584
|
+
export default MenuLists;
|