@nocios/crudify-ui 1.0.69 → 1.0.71
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/README.md +375 -0
- package/dist/index.d.mts +146 -17
- package/dist/index.d.ts +146 -17
- package/dist/index.js +901 -639
- package/dist/index.mjs +842 -587
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,7 @@ import { default as default2 } from "@nocios/crudify-browser";
|
|
|
3
3
|
export * from "@nocios/crudify-browser";
|
|
4
4
|
|
|
5
5
|
// src/components/CrudifyLogin/index.tsx
|
|
6
|
-
import
|
|
7
|
-
import { Box as Box5, Typography as Typography5 } from "@mui/material";
|
|
6
|
+
import { Box as Box6, Typography as Typography6 } from "@mui/material";
|
|
8
7
|
|
|
9
8
|
// src/components/CrudifyLogin/context/I18nProvider.tsx
|
|
10
9
|
import { createContext, useContext, useMemo } from "react";
|
|
@@ -94,8 +93,290 @@ var useTranslation = () => {
|
|
|
94
93
|
return context;
|
|
95
94
|
};
|
|
96
95
|
|
|
96
|
+
// src/components/CrudifyLogin/context/CrudifyProvider.tsx
|
|
97
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
98
|
+
import crudify from "@nocios/crudify-browser";
|
|
99
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
100
|
+
var CrudifyContext = createContext2(void 0);
|
|
101
|
+
var CrudifyProvider = ({ config, children }) => {
|
|
102
|
+
const [isLoading, setIsLoading] = useState2(true);
|
|
103
|
+
const [error, setError] = useState2(null);
|
|
104
|
+
const [isInitialized, setIsInitialized] = useState2(false);
|
|
105
|
+
const [initializationKey, setInitializationKey] = useState2("");
|
|
106
|
+
useEffect2(() => {
|
|
107
|
+
if (!config.publicApiKey) {
|
|
108
|
+
setError("No publicApiKey provided");
|
|
109
|
+
setIsLoading(false);
|
|
110
|
+
setIsInitialized(false);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const currentKey = `${config.publicApiKey}-${config.env}`;
|
|
114
|
+
if (currentKey === initializationKey && isInitialized) {
|
|
115
|
+
setIsLoading(false);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const initializeCrudify = async () => {
|
|
119
|
+
setIsLoading(true);
|
|
120
|
+
setError(null);
|
|
121
|
+
setIsInitialized(false);
|
|
122
|
+
try {
|
|
123
|
+
crudify.config(config.env || "prod");
|
|
124
|
+
await crudify.init(config.publicApiKey, "none");
|
|
125
|
+
if (typeof crudify.transaction === "function" && typeof crudify.login === "function") {
|
|
126
|
+
setIsInitialized(true);
|
|
127
|
+
setInitializationKey(currentKey);
|
|
128
|
+
} else {
|
|
129
|
+
throw new Error("Crudify methods not properly initialized");
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to initialize Crudify";
|
|
133
|
+
setError(errorMessage);
|
|
134
|
+
setIsInitialized(false);
|
|
135
|
+
} finally {
|
|
136
|
+
setIsLoading(false);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
initializeCrudify();
|
|
140
|
+
}, [config.publicApiKey, config.env, initializationKey, isInitialized]);
|
|
141
|
+
const value = {
|
|
142
|
+
crudify: isInitialized ? crudify : null,
|
|
143
|
+
isLoading,
|
|
144
|
+
error,
|
|
145
|
+
isInitialized
|
|
146
|
+
};
|
|
147
|
+
return /* @__PURE__ */ jsx2(CrudifyContext.Provider, { value, children });
|
|
148
|
+
};
|
|
149
|
+
var useCrudify = () => {
|
|
150
|
+
const context = useContext2(CrudifyContext);
|
|
151
|
+
if (context === void 0) {
|
|
152
|
+
throw new Error("useCrudify must be used within a CrudifyProvider");
|
|
153
|
+
}
|
|
154
|
+
return context;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/components/CrudifyLogin/context/LoginStateProvider.tsx
|
|
158
|
+
import { createContext as createContext3, useContext as useContext3, useReducer, useEffect as useEffect3 } from "react";
|
|
159
|
+
|
|
160
|
+
// src/components/CrudifyLogin/utils/cookies.ts
|
|
161
|
+
var getCookie = (name) => {
|
|
162
|
+
const match = document.cookie.match(new RegExp("(^|;)\\s*" + name + "=([^;]+)"));
|
|
163
|
+
return match ? match[2] : null;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// src/components/CrudifyLogin/context/LoginStateProvider.tsx
|
|
167
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
168
|
+
var initialState = {
|
|
169
|
+
currentScreen: "login",
|
|
170
|
+
searchParams: {},
|
|
171
|
+
formData: {
|
|
172
|
+
username: "",
|
|
173
|
+
password: "",
|
|
174
|
+
email: "",
|
|
175
|
+
code: "",
|
|
176
|
+
newPassword: "",
|
|
177
|
+
confirmPassword: ""
|
|
178
|
+
},
|
|
179
|
+
loading: false,
|
|
180
|
+
errors: {
|
|
181
|
+
global: []
|
|
182
|
+
},
|
|
183
|
+
emailSent: false,
|
|
184
|
+
codeAlreadyExists: false,
|
|
185
|
+
codeValidated: false,
|
|
186
|
+
fromCodeVerification: false,
|
|
187
|
+
config: {}
|
|
188
|
+
};
|
|
189
|
+
function loginStateReducer(state, action) {
|
|
190
|
+
switch (action.type) {
|
|
191
|
+
case "SET_SCREEN":
|
|
192
|
+
return {
|
|
193
|
+
...state,
|
|
194
|
+
currentScreen: action.payload.screen,
|
|
195
|
+
searchParams: action.payload.params || state.searchParams,
|
|
196
|
+
// Clear form errors when changing screens
|
|
197
|
+
errors: { global: [] }
|
|
198
|
+
};
|
|
199
|
+
case "SET_SEARCH_PARAMS":
|
|
200
|
+
return {
|
|
201
|
+
...state,
|
|
202
|
+
searchParams: action.payload
|
|
203
|
+
};
|
|
204
|
+
case "UPDATE_FORM_DATA":
|
|
205
|
+
return {
|
|
206
|
+
...state,
|
|
207
|
+
formData: {
|
|
208
|
+
...state.formData,
|
|
209
|
+
...action.payload
|
|
210
|
+
},
|
|
211
|
+
// Clear related errors when updating form data
|
|
212
|
+
errors: {
|
|
213
|
+
...state.errors,
|
|
214
|
+
...Object.keys(action.payload).reduce((acc, key) => ({
|
|
215
|
+
...acc,
|
|
216
|
+
[key]: void 0
|
|
217
|
+
}), {})
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
case "SET_LOADING":
|
|
221
|
+
return {
|
|
222
|
+
...state,
|
|
223
|
+
loading: action.payload
|
|
224
|
+
};
|
|
225
|
+
case "SET_ERRORS":
|
|
226
|
+
return {
|
|
227
|
+
...state,
|
|
228
|
+
errors: {
|
|
229
|
+
...state.errors,
|
|
230
|
+
...action.payload
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
case "CLEAR_ERRORS":
|
|
234
|
+
return {
|
|
235
|
+
...state,
|
|
236
|
+
errors: { global: [] }
|
|
237
|
+
};
|
|
238
|
+
case "SET_EMAIL_SENT":
|
|
239
|
+
return {
|
|
240
|
+
...state,
|
|
241
|
+
emailSent: action.payload
|
|
242
|
+
};
|
|
243
|
+
case "SET_CODE_ALREADY_EXISTS":
|
|
244
|
+
return {
|
|
245
|
+
...state,
|
|
246
|
+
codeAlreadyExists: action.payload
|
|
247
|
+
};
|
|
248
|
+
case "SET_CODE_VALIDATED":
|
|
249
|
+
return {
|
|
250
|
+
...state,
|
|
251
|
+
codeValidated: action.payload
|
|
252
|
+
};
|
|
253
|
+
case "SET_FROM_CODE_VERIFICATION":
|
|
254
|
+
return {
|
|
255
|
+
...state,
|
|
256
|
+
fromCodeVerification: action.payload
|
|
257
|
+
};
|
|
258
|
+
case "RESET_FORM":
|
|
259
|
+
return {
|
|
260
|
+
...state,
|
|
261
|
+
formData: initialState.formData,
|
|
262
|
+
errors: { global: [] },
|
|
263
|
+
loading: false,
|
|
264
|
+
emailSent: false,
|
|
265
|
+
codeAlreadyExists: false,
|
|
266
|
+
codeValidated: false,
|
|
267
|
+
fromCodeVerification: false
|
|
268
|
+
};
|
|
269
|
+
case "INIT_CONFIG":
|
|
270
|
+
return {
|
|
271
|
+
...state,
|
|
272
|
+
config: action.payload
|
|
273
|
+
};
|
|
274
|
+
default:
|
|
275
|
+
return state;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
var LoginStateContext = createContext3(void 0);
|
|
279
|
+
var LoginStateProvider = ({
|
|
280
|
+
children,
|
|
281
|
+
initialScreen = "login",
|
|
282
|
+
config: providedConfig,
|
|
283
|
+
autoReadFromCookies = true
|
|
284
|
+
}) => {
|
|
285
|
+
const [state, dispatch] = useReducer(loginStateReducer, {
|
|
286
|
+
...initialState,
|
|
287
|
+
currentScreen: initialScreen
|
|
288
|
+
});
|
|
289
|
+
useEffect3(() => {
|
|
290
|
+
const buildFinalConfig = () => {
|
|
291
|
+
let cookieConfig = {};
|
|
292
|
+
if (autoReadFromCookies) {
|
|
293
|
+
try {
|
|
294
|
+
const encodedLogo = getCookie("logo");
|
|
295
|
+
if (encodedLogo) {
|
|
296
|
+
const decodedLogo = decodeURIComponent(encodedLogo);
|
|
297
|
+
if (decodedLogo.startsWith("http")) {
|
|
298
|
+
cookieConfig.logo = decodedLogo;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const colorsCookie = getCookie("colors");
|
|
302
|
+
if (colorsCookie) {
|
|
303
|
+
const decodedColorsString = decodeURIComponent(colorsCookie);
|
|
304
|
+
const parsedColors = JSON.parse(decodedColorsString);
|
|
305
|
+
cookieConfig.colors = { primaryColor: "#1066BA", ...parsedColors };
|
|
306
|
+
} else {
|
|
307
|
+
cookieConfig.colors = { primaryColor: "#1066BA" };
|
|
308
|
+
}
|
|
309
|
+
} catch (e) {
|
|
310
|
+
console.error("Error reading configuration from cookies:", e);
|
|
311
|
+
cookieConfig.colors = { primaryColor: "#1066BA" };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
publicApiKey: providedConfig?.publicApiKey,
|
|
316
|
+
env: providedConfig?.env,
|
|
317
|
+
appName: providedConfig?.appName,
|
|
318
|
+
logo: providedConfig?.logo || cookieConfig.logo,
|
|
319
|
+
colors: { ...cookieConfig.colors, ...providedConfig?.colors },
|
|
320
|
+
loginActions: providedConfig?.loginActions
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
dispatch({ type: "INIT_CONFIG", payload: buildFinalConfig() });
|
|
324
|
+
}, [providedConfig, autoReadFromCookies]);
|
|
325
|
+
useEffect3(() => {
|
|
326
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
327
|
+
const paramsObject = {};
|
|
328
|
+
urlParams.forEach((value2, key) => {
|
|
329
|
+
paramsObject[key] = value2;
|
|
330
|
+
});
|
|
331
|
+
if (Object.keys(paramsObject).length > 0) {
|
|
332
|
+
dispatch({ type: "SET_SEARCH_PARAMS", payload: paramsObject });
|
|
333
|
+
}
|
|
334
|
+
if (initialScreen === "checkCode" && paramsObject.email) {
|
|
335
|
+
dispatch({
|
|
336
|
+
type: "UPDATE_FORM_DATA",
|
|
337
|
+
payload: { email: paramsObject.email, code: paramsObject.code || "" }
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
if (initialScreen === "resetPassword" && paramsObject.link) {
|
|
341
|
+
dispatch({ type: "SET_SEARCH_PARAMS", payload: paramsObject });
|
|
342
|
+
}
|
|
343
|
+
}, [initialScreen]);
|
|
344
|
+
const setScreen = (screen2, params) => {
|
|
345
|
+
dispatch({ type: "SET_SCREEN", payload: { screen: screen2, params } });
|
|
346
|
+
};
|
|
347
|
+
const updateFormData = (data) => {
|
|
348
|
+
dispatch({ type: "UPDATE_FORM_DATA", payload: data });
|
|
349
|
+
};
|
|
350
|
+
const setFieldError = (field, error) => {
|
|
351
|
+
dispatch({ type: "SET_ERRORS", payload: { [field]: error } });
|
|
352
|
+
};
|
|
353
|
+
const clearErrors = () => {
|
|
354
|
+
dispatch({ type: "CLEAR_ERRORS" });
|
|
355
|
+
};
|
|
356
|
+
const setLoading = (loading) => {
|
|
357
|
+
dispatch({ type: "SET_LOADING", payload: loading });
|
|
358
|
+
};
|
|
359
|
+
const value = {
|
|
360
|
+
state,
|
|
361
|
+
dispatch,
|
|
362
|
+
setScreen,
|
|
363
|
+
updateFormData,
|
|
364
|
+
setFieldError,
|
|
365
|
+
clearErrors,
|
|
366
|
+
setLoading
|
|
367
|
+
};
|
|
368
|
+
return /* @__PURE__ */ jsx3(LoginStateContext.Provider, { value, children });
|
|
369
|
+
};
|
|
370
|
+
var useLoginState = () => {
|
|
371
|
+
const context = useContext3(LoginStateContext);
|
|
372
|
+
if (context === void 0) {
|
|
373
|
+
throw new Error("useLoginState must be used within a LoginStateProvider");
|
|
374
|
+
}
|
|
375
|
+
return context;
|
|
376
|
+
};
|
|
377
|
+
|
|
97
378
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
98
|
-
import {
|
|
379
|
+
import { useEffect as useEffect4, useRef } from "react";
|
|
99
380
|
import { Typography, TextField, Button, Box, CircularProgress, Alert, Link } from "@mui/material";
|
|
100
381
|
|
|
101
382
|
// src/components/CrudifyLogin/utils/secureStorage.ts
|
|
@@ -207,45 +488,302 @@ var SecureStorage = class {
|
|
|
207
488
|
var secureSessionStorage = new SecureStorage("sessionStorage");
|
|
208
489
|
var secureLocalStorage = new SecureStorage("localStorage");
|
|
209
490
|
|
|
491
|
+
// src/utils/errorHandler.ts
|
|
492
|
+
var ERROR_CODES = {
|
|
493
|
+
// Authentication Errors
|
|
494
|
+
INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
|
|
495
|
+
UNAUTHORIZED: "UNAUTHORIZED",
|
|
496
|
+
INVALID_API_KEY: "INVALID_API_KEY",
|
|
497
|
+
USER_NOT_FOUND: "USER_NOT_FOUND",
|
|
498
|
+
USER_NOT_ACTIVE: "USER_NOT_ACTIVE",
|
|
499
|
+
NO_PERMISSION: "NO_PERMISSION",
|
|
500
|
+
// Data Errors
|
|
501
|
+
ITEM_NOT_FOUND: "ITEM_NOT_FOUND",
|
|
502
|
+
NOT_FOUND: "NOT_FOUND",
|
|
503
|
+
IN_USE: "IN_USE",
|
|
504
|
+
// Validation Errors
|
|
505
|
+
FIELD_ERROR: "FIELD_ERROR",
|
|
506
|
+
BAD_REQUEST: "BAD_REQUEST",
|
|
507
|
+
INVALID_EMAIL: "INVALID_EMAIL",
|
|
508
|
+
INVALID_CODE: "INVALID_CODE",
|
|
509
|
+
// System Errors
|
|
510
|
+
INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR",
|
|
511
|
+
DATABASE_CONNECTION_ERROR: "DATABASE_CONNECTION_ERROR",
|
|
512
|
+
INVALID_CONFIGURATION: "INVALID_CONFIGURATION",
|
|
513
|
+
UNKNOWN_OPERATION: "UNKNOWN_OPERATION",
|
|
514
|
+
// Rate Limiting
|
|
515
|
+
TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
|
|
516
|
+
// Network Errors
|
|
517
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
518
|
+
TIMEOUT_ERROR: "TIMEOUT_ERROR"
|
|
519
|
+
};
|
|
520
|
+
var ERROR_SEVERITY_MAP = {
|
|
521
|
+
// Authentication - warning (user can fix)
|
|
522
|
+
[ERROR_CODES.INVALID_CREDENTIALS]: "warning",
|
|
523
|
+
[ERROR_CODES.UNAUTHORIZED]: "warning",
|
|
524
|
+
[ERROR_CODES.INVALID_API_KEY]: "error",
|
|
525
|
+
[ERROR_CODES.USER_NOT_FOUND]: "warning",
|
|
526
|
+
[ERROR_CODES.USER_NOT_ACTIVE]: "warning",
|
|
527
|
+
[ERROR_CODES.NO_PERMISSION]: "warning",
|
|
528
|
+
// Data - info (might be expected)
|
|
529
|
+
[ERROR_CODES.ITEM_NOT_FOUND]: "info",
|
|
530
|
+
[ERROR_CODES.NOT_FOUND]: "info",
|
|
531
|
+
[ERROR_CODES.IN_USE]: "warning",
|
|
532
|
+
// Validation - warning (user input issue)
|
|
533
|
+
[ERROR_CODES.FIELD_ERROR]: "warning",
|
|
534
|
+
[ERROR_CODES.BAD_REQUEST]: "warning",
|
|
535
|
+
[ERROR_CODES.INVALID_EMAIL]: "warning",
|
|
536
|
+
[ERROR_CODES.INVALID_CODE]: "warning",
|
|
537
|
+
// System - error (server issue)
|
|
538
|
+
[ERROR_CODES.INTERNAL_SERVER_ERROR]: "error",
|
|
539
|
+
[ERROR_CODES.DATABASE_CONNECTION_ERROR]: "error",
|
|
540
|
+
[ERROR_CODES.INVALID_CONFIGURATION]: "error",
|
|
541
|
+
[ERROR_CODES.UNKNOWN_OPERATION]: "error",
|
|
542
|
+
// Rate limiting - warning with higher duration
|
|
543
|
+
[ERROR_CODES.TOO_MANY_REQUESTS]: "warning",
|
|
544
|
+
// Network - error
|
|
545
|
+
[ERROR_CODES.NETWORK_ERROR]: "error",
|
|
546
|
+
[ERROR_CODES.TIMEOUT_ERROR]: "error"
|
|
547
|
+
};
|
|
548
|
+
function parseApiError(response) {
|
|
549
|
+
const errors = [];
|
|
550
|
+
try {
|
|
551
|
+
const apiResponse = response;
|
|
552
|
+
if (apiResponse.data && typeof apiResponse.data === "object") {
|
|
553
|
+
const responseData = apiResponse.data;
|
|
554
|
+
if (responseData.response) {
|
|
555
|
+
const { status, fieldsWarning } = responseData.response;
|
|
556
|
+
if (fieldsWarning && typeof fieldsWarning === "object") {
|
|
557
|
+
Object.entries(fieldsWarning).forEach(([field, messages]) => {
|
|
558
|
+
if (Array.isArray(messages) && messages.length > 0) {
|
|
559
|
+
errors.push({
|
|
560
|
+
code: ERROR_CODES.FIELD_ERROR,
|
|
561
|
+
message: messages[0],
|
|
562
|
+
severity: "warning",
|
|
563
|
+
field
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
if (status && typeof status === "string") {
|
|
569
|
+
const errorCode = status;
|
|
570
|
+
if (ERROR_SEVERITY_MAP[errorCode]) {
|
|
571
|
+
errors.push({
|
|
572
|
+
code: errorCode,
|
|
573
|
+
message: getErrorMessage(errorCode),
|
|
574
|
+
severity: ERROR_SEVERITY_MAP[errorCode]
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (apiResponse.errors) {
|
|
581
|
+
if (typeof apiResponse.errors === "string") {
|
|
582
|
+
errors.push({
|
|
583
|
+
code: ERROR_CODES.BAD_REQUEST,
|
|
584
|
+
message: apiResponse.errors,
|
|
585
|
+
severity: "warning"
|
|
586
|
+
});
|
|
587
|
+
} else if (typeof apiResponse.errors === "object") {
|
|
588
|
+
const errorObj = apiResponse.errors;
|
|
589
|
+
Object.entries(errorObj).forEach(([field, messages]) => {
|
|
590
|
+
if (Array.isArray(messages) && messages.length > 0) {
|
|
591
|
+
if (field === "_error") {
|
|
592
|
+
messages.forEach((msg) => {
|
|
593
|
+
const errorCode = typeof msg === "string" && isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
|
|
594
|
+
errors.push({
|
|
595
|
+
code: errorCode,
|
|
596
|
+
message: typeof msg === "string" ? msg : getErrorMessage(errorCode),
|
|
597
|
+
severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
} else if (field === "_graphql") {
|
|
601
|
+
messages.forEach((msg) => {
|
|
602
|
+
if (typeof msg === "string") {
|
|
603
|
+
const errorCode = isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
|
|
604
|
+
errors.push({
|
|
605
|
+
code: errorCode,
|
|
606
|
+
message: getErrorMessage(errorCode),
|
|
607
|
+
severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
} else {
|
|
612
|
+
errors.push({
|
|
613
|
+
code: ERROR_CODES.FIELD_ERROR,
|
|
614
|
+
message: typeof messages[0] === "string" ? messages[0] : "Validation error",
|
|
615
|
+
severity: "warning",
|
|
616
|
+
field
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (errors.length === 0 && apiResponse.success === false) {
|
|
624
|
+
errors.push({
|
|
625
|
+
code: ERROR_CODES.BAD_REQUEST,
|
|
626
|
+
message: "Request failed",
|
|
627
|
+
severity: "warning"
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
} catch (error) {
|
|
631
|
+
errors.push({
|
|
632
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
633
|
+
message: "Failed to parse error response",
|
|
634
|
+
severity: "error",
|
|
635
|
+
details: { originalError: error }
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
return errors.length > 0 ? errors : [{
|
|
639
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
640
|
+
message: "Unknown error occurred",
|
|
641
|
+
severity: "error"
|
|
642
|
+
}];
|
|
643
|
+
}
|
|
644
|
+
function parseTransactionError(response) {
|
|
645
|
+
try {
|
|
646
|
+
const transactionResponse = response;
|
|
647
|
+
if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
|
|
648
|
+
const errors = [];
|
|
649
|
+
transactionResponse.data.forEach((item, index) => {
|
|
650
|
+
if (item.response?.status === "TOO_MANY_REQUESTS") {
|
|
651
|
+
errors.push({
|
|
652
|
+
code: ERROR_CODES.TOO_MANY_REQUESTS,
|
|
653
|
+
message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
|
|
654
|
+
severity: "warning",
|
|
655
|
+
details: { transactionIndex: index }
|
|
656
|
+
});
|
|
657
|
+
} else if (!item.response || item.response.status !== "OK") {
|
|
658
|
+
errors.push({
|
|
659
|
+
code: ERROR_CODES.BAD_REQUEST,
|
|
660
|
+
message: "Transaction failed",
|
|
661
|
+
severity: "warning",
|
|
662
|
+
details: { transactionIndex: index, response: item.response }
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
return errors;
|
|
667
|
+
}
|
|
668
|
+
return parseApiError(response);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
return [{
|
|
671
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
672
|
+
message: "Failed to parse transaction error",
|
|
673
|
+
severity: "error",
|
|
674
|
+
details: { originalError: error }
|
|
675
|
+
}];
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function isValidErrorCode(code) {
|
|
679
|
+
return Object.values(ERROR_CODES).includes(code);
|
|
680
|
+
}
|
|
681
|
+
function getErrorMessage(code) {
|
|
682
|
+
const messages = {
|
|
683
|
+
[ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
|
|
684
|
+
[ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
|
|
685
|
+
[ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
|
|
686
|
+
[ERROR_CODES.USER_NOT_FOUND]: "User not found",
|
|
687
|
+
[ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
|
|
688
|
+
[ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
|
|
689
|
+
[ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
|
|
690
|
+
[ERROR_CODES.NOT_FOUND]: "Resource not found",
|
|
691
|
+
[ERROR_CODES.IN_USE]: "Resource is currently in use",
|
|
692
|
+
[ERROR_CODES.FIELD_ERROR]: "Validation error",
|
|
693
|
+
[ERROR_CODES.BAD_REQUEST]: "Invalid request",
|
|
694
|
+
[ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
|
|
695
|
+
[ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
|
|
696
|
+
[ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
|
|
697
|
+
[ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
|
|
698
|
+
[ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
|
|
699
|
+
[ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
|
|
700
|
+
[ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
|
|
701
|
+
[ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
|
|
702
|
+
[ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
|
|
703
|
+
};
|
|
704
|
+
return messages[code] || "An unknown error occurred";
|
|
705
|
+
}
|
|
706
|
+
function parseJavaScriptError(error) {
|
|
707
|
+
if (error instanceof Error) {
|
|
708
|
+
if (error.name === "AbortError") {
|
|
709
|
+
return {
|
|
710
|
+
code: ERROR_CODES.TIMEOUT_ERROR,
|
|
711
|
+
message: "Request was cancelled",
|
|
712
|
+
severity: "info"
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
|
|
716
|
+
return {
|
|
717
|
+
code: ERROR_CODES.NETWORK_ERROR,
|
|
718
|
+
message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
|
|
719
|
+
severity: "error"
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
return {
|
|
723
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
724
|
+
message: error.message || "An unexpected error occurred",
|
|
725
|
+
severity: "error",
|
|
726
|
+
details: { originalError: error }
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
731
|
+
message: "An unknown error occurred",
|
|
732
|
+
severity: "error",
|
|
733
|
+
details: { originalError: error }
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function handleCrudifyError(error) {
|
|
737
|
+
if (error instanceof Error) {
|
|
738
|
+
return [parseJavaScriptError(error)];
|
|
739
|
+
}
|
|
740
|
+
if (typeof error === "object" && error !== null) {
|
|
741
|
+
const response = error;
|
|
742
|
+
if (response.data && Array.isArray(response.data)) {
|
|
743
|
+
return parseTransactionError(error);
|
|
744
|
+
}
|
|
745
|
+
return parseApiError(error);
|
|
746
|
+
}
|
|
747
|
+
return [{
|
|
748
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
749
|
+
message: "An unknown error occurred",
|
|
750
|
+
severity: "error",
|
|
751
|
+
details: { originalError: error }
|
|
752
|
+
}];
|
|
753
|
+
}
|
|
754
|
+
|
|
210
755
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
211
|
-
import { Fragment, jsx as
|
|
212
|
-
var LoginForm = ({
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const [loading, setLoading] = useState2(false);
|
|
216
|
-
const [errors, setErrors] = useState2([]);
|
|
217
|
-
const [helperTextEmail, setHelperTextEmail] = useState2(null);
|
|
218
|
-
const [helperTextPassword, setHelperTextPassword] = useState2(null);
|
|
756
|
+
import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
757
|
+
var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
|
|
758
|
+
const { crudify: crudify3 } = useCrudify();
|
|
759
|
+
const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
|
|
219
760
|
const { t } = useTranslation();
|
|
220
761
|
const usernameInputRef = useRef(null);
|
|
221
762
|
const getRedirectUrl = () => {
|
|
222
|
-
if (searchParams) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
|
|
228
|
-
return decodedPath;
|
|
229
|
-
}
|
|
230
|
-
} catch (error) {
|
|
763
|
+
if (state.searchParams.redirect) {
|
|
764
|
+
try {
|
|
765
|
+
const decodedPath = decodeURIComponent(state.searchParams.redirect);
|
|
766
|
+
if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
|
|
767
|
+
return decodedPath;
|
|
231
768
|
}
|
|
769
|
+
} catch (error) {
|
|
232
770
|
}
|
|
233
771
|
}
|
|
234
772
|
return redirectUrl || "/";
|
|
235
773
|
};
|
|
236
|
-
|
|
774
|
+
useEffect4(() => {
|
|
237
775
|
const timer = setTimeout(() => {
|
|
238
776
|
if (usernameInputRef.current) usernameInputRef.current.focus();
|
|
239
777
|
}, 100);
|
|
240
778
|
return () => clearTimeout(timer);
|
|
241
779
|
}, []);
|
|
242
|
-
const
|
|
780
|
+
const translateError = (parsedError) => {
|
|
243
781
|
const possibleKeys = [
|
|
244
|
-
`errors.auth.${
|
|
245
|
-
`errors.data.${
|
|
246
|
-
`errors.system.${
|
|
247
|
-
`errors.${
|
|
248
|
-
`login.${
|
|
782
|
+
`errors.auth.${parsedError.code}`,
|
|
783
|
+
`errors.data.${parsedError.code}`,
|
|
784
|
+
`errors.system.${parsedError.code}`,
|
|
785
|
+
`errors.${parsedError.code}`,
|
|
786
|
+
`login.${parsedError.code.toLowerCase()}`
|
|
249
787
|
];
|
|
250
788
|
for (const key of possibleKeys) {
|
|
251
789
|
const translated = t(key);
|
|
@@ -253,27 +791,25 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
253
791
|
return translated;
|
|
254
792
|
}
|
|
255
793
|
}
|
|
256
|
-
return t("error.unknown");
|
|
794
|
+
return parsedError.message || t("error.unknown");
|
|
257
795
|
};
|
|
258
796
|
const handleLogin = async () => {
|
|
259
|
-
if (loading) return;
|
|
260
|
-
if (!username.trim()) {
|
|
261
|
-
|
|
797
|
+
if (state.loading) return;
|
|
798
|
+
if (!state.formData.username.trim()) {
|
|
799
|
+
setFieldError("username", t("login.usernameRequired"));
|
|
262
800
|
return;
|
|
263
801
|
}
|
|
264
|
-
if (!password.trim()) {
|
|
265
|
-
|
|
802
|
+
if (!state.formData.password.trim()) {
|
|
803
|
+
setFieldError("password", t("login.passwordRequired"));
|
|
266
804
|
return;
|
|
267
805
|
}
|
|
268
|
-
|
|
269
|
-
setHelperTextEmail(null);
|
|
270
|
-
setHelperTextPassword(null);
|
|
806
|
+
clearErrors();
|
|
271
807
|
setLoading(true);
|
|
272
808
|
try {
|
|
273
809
|
if (!crudify3) {
|
|
274
810
|
throw new Error("Crudify not initialized");
|
|
275
811
|
}
|
|
276
|
-
const response = await crudify3.login(username, password);
|
|
812
|
+
const response = await crudify3.login(state.formData.username, state.formData.password);
|
|
277
813
|
setLoading(false);
|
|
278
814
|
if (response.success) {
|
|
279
815
|
secureSessionStorage.setToken(response.data.token);
|
|
@@ -288,62 +824,31 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
288
824
|
}
|
|
289
825
|
} catch (error) {
|
|
290
826
|
setLoading(false);
|
|
291
|
-
|
|
292
|
-
|
|
827
|
+
const parsedErrors = handleCrudifyError(error);
|
|
828
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
829
|
+
setFieldError("global", translatedErrors);
|
|
293
830
|
if (onError) {
|
|
294
|
-
onError(
|
|
831
|
+
onError(translatedErrors.join(", "));
|
|
295
832
|
}
|
|
296
833
|
}
|
|
297
834
|
};
|
|
298
835
|
const handleLoginError = (response) => {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (
|
|
302
|
-
|
|
303
|
-
if (fieldsWarning.password) setHelperTextPassword(fieldsWarning.password[0]);
|
|
304
|
-
} else if (status === "INVALID_CREDENTIALS") {
|
|
305
|
-
const translatedError = getSafeErrorTranslation(status);
|
|
306
|
-
setErrors([translatedError]);
|
|
307
|
-
} else if (status === "TOO_MANY_REQUESTS") {
|
|
308
|
-
const translatedError = getSafeErrorTranslation(status);
|
|
309
|
-
setErrors([translatedError]);
|
|
310
|
-
} else if (status) {
|
|
311
|
-
setErrors([getSafeErrorTranslation(status)]);
|
|
836
|
+
const parsedErrors = handleCrudifyError(response);
|
|
837
|
+
parsedErrors.forEach((error) => {
|
|
838
|
+
if (error.field) {
|
|
839
|
+
setFieldError(error.field, translateError(error));
|
|
312
840
|
} else {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
} else if (response.errors) {
|
|
316
|
-
const errors2 = response.errors;
|
|
317
|
-
if (typeof errors2 === "string") {
|
|
318
|
-
setErrors([errors2]);
|
|
319
|
-
} else if (typeof errors2 === "object") {
|
|
320
|
-
const hasUsernameError = errors2.username && errors2.username.length > 0;
|
|
321
|
-
const hasPasswordError = errors2.password && errors2.password.length > 0;
|
|
322
|
-
if (hasUsernameError || hasPasswordError) {
|
|
323
|
-
if (hasUsernameError) setHelperTextEmail(errors2.username[0]);
|
|
324
|
-
if (hasPasswordError) setHelperTextPassword(errors2.password[0]);
|
|
325
|
-
} else if (errors2._error && errors2._error.length > 0) {
|
|
326
|
-
const errorMessage = errors2._error[0];
|
|
327
|
-
if (typeof errorMessage === "string" && errorMessage.match(/^[A-Z_]+$/)) {
|
|
328
|
-
const translatedError = getSafeErrorTranslation(errorMessage);
|
|
329
|
-
setErrors([translatedError]);
|
|
330
|
-
} else setErrors([errorMessage]);
|
|
331
|
-
} else if (errors2._graphql && errors2._graphql[0] === "INVALID_CREDENTIALS") {
|
|
332
|
-
setErrors([getSafeErrorTranslation("INVALID_CREDENTIALS")]);
|
|
333
|
-
} else {
|
|
334
|
-
setErrors([t("error.unknown")]);
|
|
335
|
-
}
|
|
841
|
+
const currentGlobalErrors = state.errors.global || [];
|
|
842
|
+
setFieldError("global", [...currentGlobalErrors, translateError(error)]);
|
|
336
843
|
}
|
|
337
|
-
}
|
|
338
|
-
setErrors([t("error.unknown")]);
|
|
339
|
-
}
|
|
844
|
+
});
|
|
340
845
|
};
|
|
341
846
|
const handleSubmit = (e) => {
|
|
342
847
|
e.preventDefault();
|
|
343
848
|
handleLogin();
|
|
344
849
|
};
|
|
345
850
|
const handleKeyDown = (e) => {
|
|
346
|
-
if (e.key === "Enter" && !loading) {
|
|
851
|
+
if (e.key === "Enter" && !state.loading) {
|
|
347
852
|
e.preventDefault();
|
|
348
853
|
handleLogin();
|
|
349
854
|
}
|
|
@@ -359,7 +864,7 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
359
864
|
sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
|
|
360
865
|
children: [
|
|
361
866
|
/* @__PURE__ */ jsxs(Box, { sx: { mb: 1 }, children: [
|
|
362
|
-
/* @__PURE__ */
|
|
867
|
+
/* @__PURE__ */ jsx4(
|
|
363
868
|
Typography,
|
|
364
869
|
{
|
|
365
870
|
variant: "body2",
|
|
@@ -369,18 +874,18 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
369
874
|
children: t("login.usernameOrEmailLabel")
|
|
370
875
|
}
|
|
371
876
|
),
|
|
372
|
-
/* @__PURE__ */
|
|
877
|
+
/* @__PURE__ */ jsx4(
|
|
373
878
|
TextField,
|
|
374
879
|
{
|
|
375
880
|
fullWidth: true,
|
|
376
881
|
id: "email",
|
|
377
882
|
name: "email",
|
|
378
883
|
type: "email",
|
|
379
|
-
value: username,
|
|
380
|
-
disabled: loading,
|
|
381
|
-
onChange: (e) =>
|
|
382
|
-
error: !!
|
|
383
|
-
helperText:
|
|
884
|
+
value: state.formData.username,
|
|
885
|
+
disabled: state.loading,
|
|
886
|
+
onChange: (e) => updateFormData({ username: e.target.value }),
|
|
887
|
+
error: !!state.errors.username,
|
|
888
|
+
helperText: state.errors.username,
|
|
384
889
|
autoComplete: "email",
|
|
385
890
|
placeholder: t("login.usernameOrEmailPlaceholder"),
|
|
386
891
|
inputRef: usernameInputRef,
|
|
@@ -389,7 +894,7 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
389
894
|
)
|
|
390
895
|
] }),
|
|
391
896
|
/* @__PURE__ */ jsxs(Box, { sx: { mb: 1 }, children: [
|
|
392
|
-
/* @__PURE__ */
|
|
897
|
+
/* @__PURE__ */ jsx4(
|
|
393
898
|
Typography,
|
|
394
899
|
{
|
|
395
900
|
variant: "body2",
|
|
@@ -399,52 +904,52 @@ var LoginForm = ({ config, onNavigate, onLoginSuccess, onError, redirectUrl = "/
|
|
|
399
904
|
children: t("login.passwordLabel")
|
|
400
905
|
}
|
|
401
906
|
),
|
|
402
|
-
/* @__PURE__ */
|
|
907
|
+
/* @__PURE__ */ jsx4(
|
|
403
908
|
TextField,
|
|
404
909
|
{
|
|
405
910
|
fullWidth: true,
|
|
406
911
|
id: "password",
|
|
407
912
|
name: "password",
|
|
408
913
|
type: "password",
|
|
409
|
-
value: password,
|
|
410
|
-
disabled: loading,
|
|
411
|
-
onChange: (e) =>
|
|
412
|
-
error: !!
|
|
413
|
-
helperText:
|
|
914
|
+
value: state.formData.password,
|
|
915
|
+
disabled: state.loading,
|
|
916
|
+
onChange: (e) => updateFormData({ password: e.target.value }),
|
|
917
|
+
error: !!state.errors.password,
|
|
918
|
+
helperText: state.errors.password,
|
|
414
919
|
autoComplete: "current-password",
|
|
415
920
|
placeholder: t("login.passwordPlaceholder"),
|
|
416
921
|
required: true
|
|
417
922
|
}
|
|
418
923
|
)
|
|
419
924
|
] }),
|
|
420
|
-
config.loginActions?.includes("forgotPassword") && /* @__PURE__ */
|
|
925
|
+
state.config.loginActions?.includes("forgotPassword") && /* @__PURE__ */ jsx4(Box, { sx: { display: "flex", justifyContent: "flex-end", alignItems: "center" }, children: /* @__PURE__ */ jsx4(
|
|
421
926
|
Link,
|
|
422
927
|
{
|
|
423
928
|
sx: { cursor: "pointer" },
|
|
424
929
|
onClick: () => {
|
|
425
|
-
|
|
426
|
-
onNavigate?.(`/login/forgotPassword${searchString}`);
|
|
930
|
+
onScreenChange?.("forgotPassword", state.searchParams);
|
|
427
931
|
},
|
|
428
932
|
variant: "body2",
|
|
429
933
|
color: "secondary",
|
|
430
934
|
children: t("login.forgotPasswordLink")
|
|
431
935
|
}
|
|
432
936
|
) }),
|
|
433
|
-
/* @__PURE__ */
|
|
937
|
+
/* @__PURE__ */ jsx4(Button, { disabled: state.loading, type: "submit", fullWidth: true, variant: "contained", color: "primary", sx: { mt: 1, mb: 2 }, children: state.loading ? /* @__PURE__ */ jsx4(CircularProgress, { size: 20 }) : t("login.loginButton") })
|
|
434
938
|
]
|
|
435
939
|
}
|
|
436
940
|
),
|
|
437
|
-
/* @__PURE__ */
|
|
438
|
-
config.loginActions?.includes("createUser") && /* @__PURE__ */ jsxs(Typography, { variant: "body2", align: "center", sx: { color: "text.secondary", mt: 3 }, children: [
|
|
941
|
+
/* @__PURE__ */ jsx4(Box, { children: state.errors.global && state.errors.global.length > 0 && state.errors.global.map((error, index) => /* @__PURE__ */ jsx4(Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: /* @__PURE__ */ jsx4("div", { children: error }) }, index)) }),
|
|
942
|
+
state.config.loginActions?.includes("createUser") && /* @__PURE__ */ jsxs(Typography, { variant: "body2", align: "center", sx: { color: "text.secondary", mt: 3 }, children: [
|
|
439
943
|
t("login.noAccountPrompt"),
|
|
440
944
|
" ",
|
|
441
|
-
/* @__PURE__ */
|
|
945
|
+
/* @__PURE__ */ jsx4(
|
|
442
946
|
Link,
|
|
443
947
|
{
|
|
444
948
|
sx: { cursor: "pointer" },
|
|
445
949
|
onClick: () => {
|
|
446
|
-
const searchString = searchParams ? `?${searchParams.toString()}` : "";
|
|
447
|
-
|
|
950
|
+
const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
|
|
951
|
+
const signupUrl = `/public/users/create${searchString}`;
|
|
952
|
+
onExternalNavigate?.(signupUrl);
|
|
448
953
|
},
|
|
449
954
|
fontWeight: "medium",
|
|
450
955
|
color: "secondary",
|
|
@@ -459,8 +964,9 @@ var LoginForm_default = LoginForm;
|
|
|
459
964
|
// src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
|
|
460
965
|
import { useState as useState3 } from "react";
|
|
461
966
|
import { Typography as Typography2, TextField as TextField2, Button as Button2, Box as Box2, CircularProgress as CircularProgress2, Alert as Alert2, Link as Link2 } from "@mui/material";
|
|
462
|
-
import { Fragment as Fragment2, jsx as
|
|
463
|
-
var ForgotPasswordForm = ({
|
|
967
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
968
|
+
var ForgotPasswordForm = ({ onScreenChange, onError }) => {
|
|
969
|
+
const { crudify: crudify3 } = useCrudify();
|
|
464
970
|
const [email, setEmail] = useState3("");
|
|
465
971
|
const [loading, setLoading] = useState3(false);
|
|
466
972
|
const [errors, setErrors] = useState3([]);
|
|
@@ -468,6 +974,22 @@ var ForgotPasswordForm = ({ onNavigate, onError, crudify: crudify3 }) => {
|
|
|
468
974
|
const [emailSent, setEmailSent] = useState3(false);
|
|
469
975
|
const [codeAlreadyExists, setCodeAlreadyExists] = useState3(false);
|
|
470
976
|
const { t } = useTranslation();
|
|
977
|
+
const translateError = (parsedError) => {
|
|
978
|
+
const possibleKeys = [
|
|
979
|
+
`errors.auth.${parsedError.code}`,
|
|
980
|
+
`errors.data.${parsedError.code}`,
|
|
981
|
+
`errors.system.${parsedError.code}`,
|
|
982
|
+
`errors.${parsedError.code}`,
|
|
983
|
+
`forgotPassword.${parsedError.code.toLowerCase()}`
|
|
984
|
+
];
|
|
985
|
+
for (const key of possibleKeys) {
|
|
986
|
+
const translated = t(key);
|
|
987
|
+
if (translated !== key) {
|
|
988
|
+
return translated;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return parsedError.message || t("error.unknown");
|
|
992
|
+
};
|
|
471
993
|
const validateEmail = (email2) => {
|
|
472
994
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
473
995
|
return emailRegex.test(email2);
|
|
@@ -495,80 +1017,57 @@ var ForgotPasswordForm = ({ onNavigate, onError, crudify: crudify3 }) => {
|
|
|
495
1017
|
setEmailSent(true);
|
|
496
1018
|
}
|
|
497
1019
|
} else {
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
} else if (response.errors) {
|
|
502
|
-
if (response.errors._error) {
|
|
503
|
-
const errors2 = response.errors._error;
|
|
504
|
-
const translatedErrors = errors2.map((error) => {
|
|
505
|
-
if (error === "TOO_MANY_REQUESTS") {
|
|
506
|
-
return t("errors.auth.TOO_MANY_REQUESTS");
|
|
507
|
-
}
|
|
508
|
-
return error;
|
|
509
|
-
});
|
|
510
|
-
errorMessages.push(...translatedErrors);
|
|
511
|
-
} else {
|
|
512
|
-
errorMessages.push(t("error.unknown"));
|
|
513
|
-
}
|
|
514
|
-
} else {
|
|
515
|
-
errorMessages.push(t("error.unknown"));
|
|
516
|
-
}
|
|
517
|
-
setErrors(errorMessages);
|
|
1020
|
+
const parsedErrors = handleCrudifyError(response);
|
|
1021
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1022
|
+
setErrors(translatedErrors);
|
|
518
1023
|
}
|
|
519
1024
|
} catch (error) {
|
|
520
|
-
|
|
521
|
-
|
|
1025
|
+
const parsedErrors = handleCrudifyError(error);
|
|
1026
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1027
|
+
setErrors(translatedErrors);
|
|
522
1028
|
if (onError) {
|
|
523
|
-
onError(
|
|
1029
|
+
onError(translatedErrors.join(", "));
|
|
524
1030
|
}
|
|
525
1031
|
} finally {
|
|
526
1032
|
setLoading(false);
|
|
527
1033
|
}
|
|
528
1034
|
};
|
|
529
1035
|
const handleBack = () => {
|
|
530
|
-
|
|
1036
|
+
onScreenChange?.("login");
|
|
531
1037
|
};
|
|
532
1038
|
const handleGoToCheckCode = () => {
|
|
533
|
-
console.log("\u{1F680} handleGoToCheckCode called:", { email, emailSent, codeAlreadyExists });
|
|
534
1039
|
if (emailSent || codeAlreadyExists) {
|
|
535
|
-
|
|
536
|
-
onNavigate?.(`/login/checkCode?email=${encodeURIComponent(email)}`);
|
|
1040
|
+
onScreenChange?.("checkCode", { email });
|
|
537
1041
|
return;
|
|
538
1042
|
}
|
|
539
1043
|
if (!email) {
|
|
540
|
-
console.log("\u274C Email required");
|
|
541
1044
|
setHelperTextEmail(t("forgotPassword.emailRequired"));
|
|
542
1045
|
return;
|
|
543
1046
|
}
|
|
544
1047
|
if (!validateEmail(email)) {
|
|
545
|
-
console.log("\u274C Invalid email");
|
|
546
1048
|
setHelperTextEmail(t("forgotPassword.invalidEmail"));
|
|
547
1049
|
return;
|
|
548
1050
|
}
|
|
549
|
-
|
|
550
|
-
onNavigate?.(`/login/checkCode?email=${encodeURIComponent(email)}`);
|
|
1051
|
+
onScreenChange?.("checkCode", { email });
|
|
551
1052
|
};
|
|
552
1053
|
if (emailSent || codeAlreadyExists) {
|
|
553
|
-
|
|
554
|
-
return /* @__PURE__ */ jsx3(Fragment2, { children: /* @__PURE__ */ jsxs2(Box2, { sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2, textAlign: "center" }, children: [
|
|
1054
|
+
return /* @__PURE__ */ jsx5(Fragment2, { children: /* @__PURE__ */ jsxs2(Box2, { sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2, textAlign: "center" }, children: [
|
|
555
1055
|
/* @__PURE__ */ jsxs2(Box2, { sx: { mb: 2 }, children: [
|
|
556
|
-
/* @__PURE__ */
|
|
557
|
-
/* @__PURE__ */
|
|
1056
|
+
/* @__PURE__ */ jsx5(Typography2, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: codeAlreadyExists ? t("forgotPassword.codeAlreadyExistsMessage") : t("forgotPassword.emailSentMessage") }),
|
|
1057
|
+
/* @__PURE__ */ jsx5(Typography2, { variant: "body2", sx: { color: codeAlreadyExists ? "success.main" : "grey.600" }, children: codeAlreadyExists ? t("forgotPassword.checkEmailInstructions") : t("forgotPassword.checkEmailInstructions") })
|
|
558
1058
|
] }),
|
|
559
|
-
/* @__PURE__ */
|
|
560
|
-
/* @__PURE__ */
|
|
1059
|
+
/* @__PURE__ */ jsx5(Button2, { type: "button", onClick: handleGoToCheckCode, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: t("forgotPassword.enterCodeLink") }),
|
|
1060
|
+
/* @__PURE__ */ jsx5(Box2, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx5(Link2, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
|
|
561
1061
|
] }) });
|
|
562
1062
|
}
|
|
563
|
-
console.log("\u{1F4DD} Rendering FORM state");
|
|
564
1063
|
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
565
1064
|
/* @__PURE__ */ jsxs2(Box2, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
566
1065
|
/* @__PURE__ */ jsxs2(Box2, { sx: { mb: 2 }, children: [
|
|
567
|
-
/* @__PURE__ */
|
|
568
|
-
/* @__PURE__ */
|
|
1066
|
+
/* @__PURE__ */ jsx5(Typography2, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
|
|
1067
|
+
/* @__PURE__ */ jsx5(Typography2, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
|
|
569
1068
|
] }),
|
|
570
1069
|
/* @__PURE__ */ jsxs2(Box2, { sx: { mb: 1 }, children: [
|
|
571
|
-
/* @__PURE__ */
|
|
1070
|
+
/* @__PURE__ */ jsx5(
|
|
572
1071
|
Typography2,
|
|
573
1072
|
{
|
|
574
1073
|
variant: "body2",
|
|
@@ -578,7 +1077,7 @@ var ForgotPasswordForm = ({ onNavigate, onError, crudify: crudify3 }) => {
|
|
|
578
1077
|
children: t("forgotPassword.emailLabel")
|
|
579
1078
|
}
|
|
580
1079
|
),
|
|
581
|
-
/* @__PURE__ */
|
|
1080
|
+
/* @__PURE__ */ jsx5(
|
|
582
1081
|
TextField2,
|
|
583
1082
|
{
|
|
584
1083
|
fullWidth: true,
|
|
@@ -596,23 +1095,24 @@ var ForgotPasswordForm = ({ onNavigate, onError, crudify: crudify3 }) => {
|
|
|
596
1095
|
}
|
|
597
1096
|
)
|
|
598
1097
|
] }),
|
|
599
|
-
/* @__PURE__ */
|
|
1098
|
+
/* @__PURE__ */ jsx5(Button2, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ jsx5(CircularProgress2, { size: 20 }) : t("forgotPassword.sendCodeButton") }),
|
|
600
1099
|
/* @__PURE__ */ jsxs2(Box2, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
|
|
601
|
-
/* @__PURE__ */
|
|
602
|
-
/* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
1100
|
+
/* @__PURE__ */ jsx5(Link2, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
|
|
1101
|
+
/* @__PURE__ */ jsx5(Typography2, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
|
|
1102
|
+
/* @__PURE__ */ jsx5(Link2, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
|
|
604
1103
|
] })
|
|
605
1104
|
] }),
|
|
606
|
-
/* @__PURE__ */
|
|
1105
|
+
/* @__PURE__ */ jsx5(Box2, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ jsx5(Alert2, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
|
|
607
1106
|
] });
|
|
608
1107
|
};
|
|
609
1108
|
var ForgotPasswordForm_default = ForgotPasswordForm;
|
|
610
1109
|
|
|
611
1110
|
// src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
|
|
612
|
-
import { useState as useState4, useEffect as
|
|
1111
|
+
import { useState as useState4, useEffect as useEffect5 } from "react";
|
|
613
1112
|
import { Typography as Typography3, TextField as TextField3, Button as Button3, Box as Box3, CircularProgress as CircularProgress3, Alert as Alert3, Link as Link3 } from "@mui/material";
|
|
614
|
-
import { Fragment as Fragment3, jsx as
|
|
615
|
-
var ResetPasswordForm = ({
|
|
1113
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1114
|
+
var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
|
|
1115
|
+
const { crudify: crudify3 } = useCrudify();
|
|
616
1116
|
const [newPassword, setNewPassword] = useState4("");
|
|
617
1117
|
const [confirmPassword, setConfirmPassword] = useState4("");
|
|
618
1118
|
const [loading, setLoading] = useState4(false);
|
|
@@ -627,12 +1127,26 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
627
1127
|
const [pendingValidation, setPendingValidation] = useState4(null);
|
|
628
1128
|
const [isValidating, setIsValidating] = useState4(false);
|
|
629
1129
|
const { t } = useTranslation();
|
|
630
|
-
|
|
1130
|
+
const translateError = (parsedError) => {
|
|
1131
|
+
const possibleKeys = [
|
|
1132
|
+
`errors.auth.${parsedError.code}`,
|
|
1133
|
+
`errors.data.${parsedError.code}`,
|
|
1134
|
+
`errors.system.${parsedError.code}`,
|
|
1135
|
+
`errors.${parsedError.code}`,
|
|
1136
|
+
`resetPassword.${parsedError.code.toLowerCase()}`
|
|
1137
|
+
];
|
|
1138
|
+
for (const key of possibleKeys) {
|
|
1139
|
+
const translated = t(key);
|
|
1140
|
+
if (translated !== key) {
|
|
1141
|
+
return translated;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
return parsedError.message || t("error.unknown");
|
|
1145
|
+
};
|
|
1146
|
+
useEffect5(() => {
|
|
631
1147
|
if (!searchParams) {
|
|
632
|
-
console.log("\u{1F504} No searchParams yet, waiting...");
|
|
633
1148
|
return;
|
|
634
1149
|
}
|
|
635
|
-
console.log("\u{1F504} Processing searchParams:", searchParams.toString());
|
|
636
1150
|
if (searchParams) {
|
|
637
1151
|
const fromCodeVerificationParam = searchParams.get("fromCodeVerification");
|
|
638
1152
|
const emailParam = searchParams.get("email");
|
|
@@ -651,54 +1165,31 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
651
1165
|
const decodedLink = decodeURIComponent(linkParam);
|
|
652
1166
|
const [linkCode, linkEmail] = decodedLink.split("/");
|
|
653
1167
|
if (linkCode && linkEmail && linkCode.length === 6) {
|
|
654
|
-
console.log("\u{1F517} Reset link detected:", { linkCode, linkEmail });
|
|
655
1168
|
setCode(linkCode);
|
|
656
1169
|
setEmail(linkEmail);
|
|
657
1170
|
setFromCodeVerification(false);
|
|
658
|
-
console.log("\u23F3 Setting pending validation for reset link");
|
|
659
1171
|
setPendingValidation({ email: linkEmail, code: linkCode });
|
|
660
1172
|
return;
|
|
661
1173
|
}
|
|
662
1174
|
} catch (error) {
|
|
663
|
-
console.error("Failed to parse reset link:", error);
|
|
664
1175
|
}
|
|
665
1176
|
}
|
|
666
1177
|
if (emailParam && codeParam) {
|
|
667
1178
|
setEmail(emailParam);
|
|
668
1179
|
setCode(codeParam);
|
|
669
1180
|
setFromCodeVerification(false);
|
|
670
|
-
console.log("\u23F3 Setting pending validation for direct params");
|
|
671
1181
|
setPendingValidation({ email: emailParam, code: codeParam });
|
|
672
1182
|
return;
|
|
673
1183
|
}
|
|
674
1184
|
}
|
|
675
|
-
console.log("\u274C No valid reset parameters found");
|
|
676
1185
|
setErrors([t("resetPassword.invalidCode")]);
|
|
677
1186
|
setValidatingCode(false);
|
|
678
|
-
setTimeout(() =>
|
|
679
|
-
}, [searchParams, crudify3, t,
|
|
680
|
-
|
|
681
|
-
console.log("\u{1F504} Pending validation useEffect triggered:", {
|
|
682
|
-
crudify: !!crudify3,
|
|
683
|
-
pendingValidation,
|
|
684
|
-
crudifyType: typeof crudify3,
|
|
685
|
-
crudifyKeys: crudify3 ? Object.keys(crudify3) : null
|
|
686
|
-
});
|
|
1187
|
+
setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
|
|
1188
|
+
}, [searchParams, crudify3, t, onScreenChange]);
|
|
1189
|
+
useEffect5(() => {
|
|
687
1190
|
if (crudify3 && pendingValidation && !isValidating) {
|
|
688
|
-
console.log("\u{1F680} Crudify verified ready! Executing pending validation:", pendingValidation);
|
|
689
|
-
console.log("\u{1F50D} Crudify object details:", {
|
|
690
|
-
hasTransaction: typeof crudify3.transaction === "function",
|
|
691
|
-
hasLogin: typeof crudify3.login === "function",
|
|
692
|
-
crudifyInstance: crudify3
|
|
693
|
-
});
|
|
694
1191
|
setIsValidating(true);
|
|
695
1192
|
const validateCode = async (emailToValidate, codeToValidate) => {
|
|
696
|
-
console.log("\u{1F50D} Validating reset code:", { emailToValidate, codeToValidate });
|
|
697
|
-
console.log("\u{1F4CB} Pre-validation crudify check:", {
|
|
698
|
-
crudify: !!crudify3,
|
|
699
|
-
transaction: typeof crudify3?.transaction,
|
|
700
|
-
crudifyString: crudify3?.toString?.()
|
|
701
|
-
});
|
|
702
1193
|
try {
|
|
703
1194
|
const data = [
|
|
704
1195
|
{
|
|
@@ -706,62 +1197,27 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
706
1197
|
data: { email: emailToValidate, codePassword: codeToValidate }
|
|
707
1198
|
}
|
|
708
1199
|
];
|
|
709
|
-
console.log("\u{1F4E4} Sending validation request:", data);
|
|
710
|
-
console.log("\u{1F3AF} About to call crudify.transaction...");
|
|
711
1200
|
const response = await crudify3.transaction(data);
|
|
712
|
-
console.log("\u{1F4E5} Validation response:", response);
|
|
713
|
-
console.log("\u{1F4E5} Raw response type:", typeof response);
|
|
714
|
-
console.log("\u{1F4E5} Response keys:", Object.keys(response));
|
|
715
|
-
if (response.data) {
|
|
716
|
-
console.log("\u{1F4E5} Response.data type:", typeof response.data);
|
|
717
|
-
console.log("\u{1F4E5} Response.data content:", response.data);
|
|
718
|
-
}
|
|
719
1201
|
if (response.data && Array.isArray(response.data)) {
|
|
720
|
-
console.log("\u{1F50D} Checking array response data:", response.data);
|
|
721
1202
|
const validationResult = response.data[0];
|
|
722
1203
|
if (validationResult && validationResult.response && validationResult.response.status === "OK") {
|
|
723
|
-
console.log("\u2705 Code validation successful (from array data)");
|
|
724
1204
|
setCodeValidated(true);
|
|
725
1205
|
return;
|
|
726
1206
|
}
|
|
727
1207
|
}
|
|
728
1208
|
if (response.success) {
|
|
729
|
-
console.log("\u2705 Code validation successful");
|
|
730
1209
|
setCodeValidated(true);
|
|
731
1210
|
} else {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
errors: response.errors,
|
|
737
|
-
errorCode: response.errorCode,
|
|
738
|
-
fieldsWarning: response.fieldsWarning
|
|
739
|
-
});
|
|
740
|
-
if (response.data?.response?.status === "TOO_MANY_REQUESTS") {
|
|
741
|
-
setErrors([t("errors.auth.TOO_MANY_REQUESTS")]);
|
|
742
|
-
} else {
|
|
743
|
-
let errorMessage = t("resetPassword.invalidCode");
|
|
744
|
-
if (response.errors?._error) {
|
|
745
|
-
const error = response.errors._error[0];
|
|
746
|
-
if (error === "TOO_MANY_REQUESTS") {
|
|
747
|
-
errorMessage = t("errors.auth.TOO_MANY_REQUESTS");
|
|
748
|
-
} else {
|
|
749
|
-
const errorMsg = error?.toLowerCase() || "";
|
|
750
|
-
if (errorMsg.includes("expired")) {
|
|
751
|
-
errorMessage = t("resetPassword.codeExpiredOrInvalid");
|
|
752
|
-
} else if (errorMsg.includes("invalid")) {
|
|
753
|
-
errorMessage = t("resetPassword.invalidCode");
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
setErrors([errorMessage]);
|
|
758
|
-
}
|
|
759
|
-
setTimeout(() => onNavigate?.("/login/forgotPassword"), 3e3);
|
|
1211
|
+
const parsedErrors = handleCrudifyError(response);
|
|
1212
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1213
|
+
setErrors(translatedErrors);
|
|
1214
|
+
setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
|
|
760
1215
|
}
|
|
761
1216
|
} catch (error) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1217
|
+
const parsedErrors = handleCrudifyError(error);
|
|
1218
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1219
|
+
setErrors(translatedErrors);
|
|
1220
|
+
setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
|
|
765
1221
|
} finally {
|
|
766
1222
|
setValidatingCode(false);
|
|
767
1223
|
setPendingValidation(null);
|
|
@@ -770,7 +1226,7 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
770
1226
|
};
|
|
771
1227
|
validateCode(pendingValidation.email, pendingValidation.code);
|
|
772
1228
|
}
|
|
773
|
-
}, [crudify3, pendingValidation, t,
|
|
1229
|
+
}, [crudify3, pendingValidation, t, onScreenChange]);
|
|
774
1230
|
const validatePassword = (password) => {
|
|
775
1231
|
if (password.length < 8) {
|
|
776
1232
|
return t("resetPassword.passwordTooShort");
|
|
@@ -816,80 +1272,41 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
816
1272
|
onResetSuccess?.();
|
|
817
1273
|
}, 1e3);
|
|
818
1274
|
} else {
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
} else if (response.errors?._transaction) {
|
|
823
|
-
const transactionErrors = response.errors._transaction;
|
|
824
|
-
if (Array.isArray(transactionErrors) && transactionErrors.length > 0) {
|
|
825
|
-
const firstError = transactionErrors[0];
|
|
826
|
-
let errorMsg = "";
|
|
827
|
-
if (typeof firstError === "string") {
|
|
828
|
-
try {
|
|
829
|
-
const parsed = JSON.parse(firstError);
|
|
830
|
-
if (parsed?.response?.message) {
|
|
831
|
-
errorMsg = parsed.response.message.toLowerCase();
|
|
832
|
-
}
|
|
833
|
-
} catch {
|
|
834
|
-
errorMsg = firstError.toLowerCase();
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
if (errorMsg.includes("expired")) {
|
|
838
|
-
errorMessages.push(t("resetPassword.codeExpiredOrInvalid"));
|
|
839
|
-
} else if (errorMsg.includes("invalid")) {
|
|
840
|
-
errorMessages.push(t("resetPassword.invalidCode"));
|
|
841
|
-
} else {
|
|
842
|
-
errorMessages.push(t("error.unknown"));
|
|
843
|
-
}
|
|
844
|
-
} else {
|
|
845
|
-
errorMessages.push(t("error.unknown"));
|
|
846
|
-
}
|
|
847
|
-
} else if (response.errors?._error) {
|
|
848
|
-
const error = response.errors._error[0];
|
|
849
|
-
if (error === "TOO_MANY_REQUESTS") {
|
|
850
|
-
errorMessages.push(t("errors.auth.TOO_MANY_REQUESTS"));
|
|
851
|
-
} else {
|
|
852
|
-
const errorMsg = error?.toLowerCase() || "";
|
|
853
|
-
if (errorMsg.includes("expired")) {
|
|
854
|
-
errorMessages.push(t("resetPassword.codeExpiredOrInvalid"));
|
|
855
|
-
} else if (errorMsg.includes("invalid")) {
|
|
856
|
-
errorMessages.push(t("resetPassword.invalidCode"));
|
|
857
|
-
} else {
|
|
858
|
-
errorMessages.push(error || t("error.unknown"));
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
} else {
|
|
862
|
-
errorMessages.push(t("error.unknown"));
|
|
863
|
-
}
|
|
864
|
-
setErrors(errorMessages);
|
|
1275
|
+
const parsedErrors = handleCrudifyError(response);
|
|
1276
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1277
|
+
setErrors(translatedErrors);
|
|
865
1278
|
}
|
|
866
1279
|
} catch (error) {
|
|
867
|
-
|
|
868
|
-
|
|
1280
|
+
const parsedErrors = handleCrudifyError(error);
|
|
1281
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1282
|
+
setErrors(translatedErrors);
|
|
869
1283
|
if (onError) {
|
|
870
|
-
onError(
|
|
1284
|
+
onError(translatedErrors.join(", "));
|
|
871
1285
|
}
|
|
872
1286
|
}
|
|
873
1287
|
setLoading(false);
|
|
874
1288
|
};
|
|
875
1289
|
const handleBack = () => {
|
|
876
|
-
if (fromCodeVerification)
|
|
877
|
-
|
|
1290
|
+
if (fromCodeVerification) {
|
|
1291
|
+
onScreenChange?.("checkCode", { email });
|
|
1292
|
+
} else {
|
|
1293
|
+
onScreenChange?.("forgotPassword");
|
|
1294
|
+
}
|
|
878
1295
|
};
|
|
879
1296
|
if (validatingCode) {
|
|
880
|
-
return /* @__PURE__ */
|
|
1297
|
+
return /* @__PURE__ */ jsx6(Box3, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "300px" }, children: /* @__PURE__ */ jsx6(CircularProgress3, {}) });
|
|
881
1298
|
}
|
|
882
1299
|
if (!codeValidated) {
|
|
883
|
-
return /* @__PURE__ */
|
|
1300
|
+
return /* @__PURE__ */ jsx6(Box3, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ jsx6(Alert3, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) });
|
|
884
1301
|
}
|
|
885
1302
|
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
886
1303
|
/* @__PURE__ */ jsxs3(Box3, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
887
1304
|
/* @__PURE__ */ jsxs3(Box3, { sx: { mb: 2 }, children: [
|
|
888
|
-
/* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
1305
|
+
/* @__PURE__ */ jsx6(Typography3, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
|
|
1306
|
+
/* @__PURE__ */ jsx6(Typography3, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
|
|
890
1307
|
] }),
|
|
891
1308
|
/* @__PURE__ */ jsxs3(Box3, { sx: { mb: 1 }, children: [
|
|
892
|
-
/* @__PURE__ */
|
|
1309
|
+
/* @__PURE__ */ jsx6(
|
|
893
1310
|
Typography3,
|
|
894
1311
|
{
|
|
895
1312
|
variant: "body2",
|
|
@@ -899,7 +1316,7 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
899
1316
|
children: t("resetPassword.newPasswordLabel")
|
|
900
1317
|
}
|
|
901
1318
|
),
|
|
902
|
-
/* @__PURE__ */
|
|
1319
|
+
/* @__PURE__ */ jsx6(
|
|
903
1320
|
TextField3,
|
|
904
1321
|
{
|
|
905
1322
|
fullWidth: true,
|
|
@@ -918,7 +1335,7 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
918
1335
|
)
|
|
919
1336
|
] }),
|
|
920
1337
|
/* @__PURE__ */ jsxs3(Box3, { sx: { mb: 1 }, children: [
|
|
921
|
-
/* @__PURE__ */
|
|
1338
|
+
/* @__PURE__ */ jsx6(
|
|
922
1339
|
Typography3,
|
|
923
1340
|
{
|
|
924
1341
|
variant: "body2",
|
|
@@ -928,7 +1345,7 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
928
1345
|
children: t("resetPassword.confirmPasswordLabel")
|
|
929
1346
|
}
|
|
930
1347
|
),
|
|
931
|
-
/* @__PURE__ */
|
|
1348
|
+
/* @__PURE__ */ jsx6(
|
|
932
1349
|
TextField3,
|
|
933
1350
|
{
|
|
934
1351
|
fullWidth: true,
|
|
@@ -946,33 +1363,50 @@ var ResetPasswordForm = ({ onNavigate, onError, searchParams, onResetSuccess, cr
|
|
|
946
1363
|
}
|
|
947
1364
|
)
|
|
948
1365
|
] }),
|
|
949
|
-
/* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
1366
|
+
/* @__PURE__ */ jsx6(Button3, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ jsx6(CircularProgress3, { size: 20 }) : t("resetPassword.resetPasswordButton") }),
|
|
1367
|
+
/* @__PURE__ */ jsx6(Box3, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx6(Link3, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
|
|
951
1368
|
] }),
|
|
952
|
-
/* @__PURE__ */
|
|
1369
|
+
/* @__PURE__ */ jsx6(Box3, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ jsx6(Alert3, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
|
|
953
1370
|
] });
|
|
954
1371
|
};
|
|
955
1372
|
var ResetPasswordForm_default = ResetPasswordForm;
|
|
956
1373
|
|
|
957
1374
|
// src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
|
|
958
|
-
import { useState as useState5, useEffect as
|
|
1375
|
+
import { useState as useState5, useEffect as useEffect6 } from "react";
|
|
959
1376
|
import { Typography as Typography4, TextField as TextField4, Button as Button4, Box as Box4, CircularProgress as CircularProgress4, Alert as Alert4, Link as Link4 } from "@mui/material";
|
|
960
|
-
import { Fragment as Fragment4, jsx as
|
|
961
|
-
var CheckCodeForm = ({
|
|
1377
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1378
|
+
var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
|
|
1379
|
+
const { crudify: crudify3 } = useCrudify();
|
|
962
1380
|
const [code, setCode] = useState5("");
|
|
963
1381
|
const [loading, setLoading] = useState5(false);
|
|
964
1382
|
const [errors, setErrors] = useState5([]);
|
|
965
1383
|
const [helperTextCode, setHelperTextCode] = useState5(null);
|
|
966
1384
|
const [email, setEmail] = useState5("");
|
|
967
1385
|
const { t } = useTranslation();
|
|
968
|
-
|
|
1386
|
+
const translateError = (parsedError) => {
|
|
1387
|
+
const possibleKeys = [
|
|
1388
|
+
`errors.auth.${parsedError.code}`,
|
|
1389
|
+
`errors.data.${parsedError.code}`,
|
|
1390
|
+
`errors.system.${parsedError.code}`,
|
|
1391
|
+
`errors.${parsedError.code}`,
|
|
1392
|
+
`checkCode.${parsedError.code.toLowerCase()}`
|
|
1393
|
+
];
|
|
1394
|
+
for (const key of possibleKeys) {
|
|
1395
|
+
const translated = t(key);
|
|
1396
|
+
if (translated !== key) {
|
|
1397
|
+
return translated;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return parsedError.message || t("error.unknown");
|
|
1401
|
+
};
|
|
1402
|
+
useEffect6(() => {
|
|
969
1403
|
const emailParam = searchParams?.get("email");
|
|
970
1404
|
if (emailParam) {
|
|
971
1405
|
setEmail(emailParam);
|
|
972
1406
|
} else {
|
|
973
|
-
|
|
1407
|
+
onScreenChange?.("forgotPassword");
|
|
974
1408
|
}
|
|
975
|
-
}, [searchParams,
|
|
1409
|
+
}, [searchParams, onScreenChange]);
|
|
976
1410
|
const handleSubmit = async () => {
|
|
977
1411
|
if (loading || !crudify3) return;
|
|
978
1412
|
setErrors([]);
|
|
@@ -995,41 +1429,25 @@ var CheckCodeForm = ({ onNavigate, onError, searchParams, crudify: crudify3 }) =
|
|
|
995
1429
|
];
|
|
996
1430
|
const response = await crudify3.transaction(data);
|
|
997
1431
|
if (response.success) {
|
|
998
|
-
|
|
1432
|
+
onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
|
|
999
1433
|
} else {
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
} else if (response.errors) {
|
|
1004
|
-
if (response.errors._error) {
|
|
1005
|
-
const errors2 = response.errors._error;
|
|
1006
|
-
const translatedErrors = errors2.map((error) => {
|
|
1007
|
-
if (error === "TOO_MANY_REQUESTS") {
|
|
1008
|
-
return t("errors.auth.TOO_MANY_REQUESTS");
|
|
1009
|
-
}
|
|
1010
|
-
return error;
|
|
1011
|
-
});
|
|
1012
|
-
errorMessages.push(...translatedErrors);
|
|
1013
|
-
} else {
|
|
1014
|
-
errorMessages.push(t("error.unknown"));
|
|
1015
|
-
}
|
|
1016
|
-
} else {
|
|
1017
|
-
errorMessages.push(t("checkCode.verifyError"));
|
|
1018
|
-
}
|
|
1019
|
-
setErrors(errorMessages);
|
|
1434
|
+
const parsedErrors = handleCrudifyError(response);
|
|
1435
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1436
|
+
setErrors(translatedErrors);
|
|
1020
1437
|
setLoading(false);
|
|
1021
1438
|
}
|
|
1022
1439
|
} catch (error) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1440
|
+
const parsedErrors = handleCrudifyError(error);
|
|
1441
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
1442
|
+
setErrors(translatedErrors);
|
|
1025
1443
|
setLoading(false);
|
|
1026
1444
|
if (onError) {
|
|
1027
|
-
onError(
|
|
1445
|
+
onError(translatedErrors.join(", "));
|
|
1028
1446
|
}
|
|
1029
1447
|
}
|
|
1030
1448
|
};
|
|
1031
1449
|
const handleBack = () => {
|
|
1032
|
-
|
|
1450
|
+
onScreenChange?.("forgotPassword");
|
|
1033
1451
|
};
|
|
1034
1452
|
const handleCodeChange = (event) => {
|
|
1035
1453
|
const value = event.target.value.replace(/\D/g, "").slice(0, 6);
|
|
@@ -1038,11 +1456,11 @@ var CheckCodeForm = ({ onNavigate, onError, searchParams, crudify: crudify3 }) =
|
|
|
1038
1456
|
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1039
1457
|
/* @__PURE__ */ jsxs4(Box4, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
1040
1458
|
/* @__PURE__ */ jsxs4(Box4, { sx: { mb: 2 }, children: [
|
|
1041
|
-
/* @__PURE__ */
|
|
1042
|
-
/* @__PURE__ */
|
|
1459
|
+
/* @__PURE__ */ jsx7(Typography4, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
|
|
1460
|
+
/* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
|
|
1043
1461
|
] }),
|
|
1044
1462
|
/* @__PURE__ */ jsxs4(Box4, { sx: { mb: 1 }, children: [
|
|
1045
|
-
/* @__PURE__ */
|
|
1463
|
+
/* @__PURE__ */ jsx7(
|
|
1046
1464
|
Typography4,
|
|
1047
1465
|
{
|
|
1048
1466
|
variant: "body2",
|
|
@@ -1052,7 +1470,7 @@ var CheckCodeForm = ({ onNavigate, onError, searchParams, crudify: crudify3 }) =
|
|
|
1052
1470
|
children: t("checkCode.codeLabel")
|
|
1053
1471
|
}
|
|
1054
1472
|
),
|
|
1055
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsx7(
|
|
1056
1474
|
TextField4,
|
|
1057
1475
|
{
|
|
1058
1476
|
fullWidth: true,
|
|
@@ -1073,7 +1491,7 @@ var CheckCodeForm = ({ onNavigate, onError, searchParams, crudify: crudify3 }) =
|
|
|
1073
1491
|
}
|
|
1074
1492
|
)
|
|
1075
1493
|
] }),
|
|
1076
|
-
/* @__PURE__ */
|
|
1494
|
+
/* @__PURE__ */ jsx7(
|
|
1077
1495
|
Button4,
|
|
1078
1496
|
{
|
|
1079
1497
|
disabled: loading || code.length !== 6,
|
|
@@ -1083,33 +1501,60 @@ var CheckCodeForm = ({ onNavigate, onError, searchParams, crudify: crudify3 }) =
|
|
|
1083
1501
|
variant: "contained",
|
|
1084
1502
|
color: "primary",
|
|
1085
1503
|
sx: { mt: 2, mb: 2 },
|
|
1086
|
-
children: loading ? /* @__PURE__ */
|
|
1504
|
+
children: loading ? /* @__PURE__ */ jsx7(CircularProgress4, { size: 20 }) : t("checkCode.verifyButton")
|
|
1087
1505
|
}
|
|
1088
1506
|
),
|
|
1089
|
-
/* @__PURE__ */
|
|
1507
|
+
/* @__PURE__ */ jsx7(Box4, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx7(Link4, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
|
|
1090
1508
|
] }),
|
|
1091
|
-
/* @__PURE__ */
|
|
1509
|
+
/* @__PURE__ */ jsx7(Box4, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ jsx7(Alert4, { sx: { mt: 2 }, severity: "error", children: error }, index)) })
|
|
1092
1510
|
] });
|
|
1093
1511
|
};
|
|
1094
1512
|
var CheckCodeForm_default = CheckCodeForm;
|
|
1095
1513
|
|
|
1096
|
-
// src/components/CrudifyLogin/
|
|
1097
|
-
import {
|
|
1098
|
-
import
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1514
|
+
// src/components/CrudifyLogin/components/CrudifyInitializer.tsx
|
|
1515
|
+
import { Box as Box5, CircularProgress as CircularProgress5, Alert as Alert5, Typography as Typography5 } from "@mui/material";
|
|
1516
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1517
|
+
var CrudifyInitializer = ({
|
|
1518
|
+
children,
|
|
1519
|
+
fallback
|
|
1520
|
+
}) => {
|
|
1521
|
+
const { isLoading, error, isInitialized } = useCrudify();
|
|
1522
|
+
const { t } = useTranslation();
|
|
1523
|
+
if (isLoading) {
|
|
1524
|
+
return fallback || /* @__PURE__ */ jsxs5(
|
|
1525
|
+
Box5,
|
|
1526
|
+
{
|
|
1527
|
+
sx: {
|
|
1528
|
+
display: "flex",
|
|
1529
|
+
flexDirection: "column",
|
|
1530
|
+
alignItems: "center",
|
|
1531
|
+
justifyContent: "center",
|
|
1532
|
+
minHeight: "200px",
|
|
1533
|
+
gap: 2
|
|
1534
|
+
},
|
|
1535
|
+
children: [
|
|
1536
|
+
/* @__PURE__ */ jsx8(CircularProgress5, {}),
|
|
1537
|
+
/* @__PURE__ */ jsx8(Typography5, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
|
|
1538
|
+
]
|
|
1539
|
+
}
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
if (error) {
|
|
1543
|
+
return /* @__PURE__ */ jsx8(Alert5, { severity: "error", sx: { mt: 2 }, children: /* @__PURE__ */ jsxs5(Typography5, { variant: "body2", children: [
|
|
1544
|
+
t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
|
|
1545
|
+
": ",
|
|
1546
|
+
error
|
|
1547
|
+
] }) });
|
|
1548
|
+
}
|
|
1549
|
+
if (!isInitialized) {
|
|
1550
|
+
return /* @__PURE__ */ jsx8(Alert5, { severity: "warning", sx: { mt: 2 }, children: /* @__PURE__ */ jsx8(Typography5, { variant: "body2", children: t("login.notInitialized") !== "login.notInitialized" ? t("login.notInitialized") : "System not initialized" }) });
|
|
1551
|
+
}
|
|
1552
|
+
return /* @__PURE__ */ jsx8(Fragment5, { children });
|
|
1104
1553
|
};
|
|
1105
1554
|
|
|
1106
1555
|
// src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
|
|
1107
|
-
|
|
1108
|
-
var isGloballyInitialized = false;
|
|
1109
|
-
var lastApiKey = "";
|
|
1110
|
-
var lastEnv = "";
|
|
1556
|
+
import { useMemo as useMemo2 } from "react";
|
|
1111
1557
|
var useCrudifyLogin = (config, _options = {}) => {
|
|
1112
|
-
const [isInitialized, setIsInitialized] = useState6(false);
|
|
1113
1558
|
const finalConfig = useMemo2(() => {
|
|
1114
1559
|
const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
|
|
1115
1560
|
const rawEnv = config.env || getCookie("environment") || "prod";
|
|
@@ -1130,269 +1575,61 @@ var useCrudifyLogin = (config, _options = {}) => {
|
|
|
1130
1575
|
loginActions
|
|
1131
1576
|
};
|
|
1132
1577
|
}, [config]);
|
|
1133
|
-
|
|
1134
|
-
console.log("\u{1F527} useCrudifyLogin useEffect triggered:", {
|
|
1135
|
-
publicApiKey: !!finalConfig.publicApiKey,
|
|
1136
|
-
env: finalConfig.env,
|
|
1137
|
-
hasPublicApiKey: !!finalConfig.publicApiKey,
|
|
1138
|
-
isGloballyInitialized,
|
|
1139
|
-
lastApiKey: lastApiKey ? lastApiKey.substring(0, 10) + "..." : "none",
|
|
1140
|
-
lastEnv
|
|
1141
|
-
});
|
|
1142
|
-
if (!finalConfig.publicApiKey) {
|
|
1143
|
-
console.log("\u274C No publicApiKey, skipping crudify initialization");
|
|
1144
|
-
setIsInitialized(false);
|
|
1145
|
-
return;
|
|
1146
|
-
}
|
|
1147
|
-
const currentApiKey = finalConfig.publicApiKey;
|
|
1148
|
-
const currentEnv = finalConfig.env;
|
|
1149
|
-
if (isGloballyInitialized && lastApiKey === currentApiKey && lastEnv === currentEnv) {
|
|
1150
|
-
console.log("\u2705 Crudify already initialized with same config, reusing");
|
|
1151
|
-
setIsInitialized(true);
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
const initializeCrudify = async () => {
|
|
1155
|
-
if (globalInitPromise) {
|
|
1156
|
-
console.log("\u23F3 Waiting for existing initialization to complete");
|
|
1157
|
-
try {
|
|
1158
|
-
await globalInitPromise;
|
|
1159
|
-
setIsInitialized(isGloballyInitialized);
|
|
1160
|
-
return;
|
|
1161
|
-
} catch (error) {
|
|
1162
|
-
console.error("\u274C Previous initialization failed:", error);
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
globalInitPromise = (async () => {
|
|
1166
|
-
try {
|
|
1167
|
-
console.log("\u2699\uFE0F Configuring crudify with env:", currentEnv);
|
|
1168
|
-
crudify.config(currentEnv);
|
|
1169
|
-
console.log("\u{1F680} Initializing crudify with publicApiKey:", currentApiKey.substring(0, 10) + "...");
|
|
1170
|
-
await crudify.init(currentApiKey, "none");
|
|
1171
|
-
console.log("\u{1F9EA} Testing crudify initialization...");
|
|
1172
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
1173
|
-
if (typeof crudify.transaction === "function" && typeof crudify.login === "function") {
|
|
1174
|
-
console.log("\u2705 Crudify initialization verified and ready");
|
|
1175
|
-
isGloballyInitialized = true;
|
|
1176
|
-
lastApiKey = currentApiKey;
|
|
1177
|
-
lastEnv = currentEnv;
|
|
1178
|
-
} else {
|
|
1179
|
-
console.log("\u274C Crudify methods not properly initialized");
|
|
1180
|
-
isGloballyInitialized = false;
|
|
1181
|
-
}
|
|
1182
|
-
console.log("\u{1F50D} Crudify state after init:", {
|
|
1183
|
-
hasTransaction: typeof crudify.transaction === "function",
|
|
1184
|
-
hasLogin: typeof crudify.login === "function",
|
|
1185
|
-
isGloballyInitialized,
|
|
1186
|
-
crudifyObject: crudify
|
|
1187
|
-
});
|
|
1188
|
-
} catch (error) {
|
|
1189
|
-
console.error("\u274C Error initializing crudify:", error);
|
|
1190
|
-
isGloballyInitialized = false;
|
|
1191
|
-
throw error;
|
|
1192
|
-
}
|
|
1193
|
-
})();
|
|
1194
|
-
try {
|
|
1195
|
-
await globalInitPromise;
|
|
1196
|
-
setIsInitialized(isGloballyInitialized);
|
|
1197
|
-
} catch (error) {
|
|
1198
|
-
setIsInitialized(false);
|
|
1199
|
-
} finally {
|
|
1200
|
-
globalInitPromise = null;
|
|
1201
|
-
}
|
|
1202
|
-
};
|
|
1203
|
-
initializeCrudify();
|
|
1204
|
-
}, [finalConfig.publicApiKey, finalConfig.env]);
|
|
1205
|
-
const crudifyMethods = useMemo2(() => {
|
|
1206
|
-
console.log("\u{1F504} crudifyMethods useMemo triggered:", {
|
|
1207
|
-
publicApiKey: !!finalConfig.publicApiKey,
|
|
1208
|
-
isInitialized,
|
|
1209
|
-
isGloballyInitialized,
|
|
1210
|
-
crudifyLogin: typeof crudify.login,
|
|
1211
|
-
crudifyTransaction: typeof crudify.transaction
|
|
1212
|
-
});
|
|
1213
|
-
if (!finalConfig.publicApiKey || !isInitialized || !isGloballyInitialized) {
|
|
1214
|
-
console.log("\u274C Crudify not ready:", {
|
|
1215
|
-
publicApiKey: !!finalConfig.publicApiKey,
|
|
1216
|
-
isInitialized,
|
|
1217
|
-
isGloballyInitialized
|
|
1218
|
-
});
|
|
1219
|
-
return null;
|
|
1220
|
-
}
|
|
1221
|
-
const methods = {
|
|
1222
|
-
login: async (identifier, password) => {
|
|
1223
|
-
console.log("\u{1F517} Wrapper login called, isGloballyInitialized:", isGloballyInitialized);
|
|
1224
|
-
return await crudify.login(identifier, password);
|
|
1225
|
-
},
|
|
1226
|
-
transaction: async (data, options) => {
|
|
1227
|
-
console.log("\u{1F517} Wrapper transaction called, isGloballyInitialized:", isGloballyInitialized);
|
|
1228
|
-
return await crudify.transaction(data, options);
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
console.log("\u2705 Returning ready crudifyMethods:", {
|
|
1232
|
-
hasLogin: typeof methods.login === "function",
|
|
1233
|
-
hasTransaction: typeof methods.transaction === "function",
|
|
1234
|
-
isInitialized,
|
|
1235
|
-
isGloballyInitialized,
|
|
1236
|
-
methods
|
|
1237
|
-
});
|
|
1238
|
-
return methods;
|
|
1239
|
-
}, [finalConfig.publicApiKey, isInitialized, isGloballyInitialized]);
|
|
1240
|
-
return { crudify: crudifyMethods };
|
|
1578
|
+
return { config: finalConfig };
|
|
1241
1579
|
};
|
|
1242
1580
|
|
|
1243
1581
|
// src/components/CrudifyLogin/index.tsx
|
|
1244
|
-
import {
|
|
1582
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1245
1583
|
var CrudifyLoginInternal = ({
|
|
1246
|
-
|
|
1247
|
-
|
|
1584
|
+
onScreenChange,
|
|
1585
|
+
onExternalNavigate,
|
|
1248
1586
|
onLoginSuccess,
|
|
1249
1587
|
onError,
|
|
1250
|
-
|
|
1251
|
-
redirectUrl = "/",
|
|
1252
|
-
autoReadFromCookies = true
|
|
1588
|
+
redirectUrl = "/"
|
|
1253
1589
|
}) => {
|
|
1254
1590
|
const { t } = useTranslation();
|
|
1255
|
-
const
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
1260
|
-
if (initialScreen === "checkCode") {
|
|
1261
|
-
const email = urlParams.get("email");
|
|
1262
|
-
const code = urlParams.get("code");
|
|
1263
|
-
console.log("\u{1F517} CheckCode link detected:", { email, code });
|
|
1264
|
-
if (email) {
|
|
1265
|
-
setSearchParams(urlParams);
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
if (initialScreen === "resetPassword") {
|
|
1269
|
-
const link = urlParams.get("link");
|
|
1270
|
-
console.log("\u{1F517} ResetPassword link detected:", { link });
|
|
1271
|
-
if (link) {
|
|
1272
|
-
setSearchParams(urlParams);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
}, [initialScreen]);
|
|
1276
|
-
const finalConfig = useMemo3(() => {
|
|
1277
|
-
let cookieConfig = {};
|
|
1278
|
-
if (autoReadFromCookies) {
|
|
1279
|
-
try {
|
|
1280
|
-
let logoValue;
|
|
1281
|
-
let appColorsValue = { primaryColor: "#1066BA" };
|
|
1282
|
-
try {
|
|
1283
|
-
const encodedLogo = getCookie("logo");
|
|
1284
|
-
if (encodedLogo) {
|
|
1285
|
-
const decodedLogo = decodeURIComponent(encodedLogo);
|
|
1286
|
-
if (decodedLogo.startsWith("http")) logoValue = decodedLogo;
|
|
1287
|
-
}
|
|
1288
|
-
} catch (e) {
|
|
1289
|
-
console.warn("Could not decode logo from cookie, using default.", e);
|
|
1290
|
-
}
|
|
1291
|
-
try {
|
|
1292
|
-
const colorsCookie = getCookie("colors");
|
|
1293
|
-
if (colorsCookie) {
|
|
1294
|
-
const decodedColorsString = decodeURIComponent(colorsCookie);
|
|
1295
|
-
const parsedColors = JSON.parse(decodedColorsString);
|
|
1296
|
-
appColorsValue = { ...appColorsValue, ...parsedColors };
|
|
1297
|
-
}
|
|
1298
|
-
} catch (e) {
|
|
1299
|
-
console.error("Failed to parse colors from cookie, using defaults.", e);
|
|
1300
|
-
}
|
|
1301
|
-
cookieConfig = {
|
|
1302
|
-
logo: logoValue,
|
|
1303
|
-
colors: appColorsValue
|
|
1304
|
-
};
|
|
1305
|
-
} catch (e) {
|
|
1306
|
-
console.error("Error reading configuration from cookies:", e);
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
return {
|
|
1310
|
-
publicApiKey: providedConfig?.publicApiKey,
|
|
1311
|
-
env: providedConfig?.env,
|
|
1312
|
-
appName: providedConfig?.appName,
|
|
1313
|
-
logo: providedConfig?.logo || cookieConfig.logo,
|
|
1314
|
-
colors: { ...cookieConfig.colors, ...providedConfig?.colors },
|
|
1315
|
-
loginActions: providedConfig?.loginActions
|
|
1316
|
-
};
|
|
1317
|
-
}, [providedConfig, autoReadFromCookies]);
|
|
1318
|
-
const { crudify: crudify3 } = useCrudifyLogin(finalConfig);
|
|
1319
|
-
const handleNavigate = (path) => {
|
|
1320
|
-
console.log("\u{1F680} INTERNAL handleNavigate called with:", path);
|
|
1321
|
-
const [basePath, queryString] = path.split("?");
|
|
1322
|
-
if (queryString) {
|
|
1323
|
-
setSearchParams(new URLSearchParams(queryString));
|
|
1324
|
-
} else {
|
|
1325
|
-
setSearchParams(void 0);
|
|
1326
|
-
}
|
|
1327
|
-
let newScreen = "login";
|
|
1328
|
-
if (basePath.includes("/forgotPassword")) {
|
|
1329
|
-
newScreen = "forgotPassword";
|
|
1330
|
-
} else if (basePath.includes("/checkCode")) {
|
|
1331
|
-
newScreen = "checkCode";
|
|
1332
|
-
} else if (basePath.includes("/resetPassword")) {
|
|
1333
|
-
newScreen = "resetPassword";
|
|
1334
|
-
} else {
|
|
1335
|
-
newScreen = "login";
|
|
1336
|
-
}
|
|
1337
|
-
console.log("\u{1F3AF} INTERNAL Setting currentScreen from", currentScreen, "to", newScreen);
|
|
1338
|
-
setCurrentScreen(newScreen);
|
|
1339
|
-
console.log("\u{1F512} All navigation handled internally - no external calls");
|
|
1340
|
-
};
|
|
1341
|
-
const notifyExternal = (path, reason) => {
|
|
1342
|
-
console.log(`\u{1F4E2} Notifying external: ${reason} - ${path}`);
|
|
1343
|
-
onNavigate?.(path);
|
|
1591
|
+
const { state, setScreen } = useLoginState();
|
|
1592
|
+
const handleScreenChange = (screen2, params) => {
|
|
1593
|
+
setScreen(screen2, params);
|
|
1594
|
+
onScreenChange?.(screen2, params);
|
|
1344
1595
|
};
|
|
1345
1596
|
const renderCurrentForm = () => {
|
|
1346
|
-
console.log("\u{1F3A8} renderCurrentForm for screen:", currentScreen);
|
|
1347
1597
|
const commonProps = {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
// Navegación interna
|
|
1598
|
+
onScreenChange: handleScreenChange,
|
|
1599
|
+
onExternalNavigate,
|
|
1351
1600
|
onError,
|
|
1352
|
-
redirectUrl
|
|
1353
|
-
crudify: crudify3
|
|
1354
|
-
// Pasar la instancia compartida de crudify
|
|
1601
|
+
redirectUrl
|
|
1355
1602
|
};
|
|
1356
|
-
switch (currentScreen) {
|
|
1603
|
+
switch (state.currentScreen) {
|
|
1357
1604
|
case "forgotPassword":
|
|
1358
|
-
|
|
1359
|
-
return /* @__PURE__ */ jsx6(ForgotPasswordForm_default, { ...commonProps });
|
|
1605
|
+
return /* @__PURE__ */ jsx9(ForgotPasswordForm_default, { ...commonProps });
|
|
1360
1606
|
case "checkCode":
|
|
1361
|
-
|
|
1362
|
-
return /* @__PURE__ */ jsx6(CheckCodeForm_default, { ...commonProps, searchParams });
|
|
1607
|
+
return /* @__PURE__ */ jsx9(CheckCodeForm_default, { ...commonProps });
|
|
1363
1608
|
case "resetPassword":
|
|
1364
|
-
|
|
1365
|
-
return /* @__PURE__ */ jsx6(
|
|
1609
|
+
return /* @__PURE__ */ jsx9(
|
|
1366
1610
|
ResetPasswordForm_default,
|
|
1367
1611
|
{
|
|
1368
1612
|
...commonProps,
|
|
1369
|
-
searchParams,
|
|
1370
1613
|
onResetSuccess: () => {
|
|
1371
|
-
|
|
1614
|
+
handleScreenChange("login");
|
|
1372
1615
|
}
|
|
1373
1616
|
}
|
|
1374
1617
|
);
|
|
1375
1618
|
default:
|
|
1376
|
-
|
|
1377
|
-
return /* @__PURE__ */ jsx6(
|
|
1619
|
+
return /* @__PURE__ */ jsx9(
|
|
1378
1620
|
LoginForm_default,
|
|
1379
1621
|
{
|
|
1380
1622
|
...commonProps,
|
|
1381
|
-
onLoginSuccess
|
|
1382
|
-
if (onLoginSuccess) {
|
|
1383
|
-
onLoginSuccess(result);
|
|
1384
|
-
}
|
|
1385
|
-
notifyExternal(redirectUrl, "Login successful");
|
|
1386
|
-
}
|
|
1623
|
+
onLoginSuccess
|
|
1387
1624
|
}
|
|
1388
1625
|
);
|
|
1389
1626
|
}
|
|
1390
1627
|
};
|
|
1391
|
-
return /* @__PURE__ */
|
|
1392
|
-
/* @__PURE__ */
|
|
1628
|
+
return /* @__PURE__ */ jsxs6(CrudifyInitializer, { children: [
|
|
1629
|
+
/* @__PURE__ */ jsx9(Box6, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ jsx9(
|
|
1393
1630
|
"img",
|
|
1394
1631
|
{
|
|
1395
|
-
src:
|
|
1632
|
+
src: state.config.logo || "/nocios-default.png",
|
|
1396
1633
|
alt: t("login.logoAlt"),
|
|
1397
1634
|
style: {
|
|
1398
1635
|
width: "100%",
|
|
@@ -1405,17 +1642,17 @@ var CrudifyLoginInternal = ({
|
|
|
1405
1642
|
}
|
|
1406
1643
|
}
|
|
1407
1644
|
) }),
|
|
1408
|
-
|
|
1409
|
-
|
|
1645
|
+
state.config.appName && /* @__PURE__ */ jsx9(
|
|
1646
|
+
Typography6,
|
|
1410
1647
|
{
|
|
1411
1648
|
variant: "h6",
|
|
1412
1649
|
component: "h1",
|
|
1413
1650
|
sx: {
|
|
1414
1651
|
textAlign: "center",
|
|
1415
1652
|
mb: 2,
|
|
1416
|
-
color:
|
|
1653
|
+
color: state.config.colors?.primaryColor || "#1066BA"
|
|
1417
1654
|
},
|
|
1418
|
-
children:
|
|
1655
|
+
children: state.config.appName
|
|
1419
1656
|
}
|
|
1420
1657
|
),
|
|
1421
1658
|
renderCurrentForm()
|
|
@@ -1426,22 +1663,33 @@ var CrudifyLogin = ({
|
|
|
1426
1663
|
translationsUrl,
|
|
1427
1664
|
language = "en",
|
|
1428
1665
|
config = {},
|
|
1666
|
+
initialScreen = "login",
|
|
1667
|
+
autoReadFromCookies = true,
|
|
1429
1668
|
...props
|
|
1430
1669
|
}) => {
|
|
1431
|
-
|
|
1670
|
+
const { config: finalConfig } = useCrudifyLogin(config);
|
|
1671
|
+
return /* @__PURE__ */ jsx9(
|
|
1432
1672
|
I18nProvider,
|
|
1433
1673
|
{
|
|
1434
1674
|
translations,
|
|
1435
1675
|
translationsUrl,
|
|
1436
1676
|
language,
|
|
1437
|
-
children: /* @__PURE__ */
|
|
1677
|
+
children: /* @__PURE__ */ jsx9(CrudifyProvider, { config: finalConfig, children: /* @__PURE__ */ jsx9(
|
|
1678
|
+
LoginStateProvider,
|
|
1679
|
+
{
|
|
1680
|
+
config,
|
|
1681
|
+
initialScreen,
|
|
1682
|
+
autoReadFromCookies,
|
|
1683
|
+
children: /* @__PURE__ */ jsx9(CrudifyLoginInternal, { config, ...props })
|
|
1684
|
+
}
|
|
1685
|
+
) })
|
|
1438
1686
|
}
|
|
1439
1687
|
);
|
|
1440
1688
|
};
|
|
1441
1689
|
var CrudifyLogin_default = CrudifyLogin;
|
|
1442
1690
|
|
|
1443
1691
|
// src/hooks/useUserProfile.ts
|
|
1444
|
-
import { useState as
|
|
1692
|
+
import { useState as useState6, useEffect as useEffect7, useCallback, useRef as useRef2 } from "react";
|
|
1445
1693
|
import crudify2 from "@nocios/crudify-browser";
|
|
1446
1694
|
|
|
1447
1695
|
// src/utils/jwtUtils.ts
|
|
@@ -1487,9 +1735,9 @@ var isTokenExpired = (token) => {
|
|
|
1487
1735
|
// src/hooks/useUserProfile.ts
|
|
1488
1736
|
var useUserProfile = (options = {}) => {
|
|
1489
1737
|
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
1490
|
-
const [userProfile, setUserProfile] =
|
|
1491
|
-
const [loading, setLoading] =
|
|
1492
|
-
const [error, setError] =
|
|
1738
|
+
const [userProfile, setUserProfile] = useState6(null);
|
|
1739
|
+
const [loading, setLoading] = useState6(false);
|
|
1740
|
+
const [error, setError] = useState6(null);
|
|
1493
1741
|
const abortControllerRef = useRef2(null);
|
|
1494
1742
|
const mountedRef = useRef2(true);
|
|
1495
1743
|
const requestIdRef = useRef2(0);
|
|
@@ -1535,11 +1783,11 @@ var useUserProfile = (options = {}) => {
|
|
|
1535
1783
|
}
|
|
1536
1784
|
} catch (err) {
|
|
1537
1785
|
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
1538
|
-
|
|
1786
|
+
const error2 = err;
|
|
1787
|
+
if (error2.name === "AbortError") {
|
|
1539
1788
|
return;
|
|
1540
1789
|
}
|
|
1541
|
-
|
|
1542
|
-
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (err.message?.includes("Network Error") || err.message?.includes("Failed to fetch"));
|
|
1790
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
1543
1791
|
if (shouldRetry) {
|
|
1544
1792
|
retryCountRef.current++;
|
|
1545
1793
|
setTimeout(() => {
|
|
@@ -1561,12 +1809,12 @@ var useUserProfile = (options = {}) => {
|
|
|
1561
1809
|
}
|
|
1562
1810
|
}
|
|
1563
1811
|
}, [retryOnError, maxRetries]);
|
|
1564
|
-
|
|
1812
|
+
useEffect7(() => {
|
|
1565
1813
|
if (autoFetch) {
|
|
1566
1814
|
refreshProfile();
|
|
1567
1815
|
}
|
|
1568
1816
|
}, [autoFetch, refreshProfile]);
|
|
1569
|
-
|
|
1817
|
+
useEffect7(() => {
|
|
1570
1818
|
mountedRef.current = true;
|
|
1571
1819
|
return () => {
|
|
1572
1820
|
mountedRef.current = false;
|
|
@@ -1586,11 +1834,18 @@ var useUserProfile = (options = {}) => {
|
|
|
1586
1834
|
};
|
|
1587
1835
|
export {
|
|
1588
1836
|
CrudifyLogin_default as CrudifyLogin,
|
|
1837
|
+
ERROR_CODES,
|
|
1838
|
+
ERROR_SEVERITY_MAP,
|
|
1589
1839
|
default2 as crudify,
|
|
1590
1840
|
decodeJwtSafely,
|
|
1591
1841
|
getCookie,
|
|
1592
1842
|
getCurrentUserEmail,
|
|
1843
|
+
getErrorMessage,
|
|
1844
|
+
handleCrudifyError,
|
|
1593
1845
|
isTokenExpired,
|
|
1846
|
+
parseApiError,
|
|
1847
|
+
parseJavaScriptError,
|
|
1848
|
+
parseTransactionError,
|
|
1594
1849
|
secureLocalStorage,
|
|
1595
1850
|
secureSessionStorage,
|
|
1596
1851
|
useCrudifyLogin,
|