ui-soxo-bootstrap-core 2.6.0 → 2.6.1-dev.2

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.
@@ -0,0 +1,124 @@
1
+ /**
2
+ * ResetPassword Component
3
+ *
4
+ * Handles staff password reset flow:
5
+ * - Accepts username
6
+ * - Selects communication mode (email/SMS)
7
+ * - Calls API to send reset link
8
+ * - Displays success/error messages
9
+ * - Allows navigation back to login
10
+ *
11
+ * Props:
12
+ * @param {Function} onBack - Triggered when "Back to Login" is clicked
13
+ * @param {string} title - Page title
14
+ * @param {string} subtitle - Page subtitle
15
+ * @param {string} buttonText - Submit button text
16
+ * @param {string} defaultUsername - Pre-filled username
17
+ * @param {boolean} disabledUserName - Disable username field
18
+ */
19
+
20
+ import React, { useState, useEffect } from 'react';
21
+ import { Divider, Form, Input, message } from 'antd';
22
+ import { Button } from '../../elements';
23
+ import CommunicationModeSelection from './commnication-mode-selection';
24
+ import { motion } from 'framer-motion';
25
+ import './reset-password.scss';
26
+ import { UsersAPI } from '../../../models';
27
+
28
+ function ResetPassword({ onBack, title, subtitle, buttonText, defaultUsername, disabledUserName }) {
29
+ // Selected communication mode (default: email) */
30
+ const [communicationMode, setCommunicationMode] = useState('email');
31
+
32
+ const [modeError, setModeError] = useState(false);
33
+
34
+ // Loading state for submit button */
35
+ const [loading, setLoading] = useState(false);
36
+
37
+ const [form] = Form.useForm();
38
+
39
+ // Pre-fills username if provided and disabled.
40
+ useEffect(() => {
41
+ if (disabledUserName && defaultUsername) {
42
+ form.setFieldsValue({ username: defaultUsername });
43
+ }
44
+ }, [disabledUserName, defaultUsername]);
45
+
46
+ /**
47
+ * Sends forgot password request to backend.
48
+ * Payload: { mode, username, user_type: 'staff' }
49
+ */
50
+ const handleSendForgetPassword = async (values) => {
51
+ const payload = {
52
+ mode: communicationMode,
53
+ username: values.username,
54
+ user_type: 'staff',
55
+ };
56
+ setLoading(true);
57
+
58
+ try {
59
+ const res = await UsersAPI.createForgotePassword(payload);
60
+
61
+ if (!res?.success) {
62
+ throw new Error(res?.message || 'Reset password failed');
63
+ }
64
+
65
+ message.success(res?.message || 'Reset password link sent');
66
+ } catch (err) {
67
+ message.warning(err?.message || 'Reset password failed');
68
+ } finally {
69
+ setLoading(false);
70
+ }
71
+ };
72
+
73
+ /**
74
+ * Clears auth storage and navigates back.
75
+ */
76
+ const handleBackToLogin = () => {
77
+ localStorage.removeItem('access_token');
78
+ localStorage.removeItem('refresh_token');
79
+ sessionStorage.clear();
80
+ onBack();
81
+ };
82
+
83
+ return (
84
+ <motion.div
85
+ className="forgot-password-container"
86
+ initial={{ opacity: 0, y: 70 }}
87
+ animate={{ opacity: 1, y: 0 }}
88
+ exit={{ opacity: 0, y: -50 }}
89
+ transition={{
90
+ y: {
91
+ duration: 1,
92
+ ease: [0.22, 0.08, 0.26, 1],
93
+ },
94
+ opacity: {
95
+ duration: 0.45,
96
+ ease: 'easeOut',
97
+ },
98
+ }}
99
+ >
100
+ <h3 className="password-title">{title}</h3>
101
+ <p className="password-subtitle">{subtitle}</p>
102
+ <Divider />
103
+ <Form layout="vertical" form={form} onFinish={handleSendForgetPassword}>
104
+ <Form.Item label="Username" name="username" rules={[{ required: true, message: 'Please input your username' }]}>
105
+ <Input placeholder="Enter your username" disabled={disabledUserName} />
106
+ </Form.Item>
107
+
108
+ <CommunicationModeSelection communicationMode={communicationMode} setCommunicationMode={setCommunicationMode} modeError={modeError} />
109
+
110
+ <Button type="primary" htmlType="submit" loading={loading}>
111
+ {buttonText}
112
+ </Button>
113
+
114
+ <div style={{ marginTop: '10px', textAlign: 'center' }}>
115
+ <a style={{ cursor: 'pointer' }} onClick={handleBackToLogin}>
116
+ Back to Login
117
+ </a>
118
+ </div>
119
+ </Form>
120
+ </motion.div>
121
+ );
122
+ }
123
+
124
+ export default ResetPassword;
@@ -0,0 +1,22 @@
1
+ .forgot-password-container {
2
+
3
+ padding: 4px;
4
+ .password-title{
5
+ color: #1f1f1f;
6
+ margin: 0 0 8px;
7
+ }
8
+
9
+ .password-subtitle {
10
+ font-size: 14px;
11
+ font-weight: 400;
12
+ color: #6b7280;
13
+ line-height: 1.5;
14
+ margin: 0 0 20px;
15
+ }
16
+
17
+ .ant-divider {
18
+ margin: 0;
19
+ border-top: 1px solid #e5e7eb;
20
+ }
21
+ }
22
+
@@ -1,10 +1,4 @@
1
- import {
2
- PostData,
3
- GetData,
4
- PutData,
5
- PatchData,
6
- DeleteData,
7
- } from "./../http/http.utils";
1
+ import { PostData, GetData, PutData, PatchData, DeleteData } from './../http/http.utils';
8
2
 
9
3
  let headers = {};
10
4
 
@@ -29,40 +23,56 @@ export default class ApiUtils {
29
23
  return this.user;
30
24
  };
31
25
 
32
- static get = ({ url, config = { queries: [], order: {} }, ...props }) => {
33
- const { headers } = settings;
34
-
35
- return GetData({
36
- url: createUrlParams(url, config),
37
- settings,
38
- headers,
39
- ...props,
40
- }).catch((result) => {
41
- console.log(result);
42
- });
26
+ static get = async ({ url, config = { queries: [], order: {} }, headers: customHeaders = {}, ...props }) => {
27
+ const { headers: defaultHeaders } = settings;
28
+
29
+ try {
30
+ return await GetData({
31
+ url: createUrlParams(url, config),
32
+ settings,
33
+ headers: {
34
+ ...defaultHeaders,
35
+ // override here
36
+ ...customHeaders,
37
+ },
38
+ ...props,
39
+ });
40
+ } catch (result_1) {
41
+ console.log(result_1);
42
+ }
43
43
  };
44
44
 
45
- static getRecordDetail = ({ url, config = { queries: [] }, ...props }) => {
46
- const { headers } = settings;
47
-
48
- return GetData({
49
- url: createUrlParams(url, config),
50
- settings,
51
- headers,
52
- ...props,
53
- }).catch((result) => {
54
- console.log(result);
55
- });
45
+ static getRecordDetail = async ({ url, config = { queries: [] }, headers: customHeaders = {}, ...props }) => {
46
+ const { headers: defaultHeaders } = settings;
47
+
48
+ try {
49
+ return await GetData({
50
+ url: createUrlParams(url, config),
51
+ settings,
52
+ headers: {
53
+ ...defaultHeaders,
54
+ // override here
55
+ ...customHeaders,
56
+ },
57
+ ...props,
58
+ });
59
+ } catch (result_1) {
60
+ console.log(result_1);
61
+ }
56
62
  };
57
63
 
58
- static post = ({ url, formBody, ...props }) => {
59
- const { headers } = settings;
64
+ static post = ({ url, formBody, headers: customHeaders = {}, ...props }) => {
65
+ const { headers: defaultHeaders } = settings;
60
66
 
61
67
  return PostData({
62
68
  url,
63
69
  formBody,
64
70
  settings,
65
- headers,
71
+ headers: {
72
+ ...defaultHeaders,
73
+ // override here
74
+ ...customHeaders,
75
+ },
66
76
  ...props,
67
77
  });
68
78
  };
@@ -105,11 +115,11 @@ export default class ApiUtils {
105
115
  static upload = ({ url, data }) => {
106
116
  return fetch(process.env.REACT_APP_endpoint + url, {
107
117
  // Your POST endpoint
108
- method: "POST",
118
+ method: 'POST',
109
119
  headers: {
110
120
  // 'App-Type': 313,
111
121
  // 'App-Version': '1.0.1',
112
- Authorization: "Bearer " + localStorage.access_token,
122
+ Authorization: 'Bearer ' + localStorage.access_token,
113
123
  // type:'multipart/formData'
114
124
  },
115
125
  // credentials: 'include',
@@ -136,16 +146,17 @@ export default class ApiUtils {
136
146
  * @returns
137
147
  */
138
148
  static getAuthStatus = ({ settings: config, token }) => {
139
- headers = headers;
149
+ // headers = headers;
140
150
 
141
151
  settings = config;
142
152
 
143
153
  return GetData({
144
154
  url: `auth/profile`,
145
155
  settings,
146
-
147
- headers,
148
- token
156
+ headers: {
157
+ db_ptr: 'nuraho',
158
+ },
159
+ token,
149
160
  });
150
161
  };
151
162
  }
@@ -159,7 +170,7 @@ function createUrlParams(url, config) {
159
170
  let { queries = [], limit, order } = config;
160
171
 
161
172
  if (queries.length > 0 || limit > 0) {
162
- base_url += "?";
173
+ base_url += '?';
163
174
  }
164
175
 
165
176
  queries.forEach((ele) => {
@@ -122,6 +122,42 @@ export const checkLicenseStatus = (expiryDate) => {
122
122
  return { valid: true, daysLeft, message: null, level: null };
123
123
  };
124
124
 
125
+ /**
126
+ * Checks password expiry status.
127
+ *
128
+ * @param {string|Date} expiryDate
129
+ * @param {number} warningDays
130
+ * @param {string} expiredMessage
131
+ * @param {(daysLeft: number) => string} warningMessage
132
+ *
133
+ * @returns {{ valid: boolean, daysLeft: number, message: string|null, level: "error"|"warning"|null }}
134
+ */
135
+
136
+ export const checkExpiryStatus = ({ expiryDate, warningDays, expiredMessage, warningMessage }) => {
137
+ const expiry = new Date(expiryDate);
138
+
139
+ if (isNaN(expiry)) {
140
+ return { valid: false, daysLeft: 0, message: 'Invalid date', level: 'error' };
141
+ }
142
+
143
+ expiry.setHours(0, 0, 0, 0);
144
+ const today = new Date();
145
+ today.setHours(0, 0, 0, 0);
146
+
147
+ const msDiff = expiry.getTime() - today.getTime();
148
+ const daysLeft = Math.ceil(msDiff / (1000 * 60 * 60 * 24));
149
+
150
+ if (daysLeft < 0) {
151
+ return { valid: false, daysLeft, message: expiredMessage, level: 'error' };
152
+ }
153
+
154
+ if (daysLeft <= warningDays) {
155
+ return { valid: true, daysLeft, message: warningMessage(daysLeft), level: 'warning' };
156
+ }
157
+
158
+ return { valid: true, daysLeft, message: null, level: null };
159
+ };
160
+
125
161
  /**
126
162
  * Masks a mobile number by hiding all but the last `visibleDigits`.
127
163
  * Adds spacing only to the masked portion (groups of 3),
@@ -161,3 +197,27 @@ export const formatMobile = (mobile, visibleDigits = 4) => {
161
197
  // Combine masked and visible parts without spacing the visible digits
162
198
  return `${maskedWithSpaces} ${visible}`;
163
199
  };
200
+
201
+ /**
202
+ * Safely parse a JSON value.
203
+ *
204
+ * - Accepts JSON strings or plain objects
205
+ * - Returns null on any invalid or missing data
206
+ */
207
+ export function safeJSON(value) {
208
+ if (value == null) return null;
209
+
210
+ if (typeof value === 'object' && !Array.isArray(value)) {
211
+ return value;
212
+ }
213
+
214
+ if (typeof value !== 'string' || value.trim() === '') {
215
+ return null;
216
+ }
217
+
218
+ try {
219
+ return JSON.parse(value);
220
+ } catch {
221
+ return null;
222
+ }
223
+ }
@@ -1,10 +1,8 @@
1
-
2
-
3
- import { Location } from './location/location.utils'
1
+ import { Location } from './location/location.utils';
4
2
 
5
3
  import Notification from './notification.utils';
6
4
 
7
- import DateUtils from './date/date.utils'
5
+ import DateUtils from './date/date.utils';
8
6
 
9
7
  import ApiUtils from './api/api.utils';
10
8
 
@@ -16,31 +14,27 @@ import { GetData, PostData, PutData, DeleteData } from './http/http.utils';
16
14
 
17
15
  import { getExportData } from './generic/generic.utils';
18
16
 
19
- import { ConvertBytesToArray } from './common/common.utils';
17
+ import { ConvertBytesToArray, safeJSON } from './common/common.utils';
20
18
 
21
19
  import SettingsUtil from './setting.utils';
22
20
 
23
-
24
21
  export {
25
- // FirebaseUtils,
26
-
27
- Notification,
28
-
29
- Location,
30
- DateUtils,
31
- ApiUtils,
32
- UploadUtils,
33
- GetData,
34
- PostData,
35
- PutData,
36
- DeleteData,
37
-
38
- getExportData,
39
-
40
-
41
- // Common Functions
42
- ConvertBytesToArray,
43
-
44
- SettingsUtil,
45
- FormUtils
46
- }
22
+ // FirebaseUtils,
23
+
24
+ Notification,
25
+ Location,
26
+ DateUtils,
27
+ ApiUtils,
28
+ UploadUtils,
29
+ GetData,
30
+ PostData,
31
+ PutData,
32
+ DeleteData,
33
+ getExportData,
34
+
35
+ // Common Functions
36
+ ConvertBytesToArray,
37
+ SettingsUtil,
38
+ FormUtils,
39
+ safeJSON,
40
+ };
@@ -155,6 +155,15 @@ class RolesAPI extends BaseAPI {
155
155
 
156
156
  /**
157
157
  * Cutsom Api for creating user
158
+ getRole = () => {
159
+ return ApiUtils.get({
160
+ url: `core-roles/get-core-roles?active=Y`,
161
+ });
162
+ };
163
+
164
+
165
+ /**
166
+ * Cutsom Api for updating user
158
167
  *
159
168
  * @param {*} values
160
169
  * @returns
@@ -6,7 +6,7 @@ import { Skeleton, Typography, message, Switch, Form, Input, Select, Checkbox, R
6
6
 
7
7
  import AsyncSelect from 'react-select/async';
8
8
 
9
- import { Table, Card, Button, JSONInput, GlobalContext } from './../../../../lib/';
9
+ import { Table, Card, Button, JSONInput, GlobalContext, safeJSON } from './../../../../lib/';
10
10
 
11
11
  import { ModelsAPI, PagesAPI, RolesAPI } from '../../..';
12
12
 
@@ -42,7 +42,7 @@ const UserAdd = ({ model, callback, edit, history, formContent, match, additiona
42
42
  const [selectedStaff, setSelectedStaff] = useState(null);
43
43
  const [staffList, setStaffList] = useState([]);
44
44
  /**Converting to JSON */
45
- let firmDetails = JSON.parse(user.firm.f_otherdetails1);
45
+ const firmDetails = safeJSON(user?.firm?.f_otherdetails1) ?? {};
46
46
 
47
47
  /**Variable for cheaking mandatory condition of mobile*/
48
48
  let mobileRequired;
@@ -149,7 +149,13 @@ class Users extends Base {
149
149
  * @returns
150
150
  */
151
151
  create = (formBody) => {
152
- return ApiUtils.post({ url: `users/create-user`, formBody });
152
+ return ApiUtils.post({
153
+ url: `users/create-user`,
154
+ formBody,
155
+ headers: {
156
+ db_ptr: 'nuraho',
157
+ },
158
+ });
153
159
  };
154
160
 
155
161
  /**
@@ -161,7 +167,7 @@ class Users extends Base {
161
167
  return ApiUtils.get({
162
168
  url: `branch-master/get-records`,
163
169
  headers: {
164
- db_ptr: process.env.REACT_APP_HO_DB_PTR,
170
+ db_ptr: 'nuraho',
165
171
  },
166
172
  });
167
173
  };
@@ -271,9 +277,15 @@ class Users extends Base {
271
277
  * @returns
272
278
  */
273
279
  updateUser = ({ id, formBody }) => {
274
- return ApiUtils.put({ url: `users/update-user/${id}`, formBody });
280
+ return ApiUtils.put({
281
+ url: `users/update-user/${id}`,
282
+ formBody,
283
+ headers: {
284
+ db_ptr: 'nuraho',
285
+ },
286
+ });
275
287
  };
276
-
288
+
277
289
  /* The `getUser` method is a function that takes an object with an `id` property as a parameter. It
278
290
  then uses the `ApiUtils.get` function to make a GET request to the endpoint `users/` to fetch
279
291
  user data based on the provided `id`. This method is used to retrieve a specific user's
@@ -282,14 +294,13 @@ class Users extends Base {
282
294
  getUser = ({ id }) => {
283
295
  return ApiUtils.get({ url: `users/${id}` });
284
296
  };
285
- /* The `getUserRole` method is a function that takes an object with an `id` property as a parameter.
297
+ /* The `getUserRole` method is a function that takes an object with an `id` property as a parameter.
286
298
  It then uses the `ApiUtils.get` function to make a GET request to the endpoint `core-user-roles`
287
299
  with the `user_id` parameter set to the provided `id`. This method is used to fetch the role or
288
300
  roles associated with a specific user from the API. */
289
-
301
+
290
302
  getUserRole = ({ id }) => {
291
303
  return ApiUtils.get({ url: `core-user-roles?user_id=${id}&active=Y` });
292
-
293
304
  };
294
305
 
295
306
  /**
@@ -348,6 +359,13 @@ class Users extends Base {
348
359
  url: 'staff/get-all-staff',
349
360
  });
350
361
  };
362
+
363
+ createForgotePassword = (formBody) => {
364
+ return ApiUtils.post({
365
+ url: `bookings/trigger-reset-password-link`,
366
+ formBody,
367
+ });
368
+ };
351
369
  }
352
370
 
353
371
  export default Users;