ui-soxo-bootstrap-core 2.4.25-dev.21 → 2.4.25-dev.23
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/components/external-window/{index.test.js → external-window.test.js} +12 -12
- package/core/components/index.js +1 -1
- package/core/lib/components/sidemenu/sidemenu.js +21 -16
- package/core/models/staff/components/staff-add/staff-add.js +82 -54
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +6 -1
- package/package.json +1 -1
- /package/core/components/external-window/{index.js → external-window.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen, act } from '@testing-library/react';
|
|
3
|
-
import { ExternalWindow } from './
|
|
3
|
+
import { ExternalWindow } from './external-window';
|
|
4
4
|
|
|
5
5
|
// Mock window.open
|
|
6
6
|
global.open = jest.fn(() => {
|
|
@@ -21,8 +21,8 @@ global.open = jest.fn(() => {
|
|
|
21
21
|
removeEventListener: jest.fn(),
|
|
22
22
|
close: jest.fn(),
|
|
23
23
|
screen: {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
availWidth: 1920,
|
|
25
|
+
availHeight: 1080,
|
|
26
26
|
},
|
|
27
27
|
getComputedStyle: jest.fn().mockReturnValue({}),
|
|
28
28
|
};
|
|
@@ -31,16 +31,16 @@ global.open = jest.fn(() => {
|
|
|
31
31
|
|
|
32
32
|
// Mock getComputedStyle
|
|
33
33
|
global.getComputedStyle = jest.fn(() => ({
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
backgroundColor: '#ffffff',
|
|
35
|
+
color: '#000000'
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
38
|
// Mock message.error
|
|
39
39
|
jest.mock('antd', () => ({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
...jest.requireActual('antd'),
|
|
41
|
+
message: {
|
|
42
|
+
error: jest.fn(),
|
|
43
|
+
},
|
|
44
44
|
}));
|
|
45
45
|
|
|
46
46
|
describe('ExternalWindow', () => {
|
|
@@ -61,11 +61,11 @@ describe('ExternalWindow', () => {
|
|
|
61
61
|
it('calls window.close on unmount', () => {
|
|
62
62
|
const handleClose = jest.fn();
|
|
63
63
|
const { unmount } = render(<ExternalWindow onClose={handleClose} />);
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
const newWindow = global.open.mock.results[0].value;
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
unmount(); // cleanup
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
expect(newWindow.close).toHaveBeenCalledTimes(1);
|
|
70
70
|
});
|
|
71
71
|
|
package/core/components/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import RootApplicationAPI from './root-application-api/root-application-api';
|
|
|
10
10
|
|
|
11
11
|
import { HomePageAPI } from '../modules';
|
|
12
12
|
|
|
13
|
-
import { ExternalWindow } from './external-window';
|
|
13
|
+
import { ExternalWindow } from './external-window/external-window';
|
|
14
14
|
|
|
15
15
|
export {
|
|
16
16
|
LandingAPI,
|
|
@@ -158,29 +158,32 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
158
158
|
|
|
159
159
|
// callback();
|
|
160
160
|
// };
|
|
161
|
+
|
|
161
162
|
|
|
162
163
|
const onMenuClick = (menu, index) => {
|
|
163
164
|
const key = menu.path || `menu-${menu.id || index}`;
|
|
164
|
-
const parentKey = menu.parentKey;
|
|
165
165
|
|
|
166
|
-
// Keep submenu highlighted
|
|
167
166
|
setSelectedKeys([key]);
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
setOpenKeys((prev) =>
|
|
173
|
-
prev.includes(parentKey) ? prev : [...prev, parentKey]
|
|
174
|
-
);
|
|
175
|
-
}
|
|
168
|
+
if (menu.path) {
|
|
169
|
+
history.push(menu.path);
|
|
170
|
+
}
|
|
176
171
|
|
|
177
|
-
history.push(menu.path);
|
|
178
172
|
setMenu(menu);
|
|
179
|
-
|
|
180
173
|
if (callback) callback();
|
|
181
174
|
};
|
|
175
|
+
|
|
182
176
|
|
|
183
177
|
const onOpenChange = (keys) => {
|
|
178
|
+
const latestOpenKey = keys.find((k) => !openKeys.includes(k));
|
|
179
|
+
|
|
180
|
+
// If opening a ROOT menu → close other roots
|
|
181
|
+
if (rootSubmenuKeys.includes(latestOpenKey)) {
|
|
182
|
+
setOpenKeys([latestOpenKey]);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Otherwise (2nd / 3rd level) → keep ALL parents open
|
|
184
187
|
setOpenKeys(keys);
|
|
185
188
|
};
|
|
186
189
|
|
|
@@ -207,6 +210,8 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
207
210
|
// document.documentElement.style.setProperty('--custom-text-color', state.theme.colors.colorText);
|
|
208
211
|
}, [state.theme]);
|
|
209
212
|
|
|
213
|
+
const rootSubmenuKeys = Menus.screenMenus(modules, 'order').map((m) => m.path || m.caption);
|
|
214
|
+
|
|
210
215
|
return (
|
|
211
216
|
<div className="sidemenu">
|
|
212
217
|
{loading ? (
|
|
@@ -337,7 +342,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
337
342
|
let sub_menus = menu && menu.sub_menus ? Menus.screenMenus(menu.sub_menus) : [];
|
|
338
343
|
|
|
339
344
|
if (menu && sub_menus && sub_menus.length) {
|
|
340
|
-
let randomIndex = parseInt(Math.random() * 10000000000);
|
|
345
|
+
// let randomIndex = parseInt(Math.random() * 10000000000);
|
|
341
346
|
|
|
342
347
|
return (
|
|
343
348
|
<SubMenu
|
|
@@ -358,7 +363,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
358
363
|
}
|
|
359
364
|
>
|
|
360
365
|
{sub_menus.map((submenu, innerIndex) => {
|
|
361
|
-
let randomIndex = parseInt(Math.random() * 10000000000);
|
|
366
|
+
// let randomIndex = parseInt(Math.random() * 10000000000);
|
|
362
367
|
|
|
363
368
|
let third_menus = submenu && submenu.sub_menus ? Menus.screenMenus(submenu.sub_menus) : [];
|
|
364
369
|
|
|
@@ -381,7 +386,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
381
386
|
}
|
|
382
387
|
>
|
|
383
388
|
{third_menus.map((menu) => {
|
|
384
|
-
let randomIndex = parseInt(Math.random() * 10000000000);
|
|
389
|
+
// let randomIndex = parseInt(Math.random() * 10000000000);
|
|
385
390
|
|
|
386
391
|
return (
|
|
387
392
|
<Menu.Item
|
|
@@ -407,7 +412,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
407
412
|
</SubMenu>
|
|
408
413
|
);
|
|
409
414
|
} else {
|
|
410
|
-
let randomIndex = parseInt(Math.random() * 10000000000);
|
|
415
|
+
// let randomIndex = parseInt(Math.random() * 10000000000);
|
|
411
416
|
|
|
412
417
|
return (
|
|
413
418
|
<Menu.Item
|
|
@@ -433,7 +438,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
433
438
|
</SubMenu>
|
|
434
439
|
);
|
|
435
440
|
} else {
|
|
436
|
-
let randomIndex = parseInt(Math.random() * 10000000000);
|
|
441
|
+
// let randomIndex = parseInt(Math.random() * 10000000000);
|
|
437
442
|
|
|
438
443
|
return (
|
|
439
444
|
<Menu.Item
|
|
@@ -43,9 +43,11 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
43
43
|
setIsSubmitDisabled(!(watchedName && watchedCode && watchedDesc));
|
|
44
44
|
}, [watchedName, watchedCode, watchedDesc]);
|
|
45
45
|
|
|
46
|
-
// Load designations when modal opens
|
|
46
|
+
// Load designations and staff list when modal opens
|
|
47
47
|
useEffect(() => {
|
|
48
|
-
if (visible)
|
|
48
|
+
if (visible) {
|
|
49
|
+
getDesignations();
|
|
50
|
+
}
|
|
49
51
|
}, [visible]);
|
|
50
52
|
|
|
51
53
|
// Reset or fill edit form
|
|
@@ -93,61 +95,61 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
93
95
|
.finally(() => setLoading(false));
|
|
94
96
|
};
|
|
95
97
|
|
|
98
|
+
|
|
96
99
|
/** -------------------------------
|
|
97
|
-
* VALIDATION –
|
|
100
|
+
* VALIDATION – Input
|
|
98
101
|
* ------------------------------- */
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// Starting space not allowed
|
|
108
|
-
if (value.startsWith(' ')) {
|
|
109
|
-
setCodeStatus({
|
|
110
|
-
status: 'error',
|
|
111
|
-
message: 'Code cannot start with a space',
|
|
112
|
-
});
|
|
113
|
-
return Promise.reject(new Error('Code cannot start with a space'));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Any space not allowed
|
|
117
|
-
if (/\s/.test(value)) {
|
|
118
|
-
setCodeStatus({
|
|
119
|
-
status: 'error',
|
|
120
|
-
message: 'Spaces are not allowed in the code',
|
|
121
|
-
});
|
|
122
|
-
return Promise.reject(new Error('Spaces are not allowed in the code'));
|
|
102
|
+
const validateInput = async (rule, value) => {
|
|
103
|
+
// Common check: Starting space
|
|
104
|
+
if (value && value.startsWith(' ')) {
|
|
105
|
+
const msg = rule.message || 'Cannot start with a space';
|
|
106
|
+
if (rule.field === 'id') {
|
|
107
|
+
setCodeStatus({ status: 'error', message: msg });
|
|
108
|
+
}
|
|
109
|
+
return Promise.reject(new Error(msg));
|
|
123
110
|
}
|
|
124
111
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
112
|
+
// Specific check: Code (id)
|
|
113
|
+
if (rule.field === 'id') {
|
|
114
|
+
if (editMode) return Promise.resolve();
|
|
128
115
|
|
|
129
|
-
if (
|
|
130
|
-
setCodeStatus({ status: '
|
|
131
|
-
|
|
132
|
-
return Promise.reject(new Error(res.message || 'Code already exists'));
|
|
116
|
+
if (!value) {
|
|
117
|
+
setCodeStatus({ status: '', message: '' });
|
|
118
|
+
return Promise.resolve();
|
|
133
119
|
}
|
|
134
120
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
140
|
-
return Promise.resolve();
|
|
121
|
+
// Any space check
|
|
122
|
+
if (/\s/.test(value)) {
|
|
123
|
+
setCodeStatus({ status: 'error', message: 'Spaces are not allowed in the code' });
|
|
124
|
+
return Promise.reject(new Error('Spaces are not allowed in the code'));
|
|
141
125
|
}
|
|
142
126
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
127
|
+
// API Check
|
|
128
|
+
try {
|
|
129
|
+
const res = await UsersAPI.getStaffCode(value);
|
|
130
|
+
|
|
131
|
+
if (res?.status === 409 || res?.success === false) {
|
|
132
|
+
setCodeStatus({ status: 'error', message: res.message || 'Code already exists' });
|
|
133
|
+
return Promise.reject(new Error(res.message || 'Code already exists'));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (res?.status === 200 && res?.success === true) {
|
|
137
|
+
setCodeStatus({ status: 'success', message: 'The entered code is valid for assigning a staff.' });
|
|
138
|
+
return Promise.resolve();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setCodeStatus({ status: 'error', message: 'Please enter a valid code' });
|
|
142
|
+
return Promise.reject(new Error('Please enter a valid code'));
|
|
143
|
+
} catch {
|
|
144
|
+
setCodeStatus({ status: 'error', message: 'Validation failed' });
|
|
145
|
+
return Promise.reject(new Error('Validation failed'));
|
|
146
|
+
}
|
|
148
147
|
}
|
|
148
|
+
|
|
149
|
+
return Promise.resolve();
|
|
149
150
|
};
|
|
150
151
|
|
|
152
|
+
|
|
151
153
|
/** -------------------------------
|
|
152
154
|
* UTIL – Enter Key Navigation
|
|
153
155
|
* ------------------------------- */
|
|
@@ -171,8 +173,8 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
171
173
|
shortName: data.shortName,
|
|
172
174
|
description: data.description,
|
|
173
175
|
designation: data.designationPtr,
|
|
174
|
-
phone1: data.phone,
|
|
175
|
-
phone2: data.
|
|
176
|
+
phone1: data.phone || data.mobile,
|
|
177
|
+
phone2: data.alternateMobile,
|
|
176
178
|
email1: data.email,
|
|
177
179
|
email2: data.alternateEmail,
|
|
178
180
|
slno: data.slNo,
|
|
@@ -249,19 +251,38 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
249
251
|
name="id"
|
|
250
252
|
validateTrigger="onChange"
|
|
251
253
|
hasFeedback={!editMode}
|
|
252
|
-
rules={[
|
|
254
|
+
rules={[
|
|
255
|
+
{ required: true, message: 'Code is required' },
|
|
256
|
+
{ validator: validateInput },
|
|
257
|
+
]}
|
|
253
258
|
>
|
|
254
259
|
<Input placeholder="Enter Code" autoComplete="off" maxLength={10} ref={nameInputRef} onKeyDown={handleEnterKey} disabled={editMode} />
|
|
255
260
|
</Form.Item>
|
|
256
261
|
</Col>
|
|
257
262
|
|
|
258
263
|
<Col span={12}>
|
|
259
|
-
<Form.Item
|
|
264
|
+
<Form.Item
|
|
265
|
+
label="Name"
|
|
266
|
+
name="description"
|
|
267
|
+
rules={[
|
|
268
|
+
{ required: true, message: 'Name is required' },
|
|
269
|
+
{ pattern: /^[A-Za-z\s]+$/, message: 'Name should contain only alphabets' },
|
|
270
|
+
{ validator: validateInput, message: 'Name cannot start with a space' },
|
|
271
|
+
]}
|
|
272
|
+
>
|
|
260
273
|
<Input placeholder="Enter Description" autoComplete="off" onKeyDown={handleEnterKey} />
|
|
261
274
|
</Form.Item>
|
|
262
275
|
</Col>
|
|
263
276
|
<Col span={6}>
|
|
264
|
-
<Form.Item
|
|
277
|
+
<Form.Item
|
|
278
|
+
label="Short Name"
|
|
279
|
+
name="shortName"
|
|
280
|
+
rules={[
|
|
281
|
+
{ required: true, message: 'Short Name is required' },
|
|
282
|
+
{ pattern: /^[A-Za-z\s]+$/, message: 'Name should contain only alphabets' },
|
|
283
|
+
{ validator: validateInput, message: 'Short Name cannot start with a space' },
|
|
284
|
+
]}
|
|
285
|
+
>
|
|
265
286
|
<Input placeholder="Enter Short Name" autoComplete="off" onKeyDown={handleEnterKey} maxLength={10} />
|
|
266
287
|
</Form.Item>
|
|
267
288
|
</Col>
|
|
@@ -309,13 +330,13 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
309
330
|
</Col>
|
|
310
331
|
|
|
311
332
|
<Col span={6}>
|
|
312
|
-
<Form.Item label="Email ID" name="email1">
|
|
333
|
+
<Form.Item label="Email ID" name="email1" rules={[{ type: 'email', message: 'Please enter a valid email' }]}>
|
|
313
334
|
<Input autoComplete="off" placeholder="Enter Email" onKeyDown={handleEnterKey} />
|
|
314
335
|
</Form.Item>
|
|
315
336
|
</Col>
|
|
316
337
|
|
|
317
338
|
<Col span={6}>
|
|
318
|
-
<Form.Item label="Alternate Email" name="email2">
|
|
339
|
+
<Form.Item label="Alternate Email" name="email2" rules={[{ type: 'email', message: 'Please enter a valid email' }]}>
|
|
319
340
|
<Input autoComplete="off" placeholder="Enter Email" onKeyDown={handleEnterKey} />
|
|
320
341
|
</Form.Item>
|
|
321
342
|
</Col>
|
|
@@ -330,7 +351,7 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
330
351
|
|
|
331
352
|
<Col span={8}>
|
|
332
353
|
<Form.Item label="Serial Number" name="slno" rules={[{ message: 'only numbers are allowed', pattern: /^\d*$/ }]}>
|
|
333
|
-
<Input autoComplete="off" maxLength={5} placeholder="Enter Serial Number" onKeyDown={handleEnterKey} />
|
|
354
|
+
<Input autoComplete="off" maxLength={5} placeholder="Enter Serial Number" onKeyDown={handleEnterKey} disabled={editMode} />
|
|
334
355
|
</Form.Item>
|
|
335
356
|
</Col>
|
|
336
357
|
|
|
@@ -352,7 +373,14 @@ const StaffAdd = ({ visible, onCancel, staffId, staffData, onSuccess }) => {
|
|
|
352
373
|
|
|
353
374
|
<Row>
|
|
354
375
|
<Col span={24}>
|
|
355
|
-
<Form.Item
|
|
376
|
+
<Form.Item
|
|
377
|
+
label="Remarks"
|
|
378
|
+
name="remarks"
|
|
379
|
+
rules={[
|
|
380
|
+
{ max: 50, message: 'Remarks must be less than 50 characters' },
|
|
381
|
+
{ validator: validateInput, message: 'Remarks cannot start with a space' },
|
|
382
|
+
]}
|
|
383
|
+
>
|
|
356
384
|
<Input autoComplete="off" placeholder="Enter Remarks" onKeyDown={handleEnterKey} />
|
|
357
385
|
</Form.Item>
|
|
358
386
|
</Col>
|
|
@@ -614,6 +614,8 @@ function GuestList({
|
|
|
614
614
|
{
|
|
615
615
|
title: '#',
|
|
616
616
|
dataIndex: 'index',
|
|
617
|
+
key: 'ColumnIndex',
|
|
618
|
+
width: 60,
|
|
617
619
|
render: (value, item, index) => index + 1,
|
|
618
620
|
key: 'ColumnIndex',
|
|
619
621
|
fixed: isFixedIndex ? 'left' : null,
|
|
@@ -777,6 +779,8 @@ function GuestList({
|
|
|
777
779
|
field: entry.field,
|
|
778
780
|
title: entry.title,
|
|
779
781
|
key: entry.field,
|
|
782
|
+
width: entry.width || 160,
|
|
783
|
+
ellipsis: true,
|
|
780
784
|
fixed: entry.isFixedColumn ? entry.isFixedColumn : null, // Conditionally setting the 'fixed' key to 'left' if 'isColumnStatic' is true; otherwise, setting it to null.
|
|
781
785
|
// Check if filtering is enabled and patients is an array
|
|
782
786
|
filters:
|
|
@@ -1042,7 +1046,8 @@ function GuestList({
|
|
|
1042
1046
|
) : (
|
|
1043
1047
|
<TableComponent
|
|
1044
1048
|
size="small"
|
|
1045
|
-
scroll={{ x:
|
|
1049
|
+
scroll={{ x: 'max-content', y: '60vh' }}
|
|
1050
|
+
tableLayout="fixed"
|
|
1046
1051
|
sticky
|
|
1047
1052
|
rowKey={(record) => record.OpNo}
|
|
1048
1053
|
dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
|
package/package.json
CHANGED
|
File without changes
|