ui-soxo-bootstrap-core 2.4.25-dev.9 → 2.4.26
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 +15 -37
- package/core/components/extra-info/extra-info-details.js +126 -109
- package/core/components/landing-api/landing-api.js +30 -22
- package/core/lib/Store.js +18 -20
- package/core/lib/components/index.js +1 -4
- package/core/lib/components/sidemenu/sidemenu.js +256 -153
- package/core/lib/components/sidemenu/sidemenu.scss +26 -39
- package/core/lib/elements/basic/rangepicker/rangepicker.js +29 -118
- package/core/lib/hooks/use-otp-timer.js +0 -19
- package/core/lib/pages/login/login.js +2 -2
- package/core/lib/pages/login/login.scss +5 -1
- package/core/models/dashboard/dashboard.js +0 -14
- package/core/models/menus/components/menu-lists/menu-lists.js +89 -126
- package/core/models/menus/components/menu-lists/menu-lists.scss +0 -9
- package/core/models/menus/menus.js +267 -247
- package/core/models/roles/components/role-add/role-add.js +227 -269
- package/core/models/roles/components/role-list/role-list.js +6 -8
- package/core/models/roles/roles.js +174 -182
- package/core/models/users/components/user-add/user-add.js +1 -69
- package/core/models/users/users.js +0 -57
- package/core/modules/index.js +13 -23
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +1 -1
- package/package.json +2 -2
- package/core/models/staff/components/staff-add/staff-add.js +0 -352
- package/core/models/staff/components/staff-add/staff-add.scss +0 -0
- package/core/modules/steps/action-buttons.js +0 -79
- package/core/modules/steps/steps.js +0 -553
- package/core/modules/steps/steps.scss +0 -158
- package/core/modules/steps/timeline.js +0 -49
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import './staff-add.scss';
|
|
3
|
-
import { Modal, Tabs, Input, Form, Row, Col, message, Checkbox, Select } from 'antd';
|
|
4
|
-
import { useTranslation, Button } from './../../../../lib/';
|
|
5
|
-
import { UsersAPI } from '../../..';
|
|
6
|
-
|
|
7
|
-
const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
8
|
-
const [form] = Form.useForm();
|
|
9
|
-
const { t } = useTranslation();
|
|
10
|
-
|
|
11
|
-
/** -------------------------------
|
|
12
|
-
* STATE
|
|
13
|
-
* ------------------------------- */
|
|
14
|
-
const [loading, setLoading] = useState(false);
|
|
15
|
-
const [designations, setDesignations] = useState([]);
|
|
16
|
-
const [isSubmitDisabled, setIsSubmitDisabled] = useState(true);
|
|
17
|
-
const [codeStatus, setCodeStatus] = useState({ status: '', message: '' });
|
|
18
|
-
|
|
19
|
-
const nameInputRef = useRef(null);
|
|
20
|
-
|
|
21
|
-
const editMode = Boolean(staffId);
|
|
22
|
-
|
|
23
|
-
/** -------------------------------
|
|
24
|
-
* FORM WATCHERS
|
|
25
|
-
* ------------------------------- */
|
|
26
|
-
const watchedName = Form.useWatch('shortName', form);
|
|
27
|
-
const watchedCode = Form.useWatch('id', form);
|
|
28
|
-
const watchedDesc = Form.useWatch('description', form);
|
|
29
|
-
|
|
30
|
-
/** -------------------------------
|
|
31
|
-
* EFFECTS
|
|
32
|
-
* ------------------------------- */
|
|
33
|
-
|
|
34
|
-
// Auto-focus on open
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (visible) {
|
|
37
|
-
setTimeout(() => nameInputRef.current?.focus(), 200);
|
|
38
|
-
}
|
|
39
|
-
}, [visible]);
|
|
40
|
-
|
|
41
|
-
// Control submit button
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
setIsSubmitDisabled(!(watchedName && watchedCode && watchedDesc));
|
|
44
|
-
}, [watchedName, watchedCode, watchedDesc]);
|
|
45
|
-
|
|
46
|
-
// Load designations when modal opens
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (visible) getDesignations();
|
|
49
|
-
}, [visible]);
|
|
50
|
-
|
|
51
|
-
// Reset or fill edit form
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (visible) {
|
|
54
|
-
if (editMode && staffData) fillEditForm(staffData);
|
|
55
|
-
} else {
|
|
56
|
-
form.resetFields();
|
|
57
|
-
}
|
|
58
|
-
}, [visible]);
|
|
59
|
-
|
|
60
|
-
/** -------------------------------
|
|
61
|
-
* API CALL – Designations
|
|
62
|
-
* ------------------------------- */
|
|
63
|
-
const getDesignations = () => {
|
|
64
|
-
setLoading(true);
|
|
65
|
-
UsersAPI.getDesignations()
|
|
66
|
-
.then((res) => {
|
|
67
|
-
if (res?.success && Array.isArray(res.result)) {
|
|
68
|
-
const formatted = res.result.map((ele) => ({
|
|
69
|
-
label: ele.dg_desc?.trim() || '',
|
|
70
|
-
value: ele.dg_code,
|
|
71
|
-
}));
|
|
72
|
-
setDesignations(formatted);
|
|
73
|
-
} else {
|
|
74
|
-
setDesignations([]);
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
.catch((err) => {
|
|
78
|
-
console.error('Error fetching designations:', err);
|
|
79
|
-
setDesignations([]);
|
|
80
|
-
})
|
|
81
|
-
.finally(() => setLoading(false));
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/** -------------------------------
|
|
85
|
-
* VALIDATION – Code
|
|
86
|
-
* ------------------------------- */
|
|
87
|
-
const validateDoctorCode = async (_, value) => {
|
|
88
|
-
if (editMode) return Promise.resolve(); // Skip validation if editing
|
|
89
|
-
|
|
90
|
-
if (!value) {
|
|
91
|
-
setCodeStatus({ status: '', message: '' });
|
|
92
|
-
return Promise.resolve();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const res = await UsersAPI.getStaffCode(value);
|
|
97
|
-
|
|
98
|
-
if (res?.status === 409 || res?.success === false) {
|
|
99
|
-
setCodeStatus({ status: 'error', message: res.message || 'Code already exists' });
|
|
100
|
-
return Promise.reject(new Error(res.message || 'Code already exists'));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (res?.status === 200 && res?.success === true) {
|
|
104
|
-
setCodeStatus({
|
|
105
|
-
status: 'success',
|
|
106
|
-
message: 'The entered code is valid for assigning a staff.',
|
|
107
|
-
});
|
|
108
|
-
return Promise.resolve();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
setCodeStatus({ status: 'error', message: 'Unexpected response' });
|
|
112
|
-
return Promise.reject(new Error('Unexpected response'));
|
|
113
|
-
} catch {
|
|
114
|
-
setCodeStatus({ status: 'error', message: 'Validation failed' });
|
|
115
|
-
return Promise.reject(new Error('Validation failed'));
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/** -------------------------------
|
|
120
|
-
* UTIL – Enter Key Navigation
|
|
121
|
-
* ------------------------------- */
|
|
122
|
-
const handleEnterKey = (e) => {
|
|
123
|
-
if (e.key === 'Enter') {
|
|
124
|
-
e.preventDefault();
|
|
125
|
-
const fields = Array.from(document.querySelectorAll('.ant-input'));
|
|
126
|
-
const index = fields.indexOf(e.target);
|
|
127
|
-
if (index > -1 && index < fields.length - 1) {
|
|
128
|
-
fields[index + 1].focus();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
/** -------------------------------
|
|
134
|
-
* FORM FILL – Edit Mode
|
|
135
|
-
* ------------------------------- */
|
|
136
|
-
const fillEditForm = (data) => {
|
|
137
|
-
form.setFieldsValue({
|
|
138
|
-
id: data.id,
|
|
139
|
-
shortName: data.shortName,
|
|
140
|
-
description: data.description,
|
|
141
|
-
designation: data.designationPtr,
|
|
142
|
-
phone1: data.phone,
|
|
143
|
-
phone2: data.mobile || data.alternateMobile,
|
|
144
|
-
email1: data.email,
|
|
145
|
-
email2: data.alternateEmail,
|
|
146
|
-
slno: data.slNo,
|
|
147
|
-
active: data.active === 'Y' ? 'Y' : 'N',
|
|
148
|
-
remarks: data.remarks,
|
|
149
|
-
address1: data.address1,
|
|
150
|
-
address2: data.address2,
|
|
151
|
-
place: data.place,
|
|
152
|
-
zip: data.zip,
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/** -------------------------------
|
|
157
|
-
* SUBMIT HANDLER
|
|
158
|
-
* ------------------------------- */
|
|
159
|
-
const handleFinish = async (values) => {
|
|
160
|
-
setLoading(true);
|
|
161
|
-
|
|
162
|
-
const payload = {
|
|
163
|
-
id: values.id,
|
|
164
|
-
shortName: values.shortName,
|
|
165
|
-
description: values.description,
|
|
166
|
-
designationPtr: values.designation,
|
|
167
|
-
phone: values.phone1,
|
|
168
|
-
mobile: values.phone2,
|
|
169
|
-
alternateMobile: values.phone2,
|
|
170
|
-
email: values.email1,
|
|
171
|
-
alternateEmail: values.email2,
|
|
172
|
-
remarks: values.remarks,
|
|
173
|
-
slNo: values.slno ? Number(values.slno) : null,
|
|
174
|
-
active: values.active === 'Y' ? 'Y' : 'N',
|
|
175
|
-
address1: values.address1,
|
|
176
|
-
address2: values.address2,
|
|
177
|
-
place: values.place,
|
|
178
|
-
zip: values.zip,
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
const res = editMode ? await UsersAPI.updateStaff(payload, staffData.id) : await UsersAPI.createStaff(payload);
|
|
183
|
-
|
|
184
|
-
if (res?.success) {
|
|
185
|
-
message.success(editMode ? 'Staff updated successfully' : 'Staff created successfully');
|
|
186
|
-
onSuccess?.();
|
|
187
|
-
onCancel();
|
|
188
|
-
} else {
|
|
189
|
-
message.error(res?.message || 'Operation failed');
|
|
190
|
-
}
|
|
191
|
-
} catch {
|
|
192
|
-
message.error('Something went wrong');
|
|
193
|
-
} finally {
|
|
194
|
-
setLoading(false);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
/** -------------------------------
|
|
199
|
-
* RENDER
|
|
200
|
-
* ------------------------------- */
|
|
201
|
-
return (
|
|
202
|
-
<Modal
|
|
203
|
-
title={editMode ? 'Edit Staff' : 'Add Staff'}
|
|
204
|
-
open={visible}
|
|
205
|
-
onCancel={onCancel}
|
|
206
|
-
width={950}
|
|
207
|
-
footer={null}
|
|
208
|
-
destroyOnClose
|
|
209
|
-
style={{ top: 10 }}
|
|
210
|
-
>
|
|
211
|
-
<Form form={form} layout="vertical" onFinish={handleFinish}>
|
|
212
|
-
{/* TOP SECTION */}
|
|
213
|
-
<Row gutter={16}>
|
|
214
|
-
<Col span={6}>
|
|
215
|
-
<Form.Item
|
|
216
|
-
label="Code"
|
|
217
|
-
name="id"
|
|
218
|
-
validateTrigger="onChange"
|
|
219
|
-
hasFeedback={!editMode}
|
|
220
|
-
rules={[{ required: true }, { validator: validateDoctorCode }]}
|
|
221
|
-
>
|
|
222
|
-
<Input placeholder="Enter Code" ref={nameInputRef} onKeyDown={handleEnterKey} disabled={editMode} />
|
|
223
|
-
</Form.Item>
|
|
224
|
-
</Col>
|
|
225
|
-
|
|
226
|
-
<Col span={6}>
|
|
227
|
-
<Form.Item label="Name" name="shortName" rules={[{ required: true }]}>
|
|
228
|
-
<Input placeholder="Enter Name" onKeyDown={handleEnterKey} />
|
|
229
|
-
</Form.Item>
|
|
230
|
-
</Col>
|
|
231
|
-
|
|
232
|
-
<Col span={12}>
|
|
233
|
-
<Form.Item label="Description" name="description" rules={[{ required: true }]}>
|
|
234
|
-
<Input placeholder="Enter Description" onKeyDown={handleEnterKey} />
|
|
235
|
-
</Form.Item>
|
|
236
|
-
</Col>
|
|
237
|
-
</Row>
|
|
238
|
-
|
|
239
|
-
<Tabs defaultActiveKey="1">
|
|
240
|
-
{/* GENERAL TAB */}
|
|
241
|
-
<Tabs.TabPane tab="GENERAL" key="1">
|
|
242
|
-
<Row gutter={16}>
|
|
243
|
-
<Col span={6}>
|
|
244
|
-
<Form.Item label="Phone Number 1" name="phone1">
|
|
245
|
-
<Input maxLength={10} placeholder="Enter Phone Number" onKeyDown={handleEnterKey} />
|
|
246
|
-
</Form.Item>
|
|
247
|
-
</Col>
|
|
248
|
-
|
|
249
|
-
<Col span={6}>
|
|
250
|
-
<Form.Item label="Phone Number 2" name="phone2">
|
|
251
|
-
<Input maxLength={10} placeholder="Enter Phone Number" onKeyDown={handleEnterKey} />
|
|
252
|
-
</Form.Item>
|
|
253
|
-
</Col>
|
|
254
|
-
|
|
255
|
-
<Col span={6}>
|
|
256
|
-
<Form.Item label="Email ID 1" name="email1">
|
|
257
|
-
<Input placeholder="Enter Email" onKeyDown={handleEnterKey} />
|
|
258
|
-
</Form.Item>
|
|
259
|
-
</Col>
|
|
260
|
-
|
|
261
|
-
<Col span={6}>
|
|
262
|
-
<Form.Item label="Email ID 2" name="email2">
|
|
263
|
-
<Input placeholder="Enter Email" onKeyDown={handleEnterKey} />
|
|
264
|
-
</Form.Item>
|
|
265
|
-
</Col>
|
|
266
|
-
</Row>
|
|
267
|
-
|
|
268
|
-
<Row gutter={16}>
|
|
269
|
-
<Col span={8}>
|
|
270
|
-
<Form.Item name="designation" label="Designation">
|
|
271
|
-
<Select placeholder="Select Designation" options={designations} allowClear showSearch optionFilterProp="label" />
|
|
272
|
-
</Form.Item>
|
|
273
|
-
</Col>
|
|
274
|
-
|
|
275
|
-
<Col span={8}>
|
|
276
|
-
<Form.Item label="Serial Number" name="slno">
|
|
277
|
-
<Input placeholder="Enter Serial Number" onKeyDown={handleEnterKey} />
|
|
278
|
-
</Form.Item>
|
|
279
|
-
</Col>
|
|
280
|
-
|
|
281
|
-
<Col span={8}>
|
|
282
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 30 }}>
|
|
283
|
-
<label>Active</label>
|
|
284
|
-
<Form.Item
|
|
285
|
-
name="active"
|
|
286
|
-
valuePropName="checked"
|
|
287
|
-
getValueFromEvent={(e) => (e.target.checked ? 'Y' : 'N')}
|
|
288
|
-
getValueProps={(value) => ({ checked: value === 'Y' })}
|
|
289
|
-
style={{ marginBottom: 0 }}
|
|
290
|
-
>
|
|
291
|
-
<Checkbox />
|
|
292
|
-
</Form.Item>
|
|
293
|
-
</div>
|
|
294
|
-
</Col>
|
|
295
|
-
</Row>
|
|
296
|
-
|
|
297
|
-
<Row>
|
|
298
|
-
<Col span={24}>
|
|
299
|
-
<Form.Item label="Remarks" name="remarks">
|
|
300
|
-
<Input placeholder="Enter Remarks" onKeyDown={handleEnterKey} />
|
|
301
|
-
</Form.Item>
|
|
302
|
-
</Col>
|
|
303
|
-
</Row>
|
|
304
|
-
</Tabs.TabPane>
|
|
305
|
-
|
|
306
|
-
{/* ADDRESS TAB */}
|
|
307
|
-
<Tabs.TabPane tab="ADDRESS" key="2">
|
|
308
|
-
<Row gutter={16}>
|
|
309
|
-
<Col span={12}>
|
|
310
|
-
<Form.Item label="Address Line 1" name="address1">
|
|
311
|
-
<Input placeholder="Enter Address" onKeyDown={handleEnterKey} />
|
|
312
|
-
</Form.Item>
|
|
313
|
-
</Col>
|
|
314
|
-
|
|
315
|
-
<Col span={12}>
|
|
316
|
-
<Form.Item label="Address Line 2" name="address2">
|
|
317
|
-
<Input placeholder="Enter Address" onKeyDown={handleEnterKey} />
|
|
318
|
-
</Form.Item>
|
|
319
|
-
</Col>
|
|
320
|
-
</Row>
|
|
321
|
-
|
|
322
|
-
<Row gutter={16}>
|
|
323
|
-
<Col span={12}>
|
|
324
|
-
<Form.Item label="Place" name="place">
|
|
325
|
-
<Input placeholder="Enter Place" onKeyDown={handleEnterKey} />
|
|
326
|
-
</Form.Item>
|
|
327
|
-
</Col>
|
|
328
|
-
|
|
329
|
-
<Col span={12}>
|
|
330
|
-
<Form.Item label="Zip Code" name="zip">
|
|
331
|
-
<Input placeholder="Enter Zip Code" maxLength={7} onKeyDown={handleEnterKey} />
|
|
332
|
-
</Form.Item>
|
|
333
|
-
</Col>
|
|
334
|
-
</Row>
|
|
335
|
-
</Tabs.TabPane>
|
|
336
|
-
</Tabs>
|
|
337
|
-
|
|
338
|
-
{/* FOOTER BUTTONS */}
|
|
339
|
-
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
|
|
340
|
-
<Button onClick={onCancel} type="secondary">
|
|
341
|
-
Cancel
|
|
342
|
-
</Button>
|
|
343
|
-
<Button type="primary" htmlType="submit" loading={loading} disabled={isSubmitDisabled}>
|
|
344
|
-
{editMode ? 'Update' : 'Save'}
|
|
345
|
-
</Button>
|
|
346
|
-
</div>
|
|
347
|
-
</Form>
|
|
348
|
-
</Modal>
|
|
349
|
-
);
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
export default StaffAdd;
|
|
File without changes
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Card, Skeleton } from 'antd';
|
|
3
|
-
import { Button } from '../../lib';
|
|
4
|
-
|
|
5
|
-
export default function ActionButtons({
|
|
6
|
-
loading,
|
|
7
|
-
steps,
|
|
8
|
-
activeStep,
|
|
9
|
-
isStepCompleted,
|
|
10
|
-
renderDynamicComponent,
|
|
11
|
-
handlePrevious,
|
|
12
|
-
handleNext,
|
|
13
|
-
handleSkip,
|
|
14
|
-
handleFinish,
|
|
15
|
-
handleStartNextProcess,
|
|
16
|
-
nextProcessId,
|
|
17
|
-
timelineCollapsed,
|
|
18
|
-
}) {
|
|
19
|
-
return (
|
|
20
|
-
<>
|
|
21
|
-
<div style={{ minHeight: 300 }}>
|
|
22
|
-
{loading ? <Skeleton active /> : renderDynamicComponent()}
|
|
23
|
-
|
|
24
|
-
</div>
|
|
25
|
-
<>
|
|
26
|
-
<div style={{ marginTop: 20, display: 'flex', justifyContent: 'flex-start', gap: '10px' }}>
|
|
27
|
-
{/* Back button */}
|
|
28
|
-
<Button disabled={activeStep === 0} onClick={handlePrevious} style={{ marginRight: 8 ,borderRadius: 4, }}>
|
|
29
|
-
Back
|
|
30
|
-
</Button>
|
|
31
|
-
|
|
32
|
-
{/* Skip button */}
|
|
33
|
-
{steps.length > 0 && steps[activeStep]?.allow_skip === 'Y' && (
|
|
34
|
-
<Button type="default" onClick={handleSkip}
|
|
35
|
-
style={{
|
|
36
|
-
borderRadius: 4,
|
|
37
|
-
}}
|
|
38
|
-
disabled={activeStep === steps.length - 1}>
|
|
39
|
-
Skip
|
|
40
|
-
</Button>
|
|
41
|
-
)}
|
|
42
|
-
|
|
43
|
-
{/* Next / Finish / Start Next */}
|
|
44
|
-
{steps[activeStep]?.order_seqtype === 'E' ? (
|
|
45
|
-
nextProcessId?.next_process_id ? (
|
|
46
|
-
<Button type="primary"
|
|
47
|
-
style={{
|
|
48
|
-
borderRadius: 4,
|
|
49
|
-
}}
|
|
50
|
-
onClick={handleStartNextProcess}>
|
|
51
|
-
Start Next {nextProcessId.next_process_name}
|
|
52
|
-
</Button>
|
|
53
|
-
) : (
|
|
54
|
-
<Button type="primary"
|
|
55
|
-
style={{
|
|
56
|
-
borderRadius: 4,
|
|
57
|
-
}}
|
|
58
|
-
onClick={handleFinish}>
|
|
59
|
-
Finish
|
|
60
|
-
</Button>
|
|
61
|
-
)
|
|
62
|
-
) : (
|
|
63
|
-
<Button
|
|
64
|
-
type="primary"
|
|
65
|
-
// shape="round"
|
|
66
|
-
style={{
|
|
67
|
-
borderRadius: 4,
|
|
68
|
-
}}
|
|
69
|
-
disabled={activeStep === steps.length - 1 || !isStepCompleted}
|
|
70
|
-
onClick={handleNext}
|
|
71
|
-
>
|
|
72
|
-
Next →
|
|
73
|
-
</Button>
|
|
74
|
-
)}
|
|
75
|
-
</div>
|
|
76
|
-
</>
|
|
77
|
-
</>
|
|
78
|
-
);
|
|
79
|
-
}
|