ui-soxo-bootstrap-core 2.4.24 → 2.4.25-dev.6
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/README.md +260 -0
- 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/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 +230 -268
- package/core/models/menus/components/menu-lists/menu-lists.js +126 -89
- package/core/models/menus/components/menu-lists/menu-lists.scss +9 -0
- package/core/models/menus/menus.js +247 -267
- package/core/models/roles/components/role-add/role-add.js +269 -227
- package/core/models/roles/components/role-list/role-list.js +8 -6
- package/core/models/roles/roles.js +182 -174
- package/core/models/users/components/user-add/user-add.js +619 -365
- package/core/models/users/components/user-add/user-edit.js +90 -0
- package/core/models/users/users.js +261 -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
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
width: 17%;
|
|
44
44
|
background: #fff;
|
|
45
45
|
// border-bottom: 1.5px solid #24aeb8;
|
|
46
|
-
&.close{
|
|
47
|
-
width:6% !important
|
|
46
|
+
&.close {
|
|
47
|
+
width: 6% !important;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.logo-wrapper {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
|
|
71
71
|
@media only screen and (max-width: 500px) {
|
|
72
72
|
margin-right: 0px;
|
|
73
|
-
// margin: 10px;
|
|
73
|
+
// margin: 10px;
|
|
74
74
|
width: 150px;
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
|
|
161
161
|
/* Pseudo-element (as before) */
|
|
162
162
|
.menu-collapsed::after {
|
|
163
|
-
content:
|
|
163
|
+
content: '';
|
|
164
164
|
position: absolute;
|
|
165
165
|
top: -100%;
|
|
166
166
|
left: 0;
|
|
@@ -175,26 +175,26 @@
|
|
|
175
175
|
// background-color: #E0EBFF;
|
|
176
176
|
// transform: scale(0.95); /* Apply scale effect on hover */
|
|
177
177
|
}
|
|
178
|
-
/* Style selected item */
|
|
179
|
-
.ant-menu{
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
// .ant-menu-inline .ant-menu-item::after{
|
|
183
|
-
// border-right: none;
|
|
184
|
-
// }
|
|
185
|
-
// .ant-menu-item-selected {
|
|
186
|
-
// background-color: var(--selected-bg-color) !important;
|
|
187
|
-
// color: var(--selected-text-color) !important;
|
|
188
|
-
// border-radius: 12px;
|
|
189
|
-
// // font-weight: 600;
|
|
190
|
-
// // margin: 4px 8px;
|
|
191
|
-
// }
|
|
192
|
-
|
|
193
|
-
// /* Optional: remove hover effects */
|
|
194
|
-
// .ant-menu-item:hover {
|
|
195
|
-
// background-color: transparent !important;
|
|
196
|
-
// color: transparent !important;
|
|
197
|
-
// }
|
|
178
|
+
/* Style selected item */
|
|
179
|
+
.ant-menu {
|
|
180
|
+
background-color: transparent !important;
|
|
181
|
+
}
|
|
182
|
+
// .ant-menu-inline .ant-menu-item::after{
|
|
183
|
+
// border-right: none;
|
|
184
|
+
// }
|
|
185
|
+
// .ant-menu-item-selected {
|
|
186
|
+
// background-color: var(--selected-bg-color) !important;
|
|
187
|
+
// color: var(--selected-text-color) !important;
|
|
188
|
+
// border-radius: 12px;
|
|
189
|
+
// // font-weight: 600;
|
|
190
|
+
// // margin: 4px 8px;
|
|
191
|
+
// }
|
|
192
|
+
|
|
193
|
+
// /* Optional: remove hover effects */
|
|
194
|
+
// .ant-menu-item:hover {
|
|
195
|
+
// background-color: transparent !important;
|
|
196
|
+
// color: transparent !important;
|
|
197
|
+
// }
|
|
198
198
|
|
|
199
199
|
/* River flow effect */
|
|
200
200
|
.menu-collapsed:hover::after {
|
|
@@ -248,9 +248,7 @@
|
|
|
248
248
|
padding: 0px;
|
|
249
249
|
// width: 100% !important;
|
|
250
250
|
// padding: 10px 16px;
|
|
251
|
-
|
|
252
251
|
}
|
|
253
|
-
|
|
254
252
|
|
|
255
253
|
.menu-item {
|
|
256
254
|
width: 100% !important;
|
|
@@ -262,3 +260,18 @@
|
|
|
262
260
|
}
|
|
263
261
|
}
|
|
264
262
|
}
|
|
263
|
+
|
|
264
|
+
.ant-menu-item:hover {
|
|
265
|
+
background-color: #e6f7ff !important;
|
|
266
|
+
color: #1677ff !important;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Tooltip styling if needed */
|
|
270
|
+
.ant-tooltip-inner {
|
|
271
|
+
max-width: 200px;
|
|
272
|
+
white-space: nowrap;
|
|
273
|
+
overflow: hidden;
|
|
274
|
+
text-overflow: ellipsis;
|
|
275
|
+
background-color: #ffffff !important;
|
|
276
|
+
color: #000000 !important;
|
|
277
|
+
}
|
package/core/lib/hooks/index.js
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
import useDeviceDetect from './device-detect';
|
|
5
2
|
|
|
6
3
|
import useWindowSize from './use-window-size';
|
|
7
4
|
|
|
8
5
|
import useFormUtils from './../utils/form/form.utils';
|
|
9
6
|
import useLocation from './use-location';
|
|
7
|
+
import { useOtpTimer } from './use-otp-timer';
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
useDeviceDetect,
|
|
14
|
-
useWindowSize,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
useFormUtils,
|
|
18
|
-
useLocation
|
|
19
|
-
}
|
|
9
|
+
export { useDeviceDetect, useWindowSize, useOtpTimer, useFormUtils, useLocation };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom hook to manage an OTP (One-Time Password) countdown timer.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Can start a timer directly with seconds.
|
|
8
|
+
* - Can start a timer using an expiry timestamp (from backend).
|
|
9
|
+
* - Provides formatted remaining time (MM:SS).
|
|
10
|
+
* - Tracks whether the timer has expired.
|
|
11
|
+
*
|
|
12
|
+
* @returns {Object} API
|
|
13
|
+
* @returns {number} API.remaining - Remaining seconds.
|
|
14
|
+
* @returns {boolean} API.expired - Whether the timer has expired.
|
|
15
|
+
* @returns {string} API.formatted - Formatted remaining time (MM:SS).
|
|
16
|
+
* @returns {(seconds: number) => void} API.start - Start timer with seconds.
|
|
17
|
+
* @returns {(expirytime: string) => void} API.startFromExpiry - Start timer using expiry string (e.g. "2025-09-04T12:13:09.000Z").
|
|
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
|
+
*/
|
|
39
|
+
|
|
40
|
+
// helper to format time
|
|
41
|
+
const formatTime = (seconds) => {
|
|
42
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
43
|
+
const secs = seconds % 60;
|
|
44
|
+
return `${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const useOtpTimer = () => {
|
|
48
|
+
const [remaining, setRemaining] = useState(0);
|
|
49
|
+
const [expired, setExpired] = useState(false);
|
|
50
|
+
const intervalRef = useRef(null);
|
|
51
|
+
|
|
52
|
+
// Start timer by passing expiry string from backend
|
|
53
|
+
const startFromExpiry = (expirytime) => {
|
|
54
|
+
if (!expirytime) {
|
|
55
|
+
setRemaining(0);
|
|
56
|
+
setExpired(true);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Handle backend expiry string
|
|
61
|
+
const expiryTime = new Date(expirytime).getTime();
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
const seconds = Math.max(0, Math.floor((expiryTime - now) / 1000));
|
|
64
|
+
|
|
65
|
+
start(seconds);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Generic start (seconds)
|
|
69
|
+
const start = (seconds) => {
|
|
70
|
+
clearInterval(intervalRef.current);
|
|
71
|
+
|
|
72
|
+
if (!seconds || seconds <= 0) {
|
|
73
|
+
setRemaining(0);
|
|
74
|
+
setExpired(true);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setRemaining(seconds);
|
|
79
|
+
setExpired(false);
|
|
80
|
+
|
|
81
|
+
intervalRef.current = setInterval(() => {
|
|
82
|
+
setRemaining((prev) => {
|
|
83
|
+
if (prev <= 1) {
|
|
84
|
+
clearInterval(intervalRef.current);
|
|
85
|
+
setExpired(true);
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
return prev - 1;
|
|
89
|
+
});
|
|
90
|
+
}, 1000);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Cleanup on unmount
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
return () => clearInterval(intervalRef.current);
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return { remaining, expired, formatted: formatTime(remaining), start, startFromExpiry };
|
|
99
|
+
};
|