ui-soxo-bootstrap-core 2.4.25-dev.10 → 2.4.25-dev.12
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/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +119 -42
- package/core/lib/elements/basic/switch/switch.js +1 -1
- package/core/lib/hooks/use-otp-timer.js +0 -19
- package/core/lib/pages/login/login.js +20 -18
- package/core/lib/pages/login/login.scss +5 -1
- package/core/models/menus/components/menu-add/menu-add.js +22 -31
- package/core/models/menus/components/menu-lists/menu-lists.js +336 -218
- package/core/models/menus/components/menu-lists/menu-lists.scss +4 -9
- package/core/models/menus/menus.js +9 -0
- package/core/models/roles/components/role-add/role-add.js +123 -128
- package/core/models/roles/components/role-list/role-list.js +325 -349
- package/core/models/roles/roles.js +9 -0
- package/core/models/users/components/user-add/user-add.js +35 -1
- package/package.json +1 -1
|
@@ -1,61 +1,138 @@
|
|
|
1
|
-
import React, { useRef } from
|
|
2
|
-
import { useDrag, useDrop } from
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { useDrag, useDrop } from 'react-dnd';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
export default function DraggableWrapper({ id, index, movePanel, item, dragEnabled, level, parentId, onCrossLevelMove, canAcceptChildren }) {
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const
|
|
6
|
+
const autoScrollWindow = (monitor) => {
|
|
7
|
+
const offset = monitor.getClientOffset();
|
|
8
|
+
if (!offset) return;
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
hover(item, monitor) {
|
|
12
|
-
if (!dragEnabled) return; // ignore hover if dragging is disabled
|
|
13
|
-
if (!ref.current) return;
|
|
10
|
+
const EDGE = 80;
|
|
11
|
+
const SPEED = 20;
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
const hoverIndex = index;
|
|
13
|
+
const viewportHeight = window.innerHeight;
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
// 🔼 scroll UP
|
|
16
|
+
if (offset.y < EDGE) {
|
|
17
|
+
window.scrollBy(0, -SPEED);
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
// 🔽 scroll DOWN
|
|
21
|
+
if (offset.y > viewportHeight - EDGE) {
|
|
22
|
+
window.scrollBy(0, SPEED);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
const [{ isDragging }, drag] = useDrag({
|
|
27
|
+
type: 'PANEL',
|
|
28
|
+
item: { id, index, level, parentId },
|
|
29
|
+
canDrag: dragEnabled,
|
|
30
|
+
collect: (monitor) => ({
|
|
31
|
+
isDragging: monitor.isDragging(),
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const [{ isOver, canDrop }, drop] = useDrop({
|
|
36
|
+
accept: 'PANEL',
|
|
37
|
+
hover: (dragItem, monitor) => {
|
|
38
|
+
// THIS FIXES BOTTOM → TOP
|
|
39
|
+
autoScrollWindow(monitor);
|
|
40
|
+
|
|
41
|
+
if (dragItem.index === index) return;
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
dragItem.level === level &&
|
|
45
|
+
dragItem.parentId === parentId
|
|
46
|
+
) {
|
|
47
|
+
movePanel(dragItem.index, index);
|
|
48
|
+
dragItem.index = index; // keep in sync
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
canDrop: (item) => dragEnabled,
|
|
53
|
+
drop: (dragItem, monitor) => {
|
|
54
|
+
if (monitor.didDrop()) return;
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
dragItem.level !== level ||
|
|
58
|
+
dragItem.parentId !== parentId
|
|
59
|
+
) {
|
|
60
|
+
onCrossLevelMove?.(dragItem, {
|
|
61
|
+
targetLevel: level,
|
|
62
|
+
targetParentId: parentId,
|
|
63
|
+
targetIndex: index,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
collect: (monitor) => ({
|
|
68
|
+
isOver: monitor.isOver({ shallow: true }),
|
|
69
|
+
canDrop: monitor.canDrop(),
|
|
70
|
+
}),
|
|
31
71
|
});
|
|
32
72
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
73
|
+
// Drop zone for making items children of this item
|
|
74
|
+
const [{ isOverChild, canDropChild }, dropChild] = useDrop({
|
|
75
|
+
accept: 'PANEL',
|
|
76
|
+
canDrop: (item) => dragEnabled && item.id !== id && canAcceptChildren,
|
|
77
|
+
drop: (item, monitor) => {
|
|
78
|
+
if (monitor.didDrop()) return;
|
|
79
|
+
|
|
80
|
+
if (onCrossLevelMove && item.id !== id) {
|
|
81
|
+
// Drop as child of this item
|
|
82
|
+
onCrossLevelMove(item, { targetLevel: level + 1, targetParentId: id, targetIndex: 0 });
|
|
83
|
+
}
|
|
84
|
+
},
|
|
37
85
|
collect: (monitor) => ({
|
|
38
|
-
|
|
86
|
+
isOverChild: monitor.isOver({ shallow: true }),
|
|
87
|
+
canDropChild: monitor.canDrop(),
|
|
39
88
|
}),
|
|
40
89
|
});
|
|
41
90
|
|
|
42
|
-
|
|
91
|
+
const backgroundColor = isOver && canDrop ? '#bae7ff' : isDragging ? '#e6f7ff' : 'transparent';
|
|
92
|
+
const childZoneBackgroundColor = isOverChild && canDropChild ? '#d4f4dd' : 'transparent';
|
|
43
93
|
|
|
44
94
|
return (
|
|
45
|
-
<div
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
95
|
+
<div ref={drop} style={{ width: '100%' }}>
|
|
96
|
+
<div
|
|
97
|
+
ref={drag}
|
|
98
|
+
style={{
|
|
99
|
+
opacity: isDragging ? 0.5 : 1,
|
|
100
|
+
cursor: dragEnabled ? 'move' : 'default',
|
|
101
|
+
// padding: '8px',
|
|
102
|
+
backgroundColor,
|
|
103
|
+
transition: 'all 0.2s ease',
|
|
104
|
+
border: isOver && canDrop ? '2px dashed #1890ff' : '2px solid transparent',
|
|
105
|
+
display: 'flex',
|
|
106
|
+
justifyContent: 'space-between',
|
|
107
|
+
alignItems: 'center',
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<div style={{ flex: 1 }}>
|
|
111
|
+
{dragEnabled && <span style={{ marginRight: 8, color: '#999' }}>⋮⋮</span>}
|
|
112
|
+
<strong>{item.name}</strong>
|
|
113
|
+
{dragEnabled ?( <span style={{ marginLeft: 8, fontSize: 11, color: '#999' }}>(Level {level})</span>):(<span style={{ marginLeft: 8, fontSize: 11, color: '#999' }}>{item.path}</span>)}
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
{canAcceptChildren && dragEnabled && (
|
|
117
|
+
<div
|
|
118
|
+
ref={dropChild}
|
|
119
|
+
onClick={(e) => e.stopPropagation()}
|
|
120
|
+
style={{
|
|
121
|
+
padding: '4px 12px',
|
|
122
|
+
marginLeft: 8,
|
|
123
|
+
backgroundColor: childZoneBackgroundColor,
|
|
124
|
+
border: isOverChild && canDropChild ? '2px solid #52c41a' : '1px dashed #d9d9d9',
|
|
125
|
+
borderRadius: 4,
|
|
126
|
+
fontSize: 11,
|
|
127
|
+
color: isOverChild && canDropChild ? '#52c41a' : '#999',
|
|
128
|
+
cursor: 'default',
|
|
129
|
+
transition: 'all 0.2s ease',
|
|
130
|
+
}}
|
|
131
|
+
>
|
|
132
|
+
{isOverChild && canDropChild ? '✓ Drop as child' : '↳ Drop here'}
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
59
136
|
</div>
|
|
60
137
|
);
|
|
61
138
|
}
|
|
@@ -16,25 +16,6 @@ import { useState, useEffect, useRef } from 'react';
|
|
|
16
16
|
* @returns {(seconds: number) => void} API.start - Start timer with seconds.
|
|
17
17
|
* @returns {(expirytime: string) => void} API.startFromExpiry - Start timer using expiry string (e.g. "2025-09-04T12:13:09.000Z").
|
|
18
18
|
*
|
|
19
|
-
* @example
|
|
20
|
-
* const { remaining, expired, formatted, start, startFromExpiry } = useOtpTimer();
|
|
21
|
-
*
|
|
22
|
-
* // Start with 30 seconds
|
|
23
|
-
* useEffect(() => {
|
|
24
|
-
* start(30);
|
|
25
|
-
* }, []);
|
|
26
|
-
*
|
|
27
|
-
* // OR start from backend expiry timestamp
|
|
28
|
-
* useEffect(() => {
|
|
29
|
-
* startFromExpiry("2025-09-04T12:13:09.000Z");
|
|
30
|
-
* }, []);
|
|
31
|
-
*
|
|
32
|
-
* return (
|
|
33
|
-
* <div>
|
|
34
|
-
* <p>Time left: {formatted}</p>
|
|
35
|
-
* {expired && <p>OTP expired!</p>}
|
|
36
|
-
* </div>
|
|
37
|
-
* );
|
|
38
19
|
*/
|
|
39
20
|
|
|
40
21
|
// helper to format time
|
|
@@ -121,9 +121,11 @@ function LoginPhone({ history, appSettings }) {
|
|
|
121
121
|
.then((result) => {
|
|
122
122
|
setLoading(false);
|
|
123
123
|
|
|
124
|
-
const { user, access_token, refresh_token } = result;
|
|
124
|
+
const { user, access_token, refresh_token, insider_token } = result;
|
|
125
125
|
if (access_token) localStorage.access_token = access_token;
|
|
126
126
|
|
|
127
|
+
if (insider_token) localStorage.insider_token = insider_token;
|
|
128
|
+
|
|
127
129
|
if (result.success) {
|
|
128
130
|
//two_factor_authentication variable is present then proceed Two factor authentication
|
|
129
131
|
if (result.data && result.data.two_factor_authentication) {
|
|
@@ -516,28 +518,28 @@ function LoginPhone({ history, appSettings }) {
|
|
|
516
518
|
return user.username;
|
|
517
519
|
};
|
|
518
520
|
|
|
519
|
-
const { globalCustomerHeader = () => {} } = appSettings;
|
|
521
|
+
const { globalCustomerHeader = () => { } } = appSettings;
|
|
520
522
|
|
|
521
523
|
const themeName = process.env.REACT_APP_THEME; // e.g., 'purple'
|
|
522
524
|
const isPurple = themeName === 'purple';
|
|
523
525
|
|
|
524
526
|
const sectionStyle = isPurple
|
|
525
527
|
? {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
528
|
+
width: '100%',
|
|
529
|
+
height: '100vh',
|
|
530
|
+
backgroundImage: `${state.theme.colors.loginPageBackground}`,
|
|
531
|
+
backgroundPosition: 'center bottom, center',
|
|
532
|
+
backgroundRepeat: 'no-repeat, no-repeat',
|
|
533
|
+
backgroundSize: 'cover, cover',
|
|
534
|
+
}
|
|
533
535
|
: {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
536
|
+
width: '100%',
|
|
537
|
+
height: '100vh',
|
|
538
|
+
backgroundImage: `url(${backgroundImage}), ${state.theme.colors.loginPageBackground}`,
|
|
539
|
+
backgroundPosition: 'center bottom, center',
|
|
540
|
+
backgroundRepeat: 'no-repeat, no-repeat',
|
|
541
|
+
backgroundSize: 'cover, cover',
|
|
542
|
+
};
|
|
541
543
|
|
|
542
544
|
return (
|
|
543
545
|
<section className="full-page" style={sectionStyle}>
|
|
@@ -610,10 +612,10 @@ function LoginPhone({ history, appSettings }) {
|
|
|
610
612
|
<Text type="primary">Select Preferred OTP Verification Method</Text>
|
|
611
613
|
<div className="otp-method-group">
|
|
612
614
|
<Radio checked={communicationMode === 'email'} onChange={() => setCommunicationMode('email')}>
|
|
613
|
-
Email <MailOutlined style={{ marginLeft: 6 }} />
|
|
615
|
+
Email <MailOutlined className="otp-icon" style={{ marginLeft: 6 }} />
|
|
614
616
|
</Radio>
|
|
615
617
|
<Radio checked={communicationMode === 'mobile'} onChange={() => setCommunicationMode('mobile')}>
|
|
616
|
-
SMS <MessageOutlined style={{ marginLeft: 6 }} />
|
|
618
|
+
SMS <MessageOutlined className="otp-icon" style={{ marginLeft: 6 }} />
|
|
617
619
|
</Radio>
|
|
618
620
|
</div>
|
|
619
621
|
{modeError && <p className="otp-mode-error">Please select a communication mode.</p>}
|
|
@@ -352,10 +352,14 @@ body {
|
|
|
352
352
|
gap: 30px;
|
|
353
353
|
font-size: 12px;
|
|
354
354
|
}
|
|
355
|
+
.otp-icon {
|
|
356
|
+
position: relative;
|
|
357
|
+
top: 2px;
|
|
358
|
+
}
|
|
355
359
|
|
|
356
360
|
.ant-radio-wrapper {
|
|
357
361
|
display: flex;
|
|
358
|
-
align-items: center;
|
|
362
|
+
// align-items: center;
|
|
359
363
|
gap: 6px;
|
|
360
364
|
|
|
361
365
|
svg {
|
|
@@ -107,13 +107,14 @@ const MenuAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
107
107
|
* Submit values
|
|
108
108
|
*/
|
|
109
109
|
const onSubmit = (values) => {
|
|
110
|
-
// console.log(values);
|
|
111
110
|
setLoading(true);
|
|
112
111
|
|
|
113
112
|
let id = formContent.id;
|
|
114
113
|
|
|
115
|
-
//
|
|
116
|
-
|
|
114
|
+
// ✅ ONLY set step if it's NOT already provided
|
|
115
|
+
if (!values.step) {
|
|
116
|
+
values.step = formContent.step || step;
|
|
117
|
+
}
|
|
117
118
|
|
|
118
119
|
if (values.attributes && typeof values === 'object') {
|
|
119
120
|
values = {
|
|
@@ -123,30 +124,19 @@ const MenuAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
if (id) {
|
|
126
|
-
// Update of model
|
|
127
127
|
model.update({ id, values }).then(() => {
|
|
128
|
-
// callback();
|
|
129
128
|
message.success('Menu Updated');
|
|
130
|
-
|
|
131
129
|
setLoading(false);
|
|
132
|
-
|
|
133
130
|
callback();
|
|
134
131
|
});
|
|
135
132
|
} else {
|
|
136
|
-
values.step = step;
|
|
137
|
-
|
|
138
|
-
// Append the additional queries to the object
|
|
139
133
|
additional_queries.forEach(({ field, value }) => {
|
|
140
134
|
values[field] = value;
|
|
141
135
|
});
|
|
142
136
|
|
|
143
|
-
// add new model
|
|
144
137
|
model.add({ values }).then(() => {
|
|
145
|
-
// callback();
|
|
146
138
|
message.success('Menu Added');
|
|
147
|
-
|
|
148
139
|
setLoading(false);
|
|
149
|
-
|
|
150
140
|
callback();
|
|
151
141
|
});
|
|
152
142
|
}
|
|
@@ -154,7 +144,7 @@ const MenuAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
154
144
|
|
|
155
145
|
return (
|
|
156
146
|
<section className="collection-add menu-add">
|
|
157
|
-
<Title level={4}>{mode} Menu</Title>
|
|
147
|
+
{/* <Title level={4}>{mode} Menu</Title> */}
|
|
158
148
|
|
|
159
149
|
{loading ? (
|
|
160
150
|
<Skeleton />
|
|
@@ -163,21 +153,21 @@ const MenuAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
163
153
|
<div className="form-container">
|
|
164
154
|
<div className="left-container">
|
|
165
155
|
{/* Caption */}
|
|
166
|
-
<Form.Item name={'caption'} label="Caption" required>
|
|
156
|
+
<Form.Item name={'caption'} label="Caption" rules={[{ required: true, message: 'Caption is required' }]}>
|
|
167
157
|
<Input placeholder="Enter caption" />
|
|
168
158
|
</Form.Item>
|
|
169
159
|
{/* Caption Ends */}
|
|
170
160
|
|
|
171
161
|
{/* Name */}
|
|
172
|
-
<Form.Item name={'name'} label="Name" required>
|
|
162
|
+
<Form.Item name={'name'} label="Name" rules={[{ required: true, message: 'Name is required' }]}>
|
|
173
163
|
<Input placeholder="Enter name" />
|
|
174
164
|
</Form.Item>
|
|
175
165
|
{/* Name Ends */}
|
|
176
166
|
|
|
177
167
|
{/* Description */}
|
|
178
|
-
<Form.Item name={
|
|
179
|
-
|
|
180
|
-
|
|
168
|
+
{/* <Form.Item name={"description"} label="Description">
|
|
169
|
+
<TextArea placeholder="Enter Description" />
|
|
170
|
+
</Form.Item> */}
|
|
181
171
|
{/* Description Ends */}
|
|
182
172
|
|
|
183
173
|
{/* Model */}
|
|
@@ -229,37 +219,38 @@ const MenuAdd = ({ model, callback, edit, history, formContent, match, additiona
|
|
|
229
219
|
{/* Pages Ends */}
|
|
230
220
|
|
|
231
221
|
{/* Path */}
|
|
232
|
-
<Form.Item name="path" label="Path" required>
|
|
233
|
-
|
|
234
|
-
|
|
222
|
+
{/* <Form.Item name="path" label="Path" required>
|
|
223
|
+
<Input placeholder="Enter path" />
|
|
224
|
+
</Form.Item> */}
|
|
235
225
|
{/* Path Ends */}
|
|
236
226
|
|
|
237
227
|
{/* Route */}
|
|
238
|
-
<Form.Item name="route" label="Route" required>
|
|
228
|
+
<Form.Item name="route" label="Route" rules={[{ required: true, message: 'Route is required' }]}>
|
|
239
229
|
<Input placeholder="Enter route" />
|
|
240
230
|
</Form.Item>
|
|
241
231
|
{/* Route Ends */}
|
|
242
232
|
|
|
243
233
|
{/* Switch */}
|
|
244
|
-
<Form.Item name="is_visible" label="Visible" required>
|
|
245
|
-
<Switch
|
|
234
|
+
<Form.Item name="is_visible" label="Visible" valuePropName="checked" rules={[{ required: true, message: 'Visibility is required' }]}>
|
|
235
|
+
<Switch />
|
|
246
236
|
</Form.Item>
|
|
237
|
+
|
|
247
238
|
{/* Switch Ends */}
|
|
248
239
|
|
|
249
240
|
{/* Step */}
|
|
250
|
-
<Form.Item name={
|
|
251
|
-
|
|
252
|
-
|
|
241
|
+
{/* <Form.Item name={"order"} label="Order" required>
|
|
242
|
+
<InputNumber placeholder="Enter order" />
|
|
243
|
+
</Form.Item> */}
|
|
253
244
|
{/* Step Ends */}
|
|
254
245
|
|
|
255
246
|
{/* Icon Name*/}
|
|
256
|
-
<Form.Item name="icon_name" label="Icon Name" required>
|
|
247
|
+
<Form.Item name="icon_name" label="Icon Name" rules={[{ required: true, message: 'Icon name is required' }]}>
|
|
257
248
|
<Input placeholder="Enter icon name" />
|
|
258
249
|
</Form.Item>
|
|
259
250
|
{/* Icon Name Ends */}
|
|
260
251
|
|
|
261
252
|
{/* Step */}
|
|
262
|
-
<Form.Item name={'step'} label="Step" required>
|
|
253
|
+
<Form.Item name={'step'} label="Step" rules={[{ required: true, message: 'Step is required' }]}>
|
|
263
254
|
<InputNumber placeholder="Enter step" />
|
|
264
255
|
</Form.Item>
|
|
265
256
|
{/* Step Ends */}
|