ui-soxo-bootstrap-core 2.4.25-dev.8 → 2.4.25

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 (31) hide show
  1. package/.github/workflows/npm-publish.yml +15 -37
  2. package/core/components/extra-info/extra-info-details.js +126 -109
  3. package/core/components/landing-api/landing-api.js +30 -22
  4. package/core/lib/Store.js +18 -20
  5. package/core/lib/components/index.js +1 -4
  6. package/core/lib/components/sidemenu/sidemenu.js +256 -153
  7. package/core/lib/components/sidemenu/sidemenu.scss +26 -39
  8. package/core/lib/hooks/index.js +12 -2
  9. package/core/lib/pages/login/login.js +139 -255
  10. package/core/lib/pages/login/login.scss +32 -140
  11. package/core/models/dashboard/dashboard.js +0 -14
  12. package/core/models/menus/components/menu-add/menu-add.js +268 -230
  13. package/core/models/menus/components/menu-lists/menu-lists.js +89 -126
  14. package/core/models/menus/components/menu-lists/menu-lists.scss +0 -9
  15. package/core/models/menus/menus.js +267 -247
  16. package/core/models/roles/components/role-add/role-add.js +227 -269
  17. package/core/models/roles/components/role-list/role-list.js +6 -8
  18. package/core/models/roles/roles.js +174 -182
  19. package/core/models/users/components/user-add/user-add.js +1 -69
  20. package/core/models/users/users.js +0 -57
  21. package/core/modules/index.js +13 -23
  22. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +1 -1
  23. package/package.json +2 -2
  24. package/README.md +0 -260
  25. package/core/lib/hooks/use-otp-timer.js +0 -99
  26. package/core/models/staff/components/staff-add/staff-add.js +0 -352
  27. package/core/models/staff/components/staff-add/staff-add.scss +0 -0
  28. package/core/modules/steps/action-buttons.js +0 -79
  29. package/core/modules/steps/steps.js +0 -553
  30. package/core/modules/steps/steps.scss +0 -158
  31. package/core/modules/steps/timeline.js +0 -49
@@ -1,290 +1,248 @@
1
1
  import React, { useState, useEffect, useContext } from 'react';
2
- import { useLocation, useParams } from 'react-router-dom';
3
- import { Skeleton, Typography, message, Form, Input, Collapse, Checkbox } from 'antd';
4
- import { GlobalContext } from './../../../../lib';
5
- import {Button} from './../../../../lib';
6
- import { ModelsAPI, PagesAPI, RolesAPI, MenusAPI } from '../../..';
2
+ import { useLocation,useParams } from 'react-router-dom';
3
+ import { Skeleton, Typography, message, Form, Input, Select, Collapse, Checkbox } from 'antd';
4
+ import { Table, Card, Button, JSONInput, Switch, GlobalContext } from './../../../../lib';
5
+
6
+ import { ModelsAPI, PagesAPI, RolesAPI,MenusAPI } from '../../..';
7
7
 
8
8
  const { Title } = Typography;
9
+ const { Option } = Select;
9
10
  const { Panel } = Collapse;
10
11
 
11
- const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_queries = [] }) => {
12
- let mode = 'Add';
13
- if (formContent.id) mode = 'Edit';
14
- else if (formContent.copy) mode = 'copy';
15
-
16
- // Parse attributes safely
17
- if (formContent.attributes) {
18
- if (typeof formContent.attributes === 'string' && formContent.attributes !== '') {
19
- try {
20
- formContent.attributes = JSON.parse(formContent.attributes);
21
- } catch {
22
- formContent.attributes = {};
23
- }
12
+ const RoleAdd = ({ model, callback, edit, history, formContent, match, additional_queries, ...props }) => {
13
+
14
+ let mode = 'Add';
15
+ if (formContent.id) mode = 'Edit';
16
+ else if (formContent.copy) mode = 'copy';
17
+
18
+ // Parse attributes safely
19
+ if (formContent.attributes) {
20
+ if (typeof formContent.attributes === 'string' && formContent.attributes !== '') {
21
+ formContent.attributes = JSON.parse(formContent.attributes);
22
+ } else {
23
+ formContent.attributes = {};
24
+ }
24
25
  } else {
25
- formContent.attributes = {};
26
+ formContent.attributes = {};
26
27
  }
27
- } else {
28
- formContent.attributes = {};
29
- }
30
-
31
- const [loading, setLoading] = useState(true);
32
- const [form] = Form.useForm();
33
- const [pages, setPages] = useState([]);
34
- const [models, setModels] = useState([]);
35
- const [menuList, setMenuList] = useState([]);
36
- const [showMenus, setShowMenus] = useState(false);
37
- const [originalMenus, setOriginalMenus] = useState([]);// for deselected menu for editing
38
-
39
-
40
- // Selected menus (array of IDs)
41
- const [selectedMenus, setSelectedMenus] = useState([]);
42
-
43
- const location = useLocation();
44
- const query = new URLSearchParams(location.search);
45
- let step = parseInt(query.get('step')) || 1;
46
-
47
- const { user = {} } = useContext(GlobalContext);
48
-
49
- // On component mount
50
- useEffect(() => {
51
- getPages();
52
- getModels();
53
- loadMenus();
54
- setShowMenus(true);
55
-
56
- // Preselect menus when editing
57
- if (formContent && formContent.menu_ids) {
58
- let menus = formContent.menu_ids;
59
-
60
- setSelectedMenus(menus);
61
- setOriginalMenus(menus); // keep original copy for deselect comparison
62
- }
63
-
64
- setLoading(false);
65
- }, [formContent]);
66
-
67
-
68
-
69
- // Load pages
70
- const getPages = () => {
71
- PagesAPI.getPages().then((res) => setPages(res.result || []));
72
- };
73
-
74
- // Load models
75
- const getModels = () => {
76
- ModelsAPI.get().then((res) => setModels(res.result || []));
77
- };
78
-
79
- // Load top-level menus
80
- const loadMenus = () => {
81
- MenusAPI.get({
82
- queries: [
83
- { field: 'step', value: 1 },
84
- { field: 'header_id', value: null },
85
- ],
86
- })
87
- .then((res) => setMenuList(res.result || []))
88
- .catch(console.error);
89
- };
90
-
91
- // Toggle menu selection
92
- const toggleMenu = (id, checked) => {
93
- setSelectedMenus((prev) =>
94
- checked ? [...prev, id] : prev.filter((m) => m !== id)
95
- );
96
- };
97
-
98
- // Submit handler
99
- // const onSubmit = (values) => {
100
- // setLoading(true);
101
-
102
- // const payload = {
103
- // ...values,
104
- // menu_ids
105
- // : selectedMenus,
106
- // attributes: JSON.stringify(values.attributes || {}),
107
- // };
108
-
109
- // if (formContent.id) {
110
- // RolesAPI.updateRole({ id: formContent.id, formBody: payload })
111
- // .then(() => {
112
- // message.success('Role Updated');
113
- // setLoading(false);
114
- // callback();
115
- // })
116
- // .catch(() => setLoading(false));
117
- // } else {
118
- // additional_queries.forEach(({ field, value }) => {
119
- // payload[field] = value;
120
- // });
121
- // RolesAPI.createRole(payload)
122
- // .then(() => {
123
- // message.success('Role Added');
124
- // setLoading(false);
125
- // callback();
126
- // })
127
- // .catch(() => setLoading(false));
128
- // }
129
- // };
130
- const onSubmit = async (values) => {
131
- setLoading(true);
132
-
133
-
134
- // Find menus that were originally selected but now deselected
135
- const deselectedMenus = originalMenus.filter(
136
- (id) => !selectedMenus.includes(id)
137
- );
138
-
139
- const payload = {
140
- ...values,
141
- menu_ids: selectedMenus,
142
- deselect_array: deselectedMenus, // add deselected menus when edit time
143
- attributes: JSON.stringify(values.attributes || {}),
144
- };
145
-
146
- // include id ONLY for edit
147
- if (formContent?.id) {
148
- payload.id = formContent.id;
149
- }
150
-
151
- // include additional queries for both cases
152
- additional_queries.forEach(({ field, value }) => {
153
- payload[field] = value;
154
- });
155
-
156
- try {
157
- await RolesAPI.createRole(payload); // single API
158
- message.success(formContent?.id ? 'Role Updated' : 'Role Added');
159
- callback();
160
- } catch (err) {
161
- // message.error('Something went wrong');
162
- } finally {
163
- setLoading(false);
164
- }
165
- };
166
28
 
29
+ const [loading, setLoading] = useState(true);
30
+ const [form] = Form.useForm();
31
+ const [pages, setPages] = useState([]);
32
+ const [models, setModels] = useState([]);
33
+ const [body, setBody] = useState(formContent);
34
+
35
+ const [showMenus, setShowMenus] = useState(false);
36
+ const [menuList, setMenuList] = useState([]);
37
+
38
+ const { params } = match;
39
+ const { dispatch, user = {} } = useContext(GlobalContext);
40
+
41
+ const location = useLocation();
42
+ const query = new URLSearchParams(location.search);
43
+
44
+ let step = parseInt(query.get('step')) || 1;
45
+
46
+ match = useParams();
47
+ const id = match.id;
48
+
49
+ useEffect(() => {
50
+ getPages();
51
+ getModels();
52
+ loadMenus();
53
+
54
+ setLoading(false);
55
+ }, []);
56
+ useEffect(() => {
57
+
58
+ loadMenus();
59
+ setShowMenus(true)
60
+
61
+ // setLoading(false);
62
+ }, [id]);
63
+
64
+ // Load pages
65
+ const getPages = () => {
66
+ PagesAPI.getPages().then((result) => {
67
+ setPages(result.result);
68
+ });
69
+ };
70
+
71
+ // Load models
72
+ const getModels = () => {
73
+ ModelsAPI.get().then((result) => {
74
+ console.log(result);
75
+ setModels(result.result);
76
+ });
77
+ };
78
+
79
+ // Load menus dynamically
80
+ const loadMenus = () => {
81
+ MenusAPI.get({
82
+ queries: [
83
+ { field: 'step', value: 1 },
84
+ { field: 'header_id', value: null }
85
+ ]
86
+ })
87
+ .then(res => setMenuList(res.result || []))
88
+ .catch(console.error);
89
+ };
167
90
 
91
+
168
92
 
169
- return (
170
- <section className="collection-add">
171
- {loading ? (
172
- <Skeleton />
173
- ) : (
174
- <Form
175
- initialValues={{ ...formContent }}
176
- form={form}
177
- layout="vertical"
178
- onFinish={onSubmit}
179
- >
180
- {/* Role Name */}
181
- <Form.Item name="name" label="Enter Role Name" required>
182
- <Input placeholder="Enter name" />
183
- </Form.Item>
184
-
185
- {/* Description */}
186
- <Form.Item name="description" label="Enter Description" required>
187
- <Input placeholder="Enter description" />
188
- </Form.Item>
189
-
190
- {/* MENUS COLLAPSE */}
191
- {showMenus && menuList.length > 0 && (
192
- <div style={{ marginTop: 30 }}>
193
- <Title level={5} style={{ marginBottom: 16 }}>
194
- Menu List
195
- </Title>
196
- <p style={{ marginTop: -10, marginBottom: 20, color: '#999' }}>
197
- Choose menus and set permissions
198
- </p>
199
-
200
- <Collapse expandIconPosition="left">
201
- {menuList.map((item) => (
202
- <Panel
93
+ // Submit
94
+ const onSubmit = (values) => {
95
+ setLoading(true);
96
+ let id = formContent.id;
97
+
98
+ if (values.attributes && typeof values === 'object') {
99
+ values = {
100
+ ...values,
101
+ attributes: JSON.stringify(values.attributes)
102
+ };
103
+ }
104
+
105
+ if (id) {
106
+ RolesAPI.updateRole({ id, formBody: values }).then(() => {
107
+ message.success('Role Updated');
108
+ setLoading(false);
109
+ callback();
110
+ });
111
+ } else {
112
+ additional_queries.forEach(({ field, value }) => {
113
+ values[field] = value;
114
+ });
115
+
116
+ RolesAPI.createRole(values).then(() => {
117
+ message.success('Role Added');
118
+ setLoading(false);
119
+ callback();
120
+ });
121
+ }
122
+ };
123
+
124
+ return (
125
+ <section className="collection-add">
126
+
127
+ {loading ? (
128
+ <Skeleton />
129
+ ) : (
130
+ <Form initialValues={{ ...body }} form={form} layout="vertical" onFinish={onSubmit}>
131
+
132
+ {/* Role Name */}
133
+ <Form.Item name="name" label="Enter Role Name" required>
134
+ <Input placeholder="Enter name" />
135
+ </Form.Item>
136
+ {/* Name */}
137
+ {/* <Form.Item name={"identifier"} label="Identifier" required>
138
+ <Input placeholder="Enter identifier" />
139
+ </Form.Item> */}
140
+ {/* Name Ends */}
141
+
142
+ {/* Path */}
143
+ {/* <Form.Item name="weight" label="Weight" required>
144
+ <Input placeholder="Enter weight" />
145
+ </Form.Item> */}
146
+ {/* Path Ends */}
147
+
148
+ {/* Description */}
149
+ <Form.Item name="description" label="Enter Description" required>
150
+ <Input placeholder="Enter description" />
151
+ </Form.Item>
152
+
153
+ {/* MENUS COLLAPSE */}
154
+ {showMenus && menuList.length > 0 && (
155
+ <div style={{ marginTop: 30 }}>
156
+ <Title level={5} style={{ marginBottom: 16 }}>Menu List</Title>
157
+ <p style={{ marginTop: -10, marginBottom: 20, color: "#999" }}>
158
+ Choose menus and set permissions
159
+ </p>
160
+
161
+ <Collapse expandIconPosition="left">
162
+ {menuList.map(item => (
163
+ <Panel
203
164
  key={item.id}
204
165
  header={
205
- <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
206
- <Checkbox
207
- checked={selectedMenus.includes(item.id)}
208
- onChange={(e) => toggleMenu(item.id, e.target.checked)}
209
- />
210
- <span>{item.title || item.caption}</span>
211
- </div>
166
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
167
+ <Checkbox />
168
+ <span>{item.title || item.caption}</span>
169
+ </div>
212
170
  }
213
- >
214
- {/* Nested submenus */}
215
- <NestedMenu
216
- parentId={item.id}
217
- step={step + 1}
218
- selectedMenus={selectedMenus}
219
- toggleMenu={toggleMenu}
220
- />
221
- </Panel>
222
- ))}
223
- </Collapse>
224
- </div>
225
- )}
226
-
227
- {/* Submit Button */}
228
- <Form.Item>
229
- <Button loading={loading} htmlType="submit" type="primary">
230
- Save
231
- </Button>
232
- </Form.Item>
233
- </Form>
234
- )}
235
- </section>
236
- );
171
+ >
172
+ {/* Load submenus recursively */}
173
+ <NestedMenu parentId={item.id} step={step + 1} />
174
+ </Panel>
175
+ ))}
176
+ </Collapse>
177
+ </div>
178
+ )}
179
+ {/* <Button type="primary" onClick={loadMenus()}>
180
+ Get Menus
181
+ </Button> */}
182
+
183
+
184
+ {/* Submit Button */}
185
+ <Form.Item>
186
+ <Button loading={loading} htmlType="submit" type="primary">
187
+ Save
188
+ </Button>
189
+ </Form.Item>
190
+
191
+ </Form>
192
+ )}
193
+
194
+ </section>
195
+ );
237
196
  };
238
197
 
239
198
  export default RoleAdd;
240
199
 
200
+
241
201
  // ------------------------
242
202
  // Recursive Nested Menu Component
243
203
  // ------------------------
244
- const NestedMenu = ({ parentId, step, selectedMenus, toggleMenu }) => {
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
-
265
- return (
266
- <Collapse ghost style={{ marginLeft: 20 }}>
267
- {items.map((menu) => (
268
- <Panel
269
- key={menu.id}
270
- header={
271
- <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
272
- <Checkbox
273
- checked={selectedMenus.includes(Number(menu.id))} // ensure number
274
- onChange={(e) => toggleMenu(Number(menu.id), e.target.checked)}
275
- />
276
- <span>{menu.title || menu.caption}</span>
277
- </div>
278
- }
279
- >
280
- <NestedMenu
281
- parentId={menu.id}
282
- step={step + 1}
283
- selectedMenus={selectedMenus}
284
- toggleMenu={toggleMenu}
285
- />
286
- </Panel>
287
- ))}
288
- </Collapse>
289
- );
204
+ const NestedMenu = ({ parentId, step, api, additional_queries }) => {
205
+ const [items, setItems] = useState([]);
206
+ const [loading, setLoading] = useState(true);
207
+
208
+ useEffect(() => {
209
+ MenusAPI.get({
210
+ queries: [
211
+ // ...additional_queries,
212
+ { field: 'header_id', value: parentId },
213
+ { field: 'step', value: step }
214
+ ],
215
+ })
216
+ .then(res => {
217
+ setItems(res.result || []);
218
+ setLoading(false);
219
+ })
220
+ .catch(() => setLoading(false));
221
+ }, [parentId]);
222
+
223
+ if (loading) return <Skeleton active />;
224
+ if (!items.length) return null;
225
+
226
+ return (
227
+ <Collapse ghost style={{ marginLeft: 20 }}>
228
+ {items.map(menu => (
229
+ <Panel
230
+ key={menu.id}
231
+ header={
232
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
233
+ <Checkbox />
234
+ <span>{menu.title || menu.caption}</span>
235
+ </div>
236
+ }
237
+ >
238
+ <NestedMenu
239
+ parentId={menu.id}
240
+ step={step + 1}
241
+ api={api}
242
+ additional_queries={additional_queries}
243
+ />
244
+ </Panel>
245
+ ))}
246
+ </Collapse>
247
+ );
290
248
  };
@@ -11,7 +11,6 @@ import { Typography, Modal, Space, Switch, Popconfirm, Skeleton, Input, Drawer,S
11
11
  import { TableComponent, Card, Button } from './../../../../lib';
12
12
 
13
13
  import { ReloadOutlined, OrderedListOutlined, PicCenterOutlined, DeleteOutlined, EditOutlined, CopyOutlined } from '@ant-design/icons';
14
- import { RolesAPI } from '../../..';
15
14
 
16
15
  const { Title } = Typography;
17
16
 
@@ -80,13 +79,12 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
80
79
  setLoading(true);
81
80
 
82
81
  // Get the records
83
- return RolesAPI.getRole()
82
+ return model.get(config)
84
83
 
85
84
  .then((res) => {
86
85
 
87
86
  // setRecords(res.result);
88
87
  var result = res;
89
-
90
88
 
91
89
  // if (id) {
92
90
 
@@ -159,12 +157,13 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
159
157
  // getRecords();
160
158
  // }
161
159
  }
160
+
162
161
  /**
163
162
  * On delete of each record
164
163
  */
165
- function onDelete(id) {
164
+ function onDelete(record) {
166
165
 
167
- RolesAPI.deleteRole(id).then((res) => {
166
+ model.delete(record).then((res) => {
168
167
  if (res) {
169
168
  getRecords();
170
169
 
@@ -260,8 +259,7 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
260
259
 
261
260
  {/* Delete Icon */}
262
261
  <Popconfirm title="Are you sure" onConfirm={() => {
263
-
264
- onDelete(record.id);
262
+ onDelete(record);
265
263
  }}>
266
264
  <Button size={'small'} type="dashed">
267
265
  <DeleteOutlined />
@@ -315,7 +313,7 @@ const RoleList = ({ model, match, relativeAdd = false, additional_queries = [],
315
313
  <div className="button-container">
316
314
  <Space size="small">
317
315
 
318
- <Button onClick={getRecords} size={'small'} type='default'>
316
+ <Button onClick={getRecords} size={'small'}>
319
317
  <ReloadOutlined />
320
318
  </Button>
321
319