@nocios/crudify-ui 4.0.8 → 4.0.92

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/dist/index.js CHANGED
@@ -1,4906 +1 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/index.ts
32
- var index_exports = {};
33
- __export(index_exports, {
34
- CrudifyLogin: () => CrudifyLogin_default,
35
- ERROR_CODES: () => ERROR_CODES,
36
- ERROR_SEVERITY_MAP: () => ERROR_SEVERITY_MAP,
37
- GlobalNotificationProvider: () => GlobalNotificationProvider,
38
- LoginComponent: () => LoginComponent,
39
- POLICY_ACTIONS: () => POLICY_ACTIONS,
40
- PREFERRED_POLICY_ORDER: () => PREFERRED_POLICY_ORDER,
41
- Policies: () => Policies_default,
42
- ProtectedRoute: () => ProtectedRoute,
43
- SessionDebugInfo: () => SessionDebugInfo,
44
- SessionManager: () => SessionManager,
45
- SessionProvider: () => SessionProvider,
46
- SessionStatus: () => SessionStatus,
47
- TokenStorage: () => TokenStorage,
48
- UserProfileDisplay: () => UserProfileDisplay_default,
49
- createErrorTranslator: () => createErrorTranslator,
50
- crudify: () => import_crudify_browser7.default,
51
- decodeJwtSafely: () => decodeJwtSafely,
52
- getCookie: () => getCookie,
53
- getCurrentUserEmail: () => getCurrentUserEmail,
54
- getErrorMessage: () => getErrorMessage,
55
- handleCrudifyError: () => handleCrudifyError,
56
- isTokenExpired: () => isTokenExpired,
57
- parseApiError: () => parseApiError,
58
- parseJavaScriptError: () => parseJavaScriptError,
59
- parseTransactionError: () => parseTransactionError,
60
- secureLocalStorage: () => secureLocalStorage,
61
- secureSessionStorage: () => secureSessionStorage,
62
- translateError: () => translateError,
63
- translateErrorCode: () => translateErrorCode,
64
- translateErrorCodes: () => translateErrorCodes,
65
- useAuth: () => useAuth,
66
- useCrudifyWithNotifications: () => useCrudifyWithNotifications,
67
- useData: () => useData,
68
- useGlobalNotification: () => useGlobalNotification,
69
- useSession: () => useSession,
70
- useSessionContext: () => useSessionContext,
71
- useUserData: () => useUserData,
72
- useUserProfile: () => useUserProfile
73
- });
74
- module.exports = __toCommonJS(index_exports);
75
- var import_crudify_browser7 = __toESM(require("@nocios/crudify-browser"));
76
- __reExport(index_exports, require("@nocios/crudify-browser"), module.exports);
77
-
78
- // src/components/CrudifyLogin/index.tsx
79
- var import_material7 = require("@mui/material");
80
-
81
- // src/components/CrudifyLogin/context/I18nProvider.tsx
82
- var import_react2 = require("react");
83
-
84
- // src/components/CrudifyLogin/hooks/useTranslationsFromUrl.ts
85
- var import_react = require("react");
86
- var useTranslationsFromUrl = (url, providedTranslations) => {
87
- const [translations, setTranslations] = (0, import_react.useState)({});
88
- const [loading, setLoading] = (0, import_react.useState)(false);
89
- const [error, setError] = (0, import_react.useState)(null);
90
- (0, import_react.useEffect)(() => {
91
- console.log("\u{1F527} [I18nProvider] Hybrid translation loading:", {
92
- hasProvidedTranslations: !!providedTranslations && Object.keys(providedTranslations).length > 0,
93
- hasUrl: !!url,
94
- providedKeys: providedTranslations ? Object.keys(providedTranslations).length : 0
95
- });
96
- if (providedTranslations && Object.keys(providedTranslations).length > 0) {
97
- console.log("\u2705 [I18nProvider] Using provided translations (highest priority)");
98
- setTranslations(providedTranslations);
99
- setLoading(false);
100
- setError(null);
101
- return;
102
- }
103
- if (!url) {
104
- console.log("\u26A0\uFE0F [I18nProvider] No translations provided, using empty object (keys will show as-is)");
105
- setTranslations({});
106
- setLoading(false);
107
- setError(null);
108
- return;
109
- }
110
- console.log("\u{1F310} [I18nProvider] Loading translations from URL:", url);
111
- let isCancelled = false;
112
- setLoading(true);
113
- setError(null);
114
- fetch(url).then((response) => {
115
- if (!response.ok) {
116
- throw new Error(`Failed to load translations: ${response.status}`);
117
- }
118
- return response.json();
119
- }).then((data) => {
120
- if (!isCancelled) {
121
- console.log("\u2705 [I18nProvider] Translations loaded successfully from URL:", {
122
- url,
123
- keysLoaded: Object.keys(data).length
124
- });
125
- setTranslations(data);
126
- setLoading(false);
127
- }
128
- }).catch((err) => {
129
- if (!isCancelled) {
130
- console.error("\u274C [I18nProvider] Failed to load translations from URL:", url, err);
131
- setError(err.message);
132
- console.log("\u{1F504} [I18nProvider] Falling back to empty translations (keys will show as-is)");
133
- setTranslations({});
134
- setLoading(false);
135
- }
136
- });
137
- return () => {
138
- isCancelled = true;
139
- };
140
- }, [url, providedTranslations]);
141
- return {
142
- translations,
143
- loading,
144
- error
145
- };
146
- };
147
-
148
- // src/components/CrudifyLogin/context/I18nProvider.tsx
149
- var import_jsx_runtime = require("react/jsx-runtime");
150
- var I18nContext = (0, import_react2.createContext)(null);
151
- var getNestedValue = (obj, path) => {
152
- if (obj && obj[path]) return obj[path];
153
- return path.split(".").reduce((current, key) => {
154
- return current && typeof current === "object" ? current[key] : void 0;
155
- }, obj);
156
- };
157
- var I18nProvider = ({ children, translations, translationsUrl, language = "en" }) => {
158
- const { translations: loadedTranslations, loading } = useTranslationsFromUrl(translationsUrl, translations);
159
- const t = (0, import_react2.useMemo)(() => {
160
- return (key, variables) => {
161
- let value = getNestedValue(loadedTranslations, key);
162
- if (value === void 0 || value === null) {
163
- console.log(`\u{1F50D} [I18nProvider] Translation not found for key: "${key}" - showing key as-is`);
164
- value = key;
165
- }
166
- if (variables && typeof value === "string") {
167
- Object.entries(variables).forEach(([varKey, varValue]) => {
168
- value = value.replace(new RegExp(`{{${varKey}}}`, "g"), varValue);
169
- });
170
- }
171
- return typeof value === "string" ? value : key;
172
- };
173
- }, [loadedTranslations]);
174
- const contextValue = (0, import_react2.useMemo)(
175
- () => ({
176
- t,
177
- language
178
- }),
179
- [t, language]
180
- );
181
- if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading translations..." });
182
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nContext.Provider, { value: contextValue, children });
183
- };
184
- var useTranslation = () => {
185
- const context = (0, import_react2.useContext)(I18nContext);
186
- if (!context) {
187
- throw new Error("useTranslation must be used within I18nProvider");
188
- }
189
- return context;
190
- };
191
-
192
- // src/components/CrudifyLogin/context/CrudifyProvider.tsx
193
- var import_react3 = require("react");
194
- var import_crudify_browser = __toESM(require("@nocios/crudify-browser"));
195
- var import_jsx_runtime2 = require("react/jsx-runtime");
196
- var CrudifyContext = (0, import_react3.createContext)(void 0);
197
- var CrudifyProvider = ({ config, children }) => {
198
- const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
199
- const [error, setError] = (0, import_react3.useState)(null);
200
- const [isInitialized, setIsInitialized] = (0, import_react3.useState)(false);
201
- const [initializationKey, setInitializationKey] = (0, import_react3.useState)("");
202
- console.log("\u{1F50D} CrudifyProvider - Received config:", config);
203
- (0, import_react3.useEffect)(() => {
204
- console.log("\u{1F50D} CrudifyProvider - useEffect - config.publicApiKey:", config.publicApiKey);
205
- console.log("\u{1F50D} CrudifyProvider - useEffect - full config:", config);
206
- if (!config.publicApiKey) {
207
- console.log("\u274C CrudifyProvider - No publicApiKey provided, setting error");
208
- setError("No publicApiKey provided");
209
- setIsLoading(false);
210
- setIsInitialized(false);
211
- return;
212
- }
213
- console.log("\u2705 CrudifyProvider - publicApiKey found, proceeding with initialization");
214
- const currentKey = `${config.publicApiKey}-${config.env}`;
215
- if (currentKey === initializationKey && isInitialized) {
216
- setIsLoading(false);
217
- return;
218
- }
219
- const initializeCrudify = async () => {
220
- setIsLoading(true);
221
- setError(null);
222
- setIsInitialized(false);
223
- try {
224
- import_crudify_browser.default.config(config.env || "prod");
225
- await import_crudify_browser.default.init(config.publicApiKey, "none");
226
- if (typeof import_crudify_browser.default.transaction === "function" && typeof import_crudify_browser.default.login === "function") {
227
- setIsInitialized(true);
228
- setInitializationKey(currentKey);
229
- } else {
230
- throw new Error("Crudify methods not properly initialized");
231
- }
232
- } catch (err) {
233
- const errorMessage = err instanceof Error ? err.message : "Failed to initialize Crudify";
234
- setError(errorMessage);
235
- setIsInitialized(false);
236
- } finally {
237
- setIsLoading(false);
238
- }
239
- };
240
- initializeCrudify();
241
- }, [config.publicApiKey, config.env, initializationKey, isInitialized]);
242
- const value = {
243
- crudify: isInitialized ? import_crudify_browser.default : null,
244
- isLoading,
245
- error,
246
- isInitialized
247
- };
248
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CrudifyContext.Provider, { value, children });
249
- };
250
- var useCrudify = () => {
251
- const context = (0, import_react3.useContext)(CrudifyContext);
252
- if (context === void 0) {
253
- throw new Error("useCrudify must be used within a CrudifyProvider");
254
- }
255
- return context;
256
- };
257
-
258
- // src/components/CrudifyLogin/context/LoginStateProvider.tsx
259
- var import_react4 = require("react");
260
-
261
- // src/components/CrudifyLogin/utils/cookies.ts
262
- var getCookie = (name) => {
263
- const match = document.cookie.match(new RegExp("(^|;)\\s*" + name + "=([^;]+)"));
264
- return match ? match[2] : null;
265
- };
266
-
267
- // src/components/CrudifyLogin/context/LoginStateProvider.tsx
268
- var import_jsx_runtime3 = require("react/jsx-runtime");
269
- var initialState = {
270
- currentScreen: "login",
271
- searchParams: {},
272
- formData: {
273
- username: "",
274
- password: "",
275
- email: "",
276
- code: "",
277
- newPassword: "",
278
- confirmPassword: ""
279
- },
280
- loading: false,
281
- errors: {
282
- global: []
283
- },
284
- emailSent: false,
285
- codeAlreadyExists: false,
286
- codeValidated: false,
287
- fromCodeVerification: false,
288
- config: {}
289
- };
290
- function loginStateReducer(state, action) {
291
- switch (action.type) {
292
- case "SET_SCREEN":
293
- const newState = {
294
- ...state,
295
- currentScreen: action.payload.screen,
296
- searchParams: action.payload.params || state.searchParams,
297
- // Clear form errors when changing screens
298
- errors: { global: [] }
299
- };
300
- const newUrl = new URLSearchParams(newState.searchParams);
301
- const newPath = newUrl.toString() ? `?${newUrl.toString()}` : window.location.pathname;
302
- try {
303
- window.history.replaceState({}, "", newPath);
304
- } catch (error) {
305
- }
306
- return newState;
307
- case "SET_SEARCH_PARAMS":
308
- return {
309
- ...state,
310
- searchParams: action.payload
311
- };
312
- case "UPDATE_FORM_DATA":
313
- return {
314
- ...state,
315
- formData: {
316
- ...state.formData,
317
- ...action.payload
318
- },
319
- // Clear related errors when updating form data
320
- errors: {
321
- ...state.errors,
322
- ...Object.keys(action.payload).reduce(
323
- (acc, key) => ({
324
- ...acc,
325
- [key]: void 0
326
- }),
327
- {}
328
- )
329
- }
330
- };
331
- case "SET_LOADING":
332
- return {
333
- ...state,
334
- loading: action.payload
335
- };
336
- case "SET_ERRORS":
337
- return {
338
- ...state,
339
- errors: {
340
- ...state.errors,
341
- ...action.payload
342
- }
343
- };
344
- case "CLEAR_ERRORS":
345
- return {
346
- ...state,
347
- errors: { global: [] }
348
- };
349
- case "SET_EMAIL_SENT":
350
- return {
351
- ...state,
352
- emailSent: action.payload
353
- };
354
- case "SET_CODE_ALREADY_EXISTS":
355
- return {
356
- ...state,
357
- codeAlreadyExists: action.payload
358
- };
359
- case "SET_CODE_VALIDATED":
360
- return {
361
- ...state,
362
- codeValidated: action.payload
363
- };
364
- case "SET_FROM_CODE_VERIFICATION":
365
- return {
366
- ...state,
367
- fromCodeVerification: action.payload
368
- };
369
- case "RESET_FORM":
370
- return {
371
- ...state,
372
- formData: initialState.formData,
373
- errors: { global: [] },
374
- loading: false,
375
- emailSent: false,
376
- codeAlreadyExists: false,
377
- codeValidated: false,
378
- fromCodeVerification: false
379
- };
380
- case "INIT_CONFIG":
381
- return {
382
- ...state,
383
- config: action.payload
384
- };
385
- default:
386
- return state;
387
- }
388
- }
389
- var LoginStateContext = (0, import_react4.createContext)(void 0);
390
- var LoginStateProvider = ({
391
- children,
392
- initialScreen = "login",
393
- config: providedConfig,
394
- autoReadFromCookies = true
395
- }) => {
396
- const [state, dispatch] = (0, import_react4.useReducer)(loginStateReducer, {
397
- ...initialState,
398
- currentScreen: initialScreen
399
- });
400
- (0, import_react4.useEffect)(() => {
401
- const buildFinalConfig = () => {
402
- let cookieConfig = {};
403
- if (autoReadFromCookies) {
404
- try {
405
- const encodedLogo = getCookie("logo");
406
- if (encodedLogo) {
407
- const decodedLogo = decodeURIComponent(encodedLogo);
408
- if (decodedLogo.startsWith("http")) {
409
- cookieConfig.logo = decodedLogo;
410
- }
411
- }
412
- } catch (e) {
413
- console.error("Error reading configuration from cookies:", e);
414
- }
415
- }
416
- return {
417
- publicApiKey: providedConfig?.publicApiKey,
418
- env: providedConfig?.env,
419
- appName: providedConfig?.appName,
420
- logo: providedConfig?.logo || cookieConfig.logo,
421
- loginActions: providedConfig?.loginActions
422
- };
423
- };
424
- dispatch({ type: "INIT_CONFIG", payload: buildFinalConfig() });
425
- }, [providedConfig, autoReadFromCookies]);
426
- (0, import_react4.useEffect)(() => {
427
- const urlParams = new URLSearchParams(window.location.search);
428
- const paramsObject = {};
429
- urlParams.forEach((value2, key) => {
430
- paramsObject[key] = value2;
431
- });
432
- if (Object.keys(paramsObject).length > 0) {
433
- dispatch({ type: "SET_SEARCH_PARAMS", payload: paramsObject });
434
- }
435
- if (initialScreen === "checkCode" && paramsObject.email) {
436
- dispatch({
437
- type: "UPDATE_FORM_DATA",
438
- payload: { email: paramsObject.email, code: paramsObject.code || "" }
439
- });
440
- }
441
- if (initialScreen === "resetPassword" && paramsObject.link) {
442
- dispatch({ type: "SET_SEARCH_PARAMS", payload: paramsObject });
443
- }
444
- }, [initialScreen]);
445
- const setScreen = (screen2, params) => {
446
- dispatch({ type: "SET_SCREEN", payload: { screen: screen2, params } });
447
- };
448
- const updateFormData = (data) => {
449
- dispatch({ type: "UPDATE_FORM_DATA", payload: data });
450
- };
451
- const setFieldError = (field, error) => {
452
- dispatch({ type: "SET_ERRORS", payload: { [field]: error } });
453
- };
454
- const clearErrors = () => {
455
- dispatch({ type: "CLEAR_ERRORS" });
456
- };
457
- const setLoading = (loading) => {
458
- dispatch({ type: "SET_LOADING", payload: loading });
459
- };
460
- const value = {
461
- state,
462
- dispatch,
463
- setScreen,
464
- updateFormData,
465
- setFieldError,
466
- clearErrors,
467
- setLoading
468
- };
469
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoginStateContext.Provider, { value, children });
470
- };
471
- var useLoginState = () => {
472
- const context = (0, import_react4.useContext)(LoginStateContext);
473
- if (context === void 0) {
474
- throw new Error("useLoginState must be used within a LoginStateProvider");
475
- }
476
- return context;
477
- };
478
-
479
- // src/providers/SessionProvider.tsx
480
- var import_react7 = __toESM(require("react"));
481
-
482
- // src/hooks/useSession.ts
483
- var import_react5 = require("react");
484
-
485
- // src/core/SessionManager.ts
486
- var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
487
-
488
- // src/utils/tokenStorage.ts
489
- var import_crypto_js = __toESM(require("crypto-js"));
490
- var _TokenStorage = class _TokenStorage {
491
- /**
492
- * Configurar tipo de almacenamiento
493
- */
494
- static setStorageType(type) {
495
- _TokenStorage.storageType = type;
496
- }
497
- /**
498
- * Generar clave de encriptación única y persistente
499
- */
500
- static generateEncryptionKey() {
501
- const browserInfo = [
502
- navigator.userAgent,
503
- navigator.language,
504
- navigator.platform,
505
- screen.width,
506
- screen.height,
507
- Date.now().toString(),
508
- Math.random().toString(36)
509
- ].join("|");
510
- return import_crypto_js.default.SHA256(browserInfo).toString();
511
- }
512
- /**
513
- * Obtener o generar clave de encriptación
514
- */
515
- static getEncryptionKey() {
516
- if (_TokenStorage.encryptionKey) {
517
- return _TokenStorage.encryptionKey;
518
- }
519
- const storage = window.localStorage;
520
- if (!storage) {
521
- _TokenStorage.encryptionKey = _TokenStorage.generateEncryptionKey();
522
- return _TokenStorage.encryptionKey;
523
- }
524
- try {
525
- let existingKey = storage.getItem(_TokenStorage.ENCRYPTION_KEY_STORAGE);
526
- if (!existingKey || existingKey.length < 32) {
527
- existingKey = _TokenStorage.generateEncryptionKey();
528
- storage.setItem(_TokenStorage.ENCRYPTION_KEY_STORAGE, existingKey);
529
- }
530
- _TokenStorage.encryptionKey = existingKey;
531
- return existingKey;
532
- } catch (error) {
533
- console.warn("Crudify: Cannot persist encryption key, using temporary key");
534
- _TokenStorage.encryptionKey = _TokenStorage.generateEncryptionKey();
535
- return _TokenStorage.encryptionKey;
536
- }
537
- }
538
- /**
539
- * Verificar si el storage está disponible
540
- */
541
- static isStorageAvailable(type) {
542
- try {
543
- const storage = window[type];
544
- const testKey = "__storage_test__";
545
- storage.setItem(testKey, "test");
546
- storage.removeItem(testKey);
547
- return true;
548
- } catch {
549
- return false;
550
- }
551
- }
552
- /**
553
- * Obtener instancia de storage
554
- */
555
- static getStorage() {
556
- if (_TokenStorage.storageType === "none") return null;
557
- if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
558
- console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
559
- return null;
560
- }
561
- return window[_TokenStorage.storageType];
562
- }
563
- /**
564
- * Encriptar datos sensibles
565
- */
566
- static encrypt(data) {
567
- try {
568
- const encryptionKey = _TokenStorage.getEncryptionKey();
569
- return import_crypto_js.default.AES.encrypt(data, encryptionKey).toString();
570
- } catch (error) {
571
- console.error("Crudify: Encryption failed", error);
572
- return data;
573
- }
574
- }
575
- /**
576
- * Desencriptar datos
577
- */
578
- static decrypt(encryptedData) {
579
- try {
580
- const encryptionKey = _TokenStorage.getEncryptionKey();
581
- const bytes = import_crypto_js.default.AES.decrypt(encryptedData, encryptionKey);
582
- const decrypted = bytes.toString(import_crypto_js.default.enc.Utf8);
583
- return decrypted || encryptedData;
584
- } catch (error) {
585
- console.error("Crudify: Decryption failed", error);
586
- return encryptedData;
587
- }
588
- }
589
- /**
590
- * Guardar tokens de forma segura
591
- */
592
- static saveTokens(tokens) {
593
- const storage = _TokenStorage.getStorage();
594
- if (!storage) return;
595
- try {
596
- const tokenData = {
597
- accessToken: tokens.accessToken,
598
- refreshToken: tokens.refreshToken,
599
- expiresAt: tokens.expiresAt,
600
- refreshExpiresAt: tokens.refreshExpiresAt,
601
- savedAt: Date.now()
602
- };
603
- const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
604
- storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
605
- console.debug("Crudify: Tokens saved successfully");
606
- } catch (error) {
607
- console.error("Crudify: Failed to save tokens", error);
608
- }
609
- }
610
- /**
611
- * Obtener tokens guardados
612
- */
613
- static getTokens() {
614
- const storage = _TokenStorage.getStorage();
615
- if (!storage) return null;
616
- try {
617
- const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
618
- if (!encrypted) return null;
619
- const decrypted = _TokenStorage.decrypt(encrypted);
620
- const tokenData = JSON.parse(decrypted);
621
- if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
622
- console.warn("Crudify: Incomplete token data found, clearing storage");
623
- _TokenStorage.clearTokens();
624
- return null;
625
- }
626
- if (Date.now() >= tokenData.refreshExpiresAt) {
627
- console.info("Crudify: Refresh token expired, clearing storage");
628
- _TokenStorage.clearTokens();
629
- return null;
630
- }
631
- return {
632
- accessToken: tokenData.accessToken,
633
- refreshToken: tokenData.refreshToken,
634
- expiresAt: tokenData.expiresAt,
635
- refreshExpiresAt: tokenData.refreshExpiresAt
636
- };
637
- } catch (error) {
638
- console.error("Crudify: Failed to retrieve tokens", error);
639
- _TokenStorage.clearTokens();
640
- return null;
641
- }
642
- }
643
- /**
644
- * Limpiar tokens almacenados
645
- */
646
- static clearTokens() {
647
- const storage = _TokenStorage.getStorage();
648
- if (!storage) return;
649
- try {
650
- storage.removeItem(_TokenStorage.TOKEN_KEY);
651
- console.debug("Crudify: Tokens cleared from storage");
652
- } catch (error) {
653
- console.error("Crudify: Failed to clear tokens", error);
654
- }
655
- }
656
- /**
657
- * Rotar clave de encriptación (limpia tokens existentes por seguridad)
658
- */
659
- static rotateEncryptionKey() {
660
- try {
661
- _TokenStorage.clearTokens();
662
- _TokenStorage.encryptionKey = null;
663
- const storage = window.localStorage;
664
- if (storage) {
665
- storage.removeItem(_TokenStorage.ENCRYPTION_KEY_STORAGE);
666
- }
667
- console.info("Crudify: Encryption key rotated successfully");
668
- } catch (error) {
669
- console.error("Crudify: Failed to rotate encryption key", error);
670
- }
671
- }
672
- /**
673
- * Verificar si hay tokens válidos guardados
674
- */
675
- static hasValidTokens() {
676
- const tokens = _TokenStorage.getTokens();
677
- return tokens !== null;
678
- }
679
- /**
680
- * Obtener información de expiración
681
- */
682
- static getExpirationInfo() {
683
- const tokens = _TokenStorage.getTokens();
684
- if (!tokens) return null;
685
- const now = Date.now();
686
- return {
687
- accessExpired: now >= tokens.expiresAt,
688
- refreshExpired: now >= tokens.refreshExpiresAt,
689
- accessExpiresIn: Math.max(0, tokens.expiresAt - now),
690
- refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
691
- };
692
- }
693
- /**
694
- * Actualizar solo el access token (después de refresh)
695
- */
696
- static updateAccessToken(newAccessToken, newExpiresAt) {
697
- const existingTokens = _TokenStorage.getTokens();
698
- if (!existingTokens) {
699
- console.warn("Crudify: Cannot update access token, no existing tokens found");
700
- return;
701
- }
702
- _TokenStorage.saveTokens({
703
- ...existingTokens,
704
- accessToken: newAccessToken,
705
- expiresAt: newExpiresAt
706
- });
707
- }
708
- };
709
- _TokenStorage.TOKEN_KEY = "crudify_tokens";
710
- _TokenStorage.ENCRYPTION_KEY_STORAGE = "crudify_enc_key";
711
- _TokenStorage.encryptionKey = null;
712
- _TokenStorage.storageType = "localStorage";
713
- var TokenStorage = _TokenStorage;
714
-
715
- // src/utils/errorTranslation.ts
716
- var ERROR_TRANSLATION_HIERARCHY = [
717
- "errors.{category}.{code}",
718
- // errors.auth.INVALID_CREDENTIALS
719
- "errors.{code}",
720
- // errors.INVALID_CREDENTIALS
721
- "login.{code}",
722
- // login.INVALID_CREDENTIALS (legacy)
723
- "error.{code}",
724
- // error.INVALID_CREDENTIALS (singular)
725
- "messages.{code}",
726
- // messages.INVALID_CREDENTIALS
727
- "{code}"
728
- // INVALID_CREDENTIALS (direct)
729
- ];
730
- var ERROR_CATEGORY_MAP = {
731
- // Authentication errors
732
- "INVALID_CREDENTIALS": "auth",
733
- "UNAUTHORIZED": "auth",
734
- "INVALID_API_KEY": "auth",
735
- "USER_NOT_FOUND": "auth",
736
- "USER_NOT_ACTIVE": "auth",
737
- "NO_PERMISSION": "auth",
738
- "SESSION_EXPIRED": "auth",
739
- // Data errors
740
- "ITEM_NOT_FOUND": "data",
741
- "NOT_FOUND": "data",
742
- "IN_USE": "data",
743
- "DUPLICATE_ENTRY": "data",
744
- // Validation errors
745
- "FIELD_ERROR": "validation",
746
- "BAD_REQUEST": "validation",
747
- "INVALID_EMAIL": "validation",
748
- "INVALID_CODE": "validation",
749
- "REQUIRED_FIELD": "validation",
750
- // System errors
751
- "INTERNAL_SERVER_ERROR": "system",
752
- "DATABASE_CONNECTION_ERROR": "system",
753
- "INVALID_CONFIGURATION": "system",
754
- "UNKNOWN_OPERATION": "system",
755
- "TIMEOUT_ERROR": "system",
756
- "NETWORK_ERROR": "system",
757
- // Rate limiting
758
- "TOO_MANY_REQUESTS": "rate_limit"
759
- };
760
- var DEFAULT_ERROR_MESSAGES = {
761
- "INVALID_CREDENTIALS": "Invalid username or password",
762
- "UNAUTHORIZED": "You are not authorized to perform this action",
763
- "SESSION_EXPIRED": "Your session has expired. Please log in again.",
764
- "USER_NOT_FOUND": "User not found",
765
- "ITEM_NOT_FOUND": "Item not found",
766
- "FIELD_ERROR": "Invalid field value",
767
- "INTERNAL_SERVER_ERROR": "An internal error occurred",
768
- "NETWORK_ERROR": "Network connection error",
769
- "TIMEOUT_ERROR": "Request timeout",
770
- "UNKNOWN_OPERATION": "Unknown operation",
771
- "INVALID_EMAIL": "Invalid email format",
772
- "INVALID_CODE": "Invalid code",
773
- "TOO_MANY_REQUESTS": "Too many requests, please try again later"
774
- };
775
- function translateErrorCode(errorCode, config) {
776
- const { translateFn, currentLanguage, enableDebug } = config;
777
- if (enableDebug) {
778
- console.log(`\u{1F50D} [ErrorTranslation] Translating error code: ${errorCode} (lang: ${currentLanguage || "unknown"})`);
779
- }
780
- const normalizedCode = errorCode.toUpperCase();
781
- const category = ERROR_CATEGORY_MAP[normalizedCode];
782
- const translationKeys = ERROR_TRANSLATION_HIERARCHY.map((pattern) => {
783
- return pattern.replace("{category}", category || "general").replace("{code}", normalizedCode);
784
- });
785
- if (enableDebug) {
786
- console.log(`\u{1F511} [ErrorTranslation] Searching keys:`, translationKeys);
787
- }
788
- for (const key of translationKeys) {
789
- const translated = translateFn(key);
790
- if (enableDebug) {
791
- console.log(`\u{1F50D} [ErrorTranslation] Checking key: "${key}" -> result: "${translated}" (same as key: ${translated === key})`);
792
- }
793
- if (translated && translated !== key) {
794
- if (enableDebug) {
795
- console.log(`\u2705 [ErrorTranslation] Found translation at key: ${key} = "${translated}"`);
796
- }
797
- return translated;
798
- }
799
- }
800
- const defaultMessage = DEFAULT_ERROR_MESSAGES[normalizedCode];
801
- if (defaultMessage) {
802
- if (enableDebug) {
803
- console.log(`\u{1F504} [ErrorTranslation] Using default message: "${defaultMessage}"`);
804
- }
805
- return defaultMessage;
806
- }
807
- const friendlyCode = normalizedCode.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
808
- if (enableDebug) {
809
- console.log(`\u26A0\uFE0F [ErrorTranslation] No translation found, using friendly code: "${friendlyCode}"`);
810
- }
811
- return friendlyCode;
812
- }
813
- function translateErrorCodes(errorCodes, config) {
814
- return errorCodes.map((code) => translateErrorCode(code, config));
815
- }
816
- function translateError(error, config) {
817
- const { enableDebug } = config;
818
- if (enableDebug) {
819
- console.log(`\u{1F50D} [ErrorTranslation] Translating error:`, error);
820
- }
821
- const translatedCode = translateErrorCode(error.code, config);
822
- if (translatedCode !== error.code.toUpperCase() && translatedCode !== error.code) {
823
- if (enableDebug) {
824
- console.log(`\u2705 [ErrorTranslation] Using hierarchical translation: "${translatedCode}"`);
825
- }
826
- if (error.field) {
827
- return `${error.field}: ${translatedCode}`;
828
- }
829
- return translatedCode;
830
- }
831
- if (error.message && !error.message.includes("Error:") && error.message.length > 0 && error.message !== error.code) {
832
- if (enableDebug) {
833
- console.log(`\u{1F504} [ErrorTranslation] No hierarchical translation found, using API message: "${error.message}"`);
834
- }
835
- return error.message;
836
- }
837
- if (enableDebug) {
838
- console.log(`\u26A0\uFE0F [ErrorTranslation] Using final fallback: "${translatedCode}"`);
839
- }
840
- if (error.field) {
841
- return `${error.field}: ${translatedCode}`;
842
- }
843
- return translatedCode;
844
- }
845
- function createErrorTranslator(translateFn, options = {}) {
846
- const config = {
847
- translateFn,
848
- currentLanguage: options.currentLanguage,
849
- enableDebug: options.enableDebug || false
850
- };
851
- return {
852
- translateErrorCode: (code) => translateErrorCode(code, config),
853
- translateErrorCodes: (codes) => translateErrorCodes(codes, config),
854
- translateError: (error) => translateError(error, config),
855
- // Método de conveniencia para errores de API
856
- translateApiError: (apiResponse) => {
857
- if (apiResponse?.data?.response?.status) {
858
- return translateErrorCode(apiResponse.data.response.status, config);
859
- }
860
- if (apiResponse?.status) {
861
- return translateErrorCode(apiResponse.status, config);
862
- }
863
- if (apiResponse?.code) {
864
- return translateErrorCode(apiResponse.code, config);
865
- }
866
- return "Unknown error";
867
- }
868
- };
869
- }
870
-
871
- // src/core/SessionManager.ts
872
- var SessionManager = class _SessionManager {
873
- constructor() {
874
- this.config = {};
875
- this.initialized = false;
876
- }
877
- static getInstance() {
878
- if (!_SessionManager.instance) {
879
- _SessionManager.instance = new _SessionManager();
880
- }
881
- return _SessionManager.instance;
882
- }
883
- /**
884
- * Inicializar el SessionManager
885
- */
886
- async initialize(config = {}) {
887
- if (this.initialized) {
888
- console.warn("SessionManager: Already initialized");
889
- return;
890
- }
891
- this.config = {
892
- storageType: "localStorage",
893
- autoRestore: true,
894
- enableLogging: false,
895
- ...config
896
- };
897
- TokenStorage.setStorageType(this.config.storageType || "localStorage");
898
- if (this.config.enableLogging) {
899
- }
900
- if (this.config.autoRestore) {
901
- await this.restoreSession();
902
- }
903
- this.initialized = true;
904
- this.log("SessionManager initialized successfully");
905
- }
906
- /**
907
- * Login con persistencia automática
908
- */
909
- async login(email, password) {
910
- try {
911
- this.log("Attempting login...");
912
- const response = await import_crudify_browser2.default.login(email, password);
913
- if (!response.success) {
914
- this.log("Login failed:", response.errors);
915
- return {
916
- success: false,
917
- error: this.formatError(response.errors),
918
- rawResponse: response
919
- // Preservar respuesta original para manejo de errores específicos
920
- };
921
- }
922
- const tokens = {
923
- accessToken: response.data.token,
924
- refreshToken: response.data.refreshToken,
925
- expiresAt: response.data.expiresAt,
926
- refreshExpiresAt: response.data.refreshExpiresAt
927
- };
928
- TokenStorage.saveTokens(tokens);
929
- this.log("Login successful, tokens saved");
930
- this.config.onLoginSuccess?.(tokens);
931
- return {
932
- success: true,
933
- tokens,
934
- data: response.data
935
- // Incluir datos del usuario
936
- };
937
- } catch (error) {
938
- this.log("Login error:", error);
939
- return {
940
- success: false,
941
- error: error instanceof Error ? error.message : "Unknown error"
942
- };
943
- }
944
- }
945
- /**
946
- * Logout con limpieza de tokens
947
- */
948
- async logout() {
949
- try {
950
- this.log("Logging out...");
951
- await import_crudify_browser2.default.logout();
952
- TokenStorage.clearTokens();
953
- this.log("Logout successful");
954
- this.config.onLogout?.();
955
- } catch (error) {
956
- this.log("Logout error:", error);
957
- TokenStorage.clearTokens();
958
- }
959
- }
960
- /**
961
- * Restaurar sesión desde storage
962
- */
963
- async restoreSession() {
964
- try {
965
- this.log("Attempting to restore session...");
966
- const savedTokens = TokenStorage.getTokens();
967
- if (!savedTokens) {
968
- this.log("No valid tokens found in storage");
969
- return false;
970
- }
971
- import_crudify_browser2.default.setTokens({
972
- accessToken: savedTokens.accessToken,
973
- refreshToken: savedTokens.refreshToken,
974
- expiresAt: savedTokens.expiresAt,
975
- refreshExpiresAt: savedTokens.refreshExpiresAt
976
- });
977
- try {
978
- const isValid = import_crudify_browser2.default.isLogin();
979
- if (!isValid) {
980
- this.log("Restored tokens are invalid, clearing storage");
981
- TokenStorage.clearTokens();
982
- return false;
983
- }
984
- } catch (validationError) {
985
- this.log("Token validation failed:", validationError);
986
- TokenStorage.clearTokens();
987
- return false;
988
- }
989
- this.log("Session restored successfully");
990
- this.config.onSessionRestored?.(savedTokens);
991
- return true;
992
- } catch (error) {
993
- this.log("Session restore error:", error);
994
- TokenStorage.clearTokens();
995
- return false;
996
- }
997
- }
998
- /**
999
- * Verificar si el usuario está autenticado
1000
- */
1001
- isAuthenticated() {
1002
- return import_crudify_browser2.default.isLogin() || TokenStorage.hasValidTokens();
1003
- }
1004
- /**
1005
- * Obtener información de tokens actuales
1006
- */
1007
- getTokenInfo() {
1008
- const crudifyTokens = import_crudify_browser2.default.getTokenData();
1009
- const storageInfo = TokenStorage.getExpirationInfo();
1010
- return {
1011
- isLoggedIn: this.isAuthenticated(),
1012
- crudifyTokens,
1013
- storageInfo,
1014
- hasValidTokens: TokenStorage.hasValidTokens()
1015
- };
1016
- }
1017
- /**
1018
- * Refrescar tokens manualmente
1019
- */
1020
- async refreshTokens() {
1021
- try {
1022
- this.log("Manually refreshing tokens...");
1023
- const response = await import_crudify_browser2.default.refreshAccessToken();
1024
- if (!response.success) {
1025
- this.log("Token refresh failed:", response.errors);
1026
- TokenStorage.clearTokens();
1027
- this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
1028
- this.config.onSessionExpired?.();
1029
- return false;
1030
- }
1031
- const newTokens = {
1032
- accessToken: response.data.token,
1033
- refreshToken: response.data.refreshToken,
1034
- expiresAt: response.data.expiresAt,
1035
- refreshExpiresAt: response.data.refreshExpiresAt
1036
- };
1037
- TokenStorage.saveTokens(newTokens);
1038
- this.log("Tokens refreshed and saved successfully");
1039
- return true;
1040
- } catch (error) {
1041
- this.log("Token refresh error:", error);
1042
- TokenStorage.clearTokens();
1043
- this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
1044
- this.config.onSessionExpired?.();
1045
- return false;
1046
- }
1047
- }
1048
- /**
1049
- * Configurar interceptor de respuesta para manejo automático de errores
1050
- */
1051
- setupResponseInterceptor() {
1052
- import_crudify_browser2.default.setResponseInterceptor(async (response) => {
1053
- const authError = this.detectAuthorizationError(response);
1054
- if (authError.isAuthError) {
1055
- console.warn("\u{1F6A8} SessionManager - Authorization error detected:", {
1056
- errorType: authError.errorType,
1057
- errorDetails: authError.errorDetails,
1058
- fullResponse: response
1059
- });
1060
- if (authError.isRefreshTokenInvalid || authError.isTokenRefreshFailed) {
1061
- this.log("Refresh token invalid or refresh already failed, clearing session");
1062
- TokenStorage.clearTokens();
1063
- this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
1064
- this.config.onSessionExpired?.();
1065
- return response;
1066
- }
1067
- if (TokenStorage.hasValidTokens() && !authError.isIrrecoverable) {
1068
- this.log("Auth error detected, attempting token refresh...");
1069
- const refreshSuccess = await this.refreshTokens();
1070
- if (!refreshSuccess) {
1071
- this.log("Token refresh failed, triggering session expired");
1072
- this.config.onSessionExpired?.();
1073
- }
1074
- } else {
1075
- this.log("Auth error with no valid tokens or irrecoverable error, triggering session expired");
1076
- TokenStorage.clearTokens();
1077
- this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
1078
- this.config.onSessionExpired?.();
1079
- }
1080
- }
1081
- return response;
1082
- });
1083
- this.log("Response interceptor configured");
1084
- }
1085
- /**
1086
- * Detectar errores de autorización en todos los formatos posibles
1087
- */
1088
- detectAuthorizationError(response) {
1089
- const result = {
1090
- isAuthError: false,
1091
- isRefreshTokenInvalid: false,
1092
- isTokenRefreshFailed: false,
1093
- isIrrecoverable: false,
1094
- errorType: "",
1095
- errorDetails: null
1096
- };
1097
- if (response.errors) {
1098
- if (Array.isArray(response.errors)) {
1099
- const hasAuthError = response.errors.some(
1100
- (error) => error.errorType === "Unauthorized" || error.message?.includes("Unauthorized") || error.message?.includes("Not Authorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED" || error.message?.includes("NOT_AUTHORIZED")
1101
- );
1102
- if (hasAuthError) {
1103
- result.isAuthError = true;
1104
- result.errorType = "GraphQL Array Format";
1105
- result.errorDetails = response.errors;
1106
- }
1107
- } else if (typeof response.errors === "object") {
1108
- const errorMessages = Object.values(response.errors).flat();
1109
- const hasAuthError = errorMessages.some(
1110
- (message) => typeof message === "string" && (message.includes("NOT_AUTHORIZED") || message.includes("TOKEN_REFRESH_FAILED") || message.includes("PLEASE_LOGIN") || message.includes("Unauthorized") || message.includes("UNAUTHENTICATED") || message.includes("Token"))
1111
- );
1112
- if (hasAuthError) {
1113
- result.isAuthError = true;
1114
- result.errorType = "GraphQL Object Format";
1115
- result.errorDetails = response.errors;
1116
- result.isTokenRefreshFailed = errorMessages.some(
1117
- (message) => typeof message === "string" && message.includes("TOKEN_REFRESH_FAILED")
1118
- );
1119
- }
1120
- }
1121
- }
1122
- if (!result.isAuthError && response.data?.response?.status === "UNAUTHORIZED") {
1123
- result.isAuthError = true;
1124
- result.errorType = "Status UNAUTHORIZED";
1125
- result.errorDetails = response.data.response;
1126
- result.isIrrecoverable = true;
1127
- }
1128
- if (!result.isAuthError && response.data?.response?.data) {
1129
- try {
1130
- const parsedData = JSON.parse(response.data.response.data);
1131
- if (parsedData.error === "REFRESH_TOKEN_INVALID" || parsedData.error === "TOKEN_EXPIRED") {
1132
- result.isAuthError = true;
1133
- result.errorType = "Parsed Data Format";
1134
- result.errorDetails = parsedData;
1135
- result.isRefreshTokenInvalid = true;
1136
- result.isIrrecoverable = true;
1137
- }
1138
- } catch {
1139
- }
1140
- }
1141
- if (!result.isAuthError && response.errorCode) {
1142
- const errorCode = response.errorCode;
1143
- const isAuthErrorCode = errorCode === "UNAUTHORIZED" || errorCode === "UNAUTHENTICATED" || errorCode === "TOKEN_EXPIRED";
1144
- if (isAuthErrorCode) {
1145
- result.isAuthError = true;
1146
- result.errorType = "Error Code Format";
1147
- result.errorDetails = { errorCode };
1148
- }
1149
- }
1150
- return result;
1151
- }
1152
- /**
1153
- * Limpiar sesión completamente
1154
- */
1155
- clearSession() {
1156
- TokenStorage.clearTokens();
1157
- import_crudify_browser2.default.logout();
1158
- this.log("Session cleared completely");
1159
- }
1160
- /**
1161
- * Obtener mensaje de sesión expirada traducido
1162
- */
1163
- getSessionExpiredMessage() {
1164
- if (this.config.translateFn) {
1165
- return translateErrorCode("SESSION_EXPIRED", {
1166
- translateFn: this.config.translateFn,
1167
- enableDebug: this.config.enableLogging
1168
- });
1169
- }
1170
- return "Tu sesi\xF3n ha expirado. Por favor, inicia sesi\xF3n nuevamente.";
1171
- }
1172
- // Métodos privados
1173
- log(message, ...args) {
1174
- if (this.config.enableLogging) {
1175
- console.log(`[SessionManager] ${message}`, ...args);
1176
- }
1177
- }
1178
- formatError(errors) {
1179
- if (!errors) return "Unknown error";
1180
- if (typeof errors === "string") return errors;
1181
- if (typeof errors === "object") {
1182
- const errorMessages = Object.values(errors).flat();
1183
- return errorMessages.join(", ");
1184
- }
1185
- return "Authentication failed";
1186
- }
1187
- };
1188
-
1189
- // src/hooks/useSession.ts
1190
- function useSession(options = {}) {
1191
- const [state, setState] = (0, import_react5.useState)({
1192
- isAuthenticated: false,
1193
- isLoading: true,
1194
- isInitialized: false,
1195
- tokens: null,
1196
- error: null
1197
- });
1198
- const sessionManager = SessionManager.getInstance();
1199
- const initialize = (0, import_react5.useCallback)(async () => {
1200
- try {
1201
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
1202
- const config = {
1203
- autoRestore: options.autoRestore ?? true,
1204
- enableLogging: options.enableLogging ?? false,
1205
- showNotification: options.showNotification,
1206
- translateFn: options.translateFn,
1207
- onSessionExpired: () => {
1208
- setState((prev) => ({
1209
- ...prev,
1210
- isAuthenticated: false,
1211
- tokens: null,
1212
- error: "Session expired"
1213
- }));
1214
- options.onSessionExpired?.();
1215
- },
1216
- onSessionRestored: (tokens) => {
1217
- setState((prev) => ({
1218
- ...prev,
1219
- isAuthenticated: true,
1220
- tokens,
1221
- error: null
1222
- }));
1223
- options.onSessionRestored?.(tokens);
1224
- },
1225
- onLoginSuccess: (tokens) => {
1226
- setState((prev) => ({
1227
- ...prev,
1228
- isAuthenticated: true,
1229
- tokens,
1230
- error: null
1231
- }));
1232
- },
1233
- onLogout: () => {
1234
- setState((prev) => ({
1235
- ...prev,
1236
- isAuthenticated: false,
1237
- tokens: null,
1238
- error: null
1239
- }));
1240
- }
1241
- };
1242
- await sessionManager.initialize(config);
1243
- sessionManager.setupResponseInterceptor();
1244
- const isAuth = sessionManager.isAuthenticated();
1245
- const tokenInfo = sessionManager.getTokenInfo();
1246
- setState((prev) => ({
1247
- ...prev,
1248
- isAuthenticated: isAuth,
1249
- isInitialized: true,
1250
- isLoading: false,
1251
- tokens: tokenInfo.crudifyTokens.accessToken ? {
1252
- accessToken: tokenInfo.crudifyTokens.accessToken,
1253
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
1254
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
1255
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
1256
- } : null
1257
- }));
1258
- } catch (error) {
1259
- const errorMessage = error instanceof Error ? error.message : "Initialization failed";
1260
- setState((prev) => ({
1261
- ...prev,
1262
- isLoading: false,
1263
- isInitialized: true,
1264
- error: errorMessage
1265
- }));
1266
- }
1267
- }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
1268
- const login = (0, import_react5.useCallback)(
1269
- async (email, password) => {
1270
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
1271
- try {
1272
- const result = await sessionManager.login(email, password);
1273
- if (result.success && result.tokens) {
1274
- setState((prev) => ({
1275
- ...prev,
1276
- isAuthenticated: true,
1277
- tokens: result.tokens,
1278
- isLoading: false,
1279
- error: null
1280
- }));
1281
- } else {
1282
- setState((prev) => ({
1283
- ...prev,
1284
- isAuthenticated: false,
1285
- tokens: null,
1286
- isLoading: false,
1287
- error: null
1288
- // No establecer error global para errores de login
1289
- }));
1290
- }
1291
- return result;
1292
- } catch (error) {
1293
- const errorMsg = error instanceof Error ? error.message : "Login failed";
1294
- const isCredentialError = errorMsg.includes("INVALID_CREDENTIALS") || errorMsg.includes("Invalid email") || errorMsg.includes("Invalid password") || errorMsg.includes("credentials");
1295
- setState((prev) => ({
1296
- ...prev,
1297
- isAuthenticated: false,
1298
- tokens: null,
1299
- isLoading: false,
1300
- error: isCredentialError ? null : errorMsg
1301
- // Solo errores del sistema van al estado global
1302
- }));
1303
- return {
1304
- success: false,
1305
- error: errorMsg
1306
- };
1307
- }
1308
- },
1309
- [sessionManager]
1310
- );
1311
- const logout = (0, import_react5.useCallback)(async () => {
1312
- setState((prev) => ({ ...prev, isLoading: true }));
1313
- try {
1314
- await sessionManager.logout();
1315
- setState((prev) => ({
1316
- ...prev,
1317
- isAuthenticated: false,
1318
- tokens: null,
1319
- isLoading: false,
1320
- error: null
1321
- }));
1322
- } catch (error) {
1323
- setState((prev) => ({
1324
- ...prev,
1325
- isAuthenticated: false,
1326
- tokens: null,
1327
- isLoading: false,
1328
- error: error instanceof Error ? error.message : "Logout error"
1329
- }));
1330
- }
1331
- }, [sessionManager]);
1332
- const refreshTokens = (0, import_react5.useCallback)(async () => {
1333
- try {
1334
- const success = await sessionManager.refreshTokens();
1335
- if (success) {
1336
- const tokenInfo = sessionManager.getTokenInfo();
1337
- setState((prev) => ({
1338
- ...prev,
1339
- tokens: tokenInfo.crudifyTokens.accessToken ? {
1340
- accessToken: tokenInfo.crudifyTokens.accessToken,
1341
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
1342
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
1343
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
1344
- } : null,
1345
- error: null
1346
- }));
1347
- } else {
1348
- setState((prev) => ({
1349
- ...prev,
1350
- isAuthenticated: false,
1351
- tokens: null,
1352
- error: "Token refresh failed"
1353
- }));
1354
- }
1355
- return success;
1356
- } catch (error) {
1357
- setState((prev) => ({
1358
- ...prev,
1359
- isAuthenticated: false,
1360
- tokens: null,
1361
- error: error instanceof Error ? error.message : "Token refresh failed"
1362
- }));
1363
- return false;
1364
- }
1365
- }, [sessionManager]);
1366
- const clearError = (0, import_react5.useCallback)(() => {
1367
- setState((prev) => ({ ...prev, error: null }));
1368
- }, []);
1369
- const getTokenInfo = (0, import_react5.useCallback)(() => {
1370
- return sessionManager.getTokenInfo();
1371
- }, [sessionManager]);
1372
- (0, import_react5.useEffect)(() => {
1373
- initialize();
1374
- }, [initialize]);
1375
- return {
1376
- // Estado
1377
- ...state,
1378
- // Acciones
1379
- login,
1380
- logout,
1381
- refreshTokens,
1382
- clearError,
1383
- getTokenInfo,
1384
- // Utilidades
1385
- isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
1386
- // 5 minutos
1387
- expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
1388
- refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
1389
- };
1390
- }
1391
-
1392
- // src/utils/jwtUtils.ts
1393
- var decodeJwtSafely = (token) => {
1394
- try {
1395
- const parts = token.split(".");
1396
- if (parts.length !== 3) {
1397
- console.warn("Invalid JWT format: token must have 3 parts");
1398
- return null;
1399
- }
1400
- const payload = parts[1];
1401
- const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
1402
- const decodedPayload = JSON.parse(atob(paddedPayload));
1403
- return decodedPayload;
1404
- } catch (error) {
1405
- console.warn("Failed to decode JWT token:", error);
1406
- return null;
1407
- }
1408
- };
1409
- var getCurrentUserEmail = () => {
1410
- try {
1411
- let token = null;
1412
- token = sessionStorage.getItem("authToken");
1413
- console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
1414
- if (!token) {
1415
- token = sessionStorage.getItem("token");
1416
- console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
1417
- }
1418
- if (!token) {
1419
- token = localStorage.getItem("authToken") || localStorage.getItem("token");
1420
- console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
1421
- }
1422
- if (!token) {
1423
- console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
1424
- return null;
1425
- }
1426
- const payload = decodeJwtSafely(token);
1427
- if (!payload) {
1428
- console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
1429
- return null;
1430
- }
1431
- const email = payload.email || payload["cognito:username"] || null;
1432
- console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
1433
- return email;
1434
- } catch (error) {
1435
- console.warn("Failed to get current user email:", error);
1436
- return null;
1437
- }
1438
- };
1439
- var isTokenExpired = (token) => {
1440
- try {
1441
- const payload = decodeJwtSafely(token);
1442
- if (!payload || !payload.exp) return true;
1443
- const currentTime = Math.floor(Date.now() / 1e3);
1444
- return payload.exp < currentTime;
1445
- } catch {
1446
- return true;
1447
- }
1448
- };
1449
-
1450
- // src/components/GlobalNotificationProvider.tsx
1451
- var import_react6 = require("react");
1452
- var import_material = require("@mui/material");
1453
- var import_uuid = require("uuid");
1454
- var import_dompurify = __toESM(require("dompurify"));
1455
- var import_jsx_runtime4 = require("react/jsx-runtime");
1456
- var GlobalNotificationContext = (0, import_react6.createContext)(null);
1457
- var sanitizeNotificationContent = (html) => {
1458
- return import_dompurify.default.sanitize(html, {
1459
- // Solo permitir tags seguros para notificaciones
1460
- ALLOWED_TAGS: ["b", "i", "em", "strong", "br", "span"],
1461
- ALLOWED_ATTR: ["class"],
1462
- // Remover scripts y eventos
1463
- FORBID_TAGS: ["script", "iframe", "object", "embed"],
1464
- FORBID_ATTR: ["onload", "onerror", "onclick", "onmouseover", "onfocus", "onblur"],
1465
- // Configuración adicional de seguridad
1466
- WHOLE_DOCUMENT: false,
1467
- RETURN_DOM: false,
1468
- RETURN_DOM_FRAGMENT: false,
1469
- RETURN_TRUSTED_TYPE: false
1470
- });
1471
- };
1472
- var GlobalNotificationProvider = ({
1473
- children,
1474
- maxNotifications = 5,
1475
- defaultAutoHideDuration = 6e3,
1476
- position = { vertical: "top", horizontal: "right" },
1477
- enabled = false,
1478
- // ✅ Por defecto DESACTIVADO
1479
- allowHtml = false
1480
- // Por defecto no permitir HTML
1481
- }) => {
1482
- const [notifications, setNotifications] = (0, import_react6.useState)([]);
1483
- const showNotification = (0, import_react6.useCallback)(
1484
- (message, severity = "info", options) => {
1485
- if (!enabled) {
1486
- return "";
1487
- }
1488
- if (!message || typeof message !== "string") {
1489
- console.warn("\u26A0\uFE0F GlobalNotificationProvider: Invalid message provided");
1490
- return "";
1491
- }
1492
- if (message.length > 1e3) {
1493
- console.warn("\u26A0\uFE0F GlobalNotificationProvider: Message too long, truncating");
1494
- message = message.substring(0, 1e3) + "...";
1495
- }
1496
- const id = (0, import_uuid.v4)();
1497
- const newNotification = {
1498
- id,
1499
- message,
1500
- severity,
1501
- autoHideDuration: options?.autoHideDuration ?? defaultAutoHideDuration,
1502
- persistent: options?.persistent ?? false,
1503
- allowHtml: options?.allowHtml ?? allowHtml
1504
- // Usar valor del provider por defecto
1505
- };
1506
- setNotifications((prev) => {
1507
- const updatedNotifications = prev.length >= maxNotifications ? prev.slice(-(maxNotifications - 1)) : prev;
1508
- return [...updatedNotifications, newNotification];
1509
- });
1510
- return id;
1511
- },
1512
- [maxNotifications, defaultAutoHideDuration, enabled, allowHtml]
1513
- );
1514
- const hideNotification = (0, import_react6.useCallback)((id) => {
1515
- setNotifications((prev) => prev.filter((notification) => notification.id !== id));
1516
- }, []);
1517
- const clearAllNotifications = (0, import_react6.useCallback)(() => {
1518
- setNotifications([]);
1519
- }, []);
1520
- const value = {
1521
- showNotification,
1522
- hideNotification,
1523
- clearAllNotifications
1524
- };
1525
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(GlobalNotificationContext.Provider, { value, children: [
1526
- children,
1527
- enabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1528
- import_material.Box,
1529
- {
1530
- sx: {
1531
- position: "fixed",
1532
- zIndex: 9999,
1533
- [position.vertical]: position.vertical === "top" ? 24 : 24,
1534
- [position.horizontal]: position.horizontal === "right" ? 24 : position.horizontal === "left" ? 24 : "50%",
1535
- ...position.horizontal === "center" && {
1536
- transform: "translateX(-50%)"
1537
- },
1538
- display: "flex",
1539
- flexDirection: position.vertical === "top" ? "column" : "column-reverse",
1540
- gap: 1,
1541
- maxWidth: "400px",
1542
- width: "auto"
1543
- },
1544
- children: notifications.map((notification) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NotificationItem, { notification, onClose: () => hideNotification(notification.id) }, notification.id))
1545
- }
1546
- ) })
1547
- ] });
1548
- };
1549
- var NotificationItem = ({ notification, onClose }) => {
1550
- const [open, setOpen] = (0, import_react6.useState)(true);
1551
- const handleClose = (0, import_react6.useCallback)(
1552
- (_event, reason) => {
1553
- if (reason === "clickaway") return;
1554
- setOpen(false);
1555
- setTimeout(onClose, 300);
1556
- },
1557
- [onClose]
1558
- );
1559
- (0, import_react6.useEffect)(() => {
1560
- if (!notification.persistent && notification.autoHideDuration) {
1561
- const timer = setTimeout(() => {
1562
- handleClose();
1563
- }, notification.autoHideDuration);
1564
- return () => clearTimeout(timer);
1565
- }
1566
- }, [notification.autoHideDuration, notification.persistent, handleClose]);
1567
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1568
- import_material.Snackbar,
1569
- {
1570
- open,
1571
- onClose: handleClose,
1572
- sx: {
1573
- position: "relative",
1574
- "& .MuiSnackbarContent-root": {
1575
- minWidth: "auto"
1576
- }
1577
- },
1578
- TransitionProps: {
1579
- enter: true,
1580
- exit: true
1581
- },
1582
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1583
- import_material.Alert,
1584
- {
1585
- variant: "filled",
1586
- severity: notification.severity,
1587
- onClose: handleClose,
1588
- sx: {
1589
- width: "100%",
1590
- minWidth: "280px",
1591
- maxWidth: "400px",
1592
- wordBreak: "break-word"
1593
- },
1594
- children: notification.allowHtml ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: sanitizeNotificationContent(notification.message) } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: notification.message })
1595
- }
1596
- )
1597
- }
1598
- );
1599
- };
1600
- var useGlobalNotification = () => {
1601
- const context = (0, import_react6.useContext)(GlobalNotificationContext);
1602
- if (!context) {
1603
- throw new Error("useGlobalNotification debe ser usado dentro de un GlobalNotificationProvider");
1604
- }
1605
- return context;
1606
- };
1607
-
1608
- // src/providers/SessionProvider.tsx
1609
- var import_jsx_runtime5 = require("react/jsx-runtime");
1610
- var SessionContext = (0, import_react7.createContext)(void 0);
1611
- function InnerSessionProvider({
1612
- children,
1613
- options = {},
1614
- config: propConfig,
1615
- showNotifications = false,
1616
- notificationOptions = {}
1617
- }) {
1618
- let showNotificationFn;
1619
- try {
1620
- const { showNotification } = useGlobalNotification();
1621
- showNotificationFn = showNotification;
1622
- } catch {
1623
- }
1624
- const enhancedOptions = import_react7.default.useMemo(
1625
- () => ({
1626
- ...options,
1627
- showNotification: showNotificationFn,
1628
- // TODO: Agregar translateFn cuando esté disponible
1629
- onSessionExpired: () => {
1630
- options.onSessionExpired?.();
1631
- }
1632
- }),
1633
- [options, showNotificationFn]
1634
- );
1635
- const sessionHook = useSession(enhancedOptions);
1636
- const resolvedConfig = (0, import_react7.useMemo)(() => {
1637
- let publicApiKey;
1638
- let env;
1639
- let appName;
1640
- let loginActions;
1641
- let logo;
1642
- let configSource = "unknown";
1643
- if (propConfig?.publicApiKey) {
1644
- publicApiKey = propConfig.publicApiKey;
1645
- configSource = "props";
1646
- }
1647
- if (propConfig?.env) {
1648
- env = propConfig.env;
1649
- }
1650
- if (propConfig?.appName) {
1651
- appName = propConfig.appName;
1652
- }
1653
- if (propConfig?.loginActions) {
1654
- loginActions = propConfig.loginActions;
1655
- }
1656
- if (propConfig?.logo) {
1657
- logo = propConfig.logo;
1658
- }
1659
- if (!publicApiKey) {
1660
- const cookieApiKey = getCookie("publicApiKey");
1661
- const cookieEnv = getCookie("environment");
1662
- const cookieAppName = getCookie("appName");
1663
- const cookieLoginActions = getCookie("loginActions");
1664
- const cookieLogo = getCookie("logo");
1665
- if (cookieApiKey) {
1666
- publicApiKey = cookieApiKey;
1667
- configSource = "cookies";
1668
- }
1669
- if (cookieEnv && ["dev", "stg", "prod"].includes(cookieEnv)) {
1670
- env = cookieEnv;
1671
- }
1672
- if (cookieAppName) {
1673
- appName = decodeURIComponent(cookieAppName);
1674
- }
1675
- if (cookieLoginActions) {
1676
- const decodedActions = decodeURIComponent(cookieLoginActions);
1677
- loginActions = decodedActions.split(",").map((s) => s.trim()).filter(Boolean);
1678
- }
1679
- if (cookieLogo) logo = decodeURIComponent(cookieLogo);
1680
- }
1681
- return {
1682
- publicApiKey,
1683
- env,
1684
- appName,
1685
- loginActions,
1686
- logo
1687
- };
1688
- }, [propConfig]);
1689
- const sessionData = (0, import_react7.useMemo)(() => {
1690
- if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
1691
- return null;
1692
- }
1693
- try {
1694
- const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
1695
- if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
1696
- const result = {
1697
- _id: decoded.sub,
1698
- email: decoded.email,
1699
- subscriberKey: decoded.subscriber
1700
- };
1701
- Object.keys(decoded).forEach((key) => {
1702
- if (!["sub", "email", "subscriber"].includes(key)) {
1703
- result[key] = decoded[key];
1704
- }
1705
- });
1706
- return result;
1707
- }
1708
- } catch (error) {
1709
- console.error("Error decoding JWT token for sessionData:", error);
1710
- }
1711
- return null;
1712
- }, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
1713
- const contextValue = {
1714
- ...sessionHook,
1715
- sessionData,
1716
- config: resolvedConfig
1717
- };
1718
- const notificationConfig = {
1719
- enabled: showNotifications,
1720
- maxNotifications: notificationOptions.maxNotifications || 5,
1721
- defaultAutoHideDuration: notificationOptions.defaultAutoHideDuration || 6e3,
1722
- position: notificationOptions.position || { vertical: "top", horizontal: "right" }
1723
- };
1724
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SessionContext.Provider, { value: contextValue, children });
1725
- }
1726
- function SessionProvider(props) {
1727
- const notificationConfig = {
1728
- enabled: props.showNotifications,
1729
- maxNotifications: props.notificationOptions?.maxNotifications || 5,
1730
- defaultAutoHideDuration: props.notificationOptions?.defaultAutoHideDuration || 6e3,
1731
- position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" },
1732
- allowHtml: props.notificationOptions?.allowHtml || false
1733
- // Pasar allowHtml desde notificationOptions
1734
- };
1735
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalNotificationProvider, { ...notificationConfig, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InnerSessionProvider, { ...props }) });
1736
- }
1737
- function useSessionContext() {
1738
- const context = (0, import_react7.useContext)(SessionContext);
1739
- if (context === void 0) {
1740
- throw new Error("useSessionContext must be used within a SessionProvider");
1741
- }
1742
- return context;
1743
- }
1744
- function ProtectedRoute({ children, fallback = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: "Please log in to access this content" }), redirectTo }) {
1745
- const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
1746
- if (!isInitialized || isLoading) {
1747
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: "Loading..." });
1748
- }
1749
- if (!isAuthenticated) {
1750
- if (redirectTo) {
1751
- redirectTo();
1752
- return null;
1753
- }
1754
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: fallback });
1755
- }
1756
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
1757
- }
1758
- function SessionDebugInfo() {
1759
- const session = useSessionContext();
1760
- if (!session.isInitialized) {
1761
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: "Session not initialized" });
1762
- }
1763
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1764
- "div",
1765
- {
1766
- style: {
1767
- padding: "10px",
1768
- margin: "10px",
1769
- border: "1px solid #ccc",
1770
- borderRadius: "4px",
1771
- fontSize: "12px",
1772
- fontFamily: "monospace"
1773
- },
1774
- children: [
1775
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Session Debug Info" }),
1776
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1777
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Authenticated:" }),
1778
- " ",
1779
- session.isAuthenticated ? "Yes" : "No"
1780
- ] }),
1781
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1782
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Loading:" }),
1783
- " ",
1784
- session.isLoading ? "Yes" : "No"
1785
- ] }),
1786
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1787
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Error:" }),
1788
- " ",
1789
- session.error || "None"
1790
- ] }),
1791
- session.tokens && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1792
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1793
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Access Token:" }),
1794
- " ",
1795
- session.tokens.accessToken.substring(0, 20),
1796
- "..."
1797
- ] }),
1798
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1799
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Refresh Token:" }),
1800
- " ",
1801
- session.tokens.refreshToken.substring(0, 20),
1802
- "..."
1803
- ] }),
1804
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1805
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Access Expires In:" }),
1806
- " ",
1807
- Math.round(session.expiresIn / 1e3 / 60),
1808
- " minutes"
1809
- ] }),
1810
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1811
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Refresh Expires In:" }),
1812
- " ",
1813
- Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
1814
- " hours"
1815
- ] }),
1816
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1817
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Expiring Soon:" }),
1818
- " ",
1819
- session.isExpiringSoon ? "Yes" : "No"
1820
- ] })
1821
- ] })
1822
- ]
1823
- }
1824
- );
1825
- }
1826
-
1827
- // src/components/CrudifyLogin/Forms/LoginForm.tsx
1828
- var import_react8 = require("react");
1829
- var import_material2 = require("@mui/material");
1830
-
1831
- // src/utils/errorHandler.ts
1832
- var ERROR_CODES = {
1833
- // Authentication Errors
1834
- INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
1835
- UNAUTHORIZED: "UNAUTHORIZED",
1836
- INVALID_API_KEY: "INVALID_API_KEY",
1837
- USER_NOT_FOUND: "USER_NOT_FOUND",
1838
- USER_NOT_ACTIVE: "USER_NOT_ACTIVE",
1839
- NO_PERMISSION: "NO_PERMISSION",
1840
- // Data Errors
1841
- ITEM_NOT_FOUND: "ITEM_NOT_FOUND",
1842
- NOT_FOUND: "NOT_FOUND",
1843
- IN_USE: "IN_USE",
1844
- // Validation Errors
1845
- FIELD_ERROR: "FIELD_ERROR",
1846
- BAD_REQUEST: "BAD_REQUEST",
1847
- INVALID_EMAIL: "INVALID_EMAIL",
1848
- INVALID_CODE: "INVALID_CODE",
1849
- // System Errors
1850
- INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR",
1851
- DATABASE_CONNECTION_ERROR: "DATABASE_CONNECTION_ERROR",
1852
- INVALID_CONFIGURATION: "INVALID_CONFIGURATION",
1853
- UNKNOWN_OPERATION: "UNKNOWN_OPERATION",
1854
- // Rate Limiting
1855
- TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
1856
- // Network Errors
1857
- NETWORK_ERROR: "NETWORK_ERROR",
1858
- TIMEOUT_ERROR: "TIMEOUT_ERROR"
1859
- };
1860
- var ERROR_SEVERITY_MAP = {
1861
- // Authentication - warning (user can fix)
1862
- [ERROR_CODES.INVALID_CREDENTIALS]: "warning",
1863
- [ERROR_CODES.UNAUTHORIZED]: "warning",
1864
- [ERROR_CODES.INVALID_API_KEY]: "error",
1865
- [ERROR_CODES.USER_NOT_FOUND]: "warning",
1866
- [ERROR_CODES.USER_NOT_ACTIVE]: "warning",
1867
- [ERROR_CODES.NO_PERMISSION]: "warning",
1868
- // Data - info (might be expected)
1869
- [ERROR_CODES.ITEM_NOT_FOUND]: "info",
1870
- [ERROR_CODES.NOT_FOUND]: "info",
1871
- [ERROR_CODES.IN_USE]: "warning",
1872
- // Validation - warning (user input issue)
1873
- [ERROR_CODES.FIELD_ERROR]: "warning",
1874
- [ERROR_CODES.BAD_REQUEST]: "warning",
1875
- [ERROR_CODES.INVALID_EMAIL]: "warning",
1876
- [ERROR_CODES.INVALID_CODE]: "warning",
1877
- // System - error (server issue)
1878
- [ERROR_CODES.INTERNAL_SERVER_ERROR]: "error",
1879
- [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "error",
1880
- [ERROR_CODES.INVALID_CONFIGURATION]: "error",
1881
- [ERROR_CODES.UNKNOWN_OPERATION]: "error",
1882
- // Rate limiting - warning with higher duration
1883
- [ERROR_CODES.TOO_MANY_REQUESTS]: "warning",
1884
- // Network - error
1885
- [ERROR_CODES.NETWORK_ERROR]: "error",
1886
- [ERROR_CODES.TIMEOUT_ERROR]: "error"
1887
- };
1888
- function parseApiError(response) {
1889
- const errors = [];
1890
- try {
1891
- const apiResponse = response;
1892
- if (apiResponse.data && typeof apiResponse.data === "object") {
1893
- const responseData = apiResponse.data;
1894
- if (responseData.response) {
1895
- const { status, fieldsWarning } = responseData.response;
1896
- if (fieldsWarning && typeof fieldsWarning === "object") {
1897
- Object.entries(fieldsWarning).forEach(([field, messages]) => {
1898
- if (Array.isArray(messages) && messages.length > 0) {
1899
- errors.push({
1900
- code: ERROR_CODES.FIELD_ERROR,
1901
- message: messages[0],
1902
- severity: "warning",
1903
- field
1904
- });
1905
- }
1906
- });
1907
- }
1908
- if (status && typeof status === "string") {
1909
- const errorCode = status;
1910
- if (ERROR_SEVERITY_MAP[errorCode]) {
1911
- errors.push({
1912
- code: errorCode,
1913
- message: getErrorMessage(errorCode),
1914
- severity: ERROR_SEVERITY_MAP[errorCode]
1915
- });
1916
- }
1917
- }
1918
- }
1919
- }
1920
- if (apiResponse.errors) {
1921
- if (typeof apiResponse.errors === "string") {
1922
- errors.push({
1923
- code: ERROR_CODES.BAD_REQUEST,
1924
- message: apiResponse.errors,
1925
- severity: "warning"
1926
- });
1927
- } else if (typeof apiResponse.errors === "object") {
1928
- const errorObj = apiResponse.errors;
1929
- Object.entries(errorObj).forEach(([field, messages]) => {
1930
- if (Array.isArray(messages) && messages.length > 0) {
1931
- if (field === "_error") {
1932
- messages.forEach((msg) => {
1933
- const errorCode = typeof msg === "string" && isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
1934
- errors.push({
1935
- code: errorCode,
1936
- message: typeof msg === "string" ? msg : getErrorMessage(errorCode),
1937
- severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
1938
- });
1939
- });
1940
- } else if (field === "_graphql") {
1941
- messages.forEach((msg) => {
1942
- if (typeof msg === "string") {
1943
- const errorCode = isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
1944
- errors.push({
1945
- code: errorCode,
1946
- message: getErrorMessage(errorCode),
1947
- severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
1948
- });
1949
- }
1950
- });
1951
- } else {
1952
- errors.push({
1953
- code: ERROR_CODES.FIELD_ERROR,
1954
- message: typeof messages[0] === "string" ? messages[0] : "Validation error",
1955
- severity: "warning",
1956
- field
1957
- });
1958
- }
1959
- }
1960
- });
1961
- }
1962
- }
1963
- if (errors.length === 0 && apiResponse.success === false) {
1964
- errors.push({
1965
- code: ERROR_CODES.BAD_REQUEST,
1966
- message: "Request failed",
1967
- severity: "warning"
1968
- });
1969
- }
1970
- } catch (error) {
1971
- errors.push({
1972
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1973
- message: "Failed to parse error response",
1974
- severity: "error",
1975
- details: { originalError: error }
1976
- });
1977
- }
1978
- return errors.length > 0 ? errors : [
1979
- {
1980
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1981
- message: "Unknown error occurred",
1982
- severity: "error"
1983
- }
1984
- ];
1985
- }
1986
- function parseTransactionError(response) {
1987
- try {
1988
- const transactionResponse = response;
1989
- if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
1990
- const errors = [];
1991
- transactionResponse.data.forEach((item, index) => {
1992
- if (item.response?.status === "TOO_MANY_REQUESTS") {
1993
- errors.push({
1994
- code: ERROR_CODES.TOO_MANY_REQUESTS,
1995
- message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
1996
- severity: "warning",
1997
- details: { transactionIndex: index }
1998
- });
1999
- } else if (!item.response || item.response.status !== "OK") {
2000
- errors.push({
2001
- code: ERROR_CODES.BAD_REQUEST,
2002
- message: "Transaction failed",
2003
- severity: "warning",
2004
- details: { transactionIndex: index, response: item.response }
2005
- });
2006
- }
2007
- });
2008
- return errors;
2009
- }
2010
- return parseApiError(response);
2011
- } catch (error) {
2012
- return [
2013
- {
2014
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
2015
- message: "Failed to parse transaction error",
2016
- severity: "error",
2017
- details: { originalError: error }
2018
- }
2019
- ];
2020
- }
2021
- }
2022
- function isValidErrorCode(code) {
2023
- return Object.values(ERROR_CODES).includes(code);
2024
- }
2025
- function getErrorMessage(code) {
2026
- const messages = {
2027
- [ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
2028
- [ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
2029
- [ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
2030
- [ERROR_CODES.USER_NOT_FOUND]: "User not found",
2031
- [ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
2032
- [ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
2033
- [ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
2034
- [ERROR_CODES.NOT_FOUND]: "Resource not found",
2035
- [ERROR_CODES.IN_USE]: "Resource is currently in use",
2036
- [ERROR_CODES.FIELD_ERROR]: "Validation error",
2037
- [ERROR_CODES.BAD_REQUEST]: "Invalid request",
2038
- [ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
2039
- [ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
2040
- [ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
2041
- [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
2042
- [ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
2043
- [ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
2044
- [ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
2045
- [ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
2046
- [ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
2047
- };
2048
- return messages[code] || "An unknown error occurred";
2049
- }
2050
- function parseJavaScriptError(error) {
2051
- if (error instanceof Error) {
2052
- if (error.name === "AbortError") {
2053
- return {
2054
- code: ERROR_CODES.TIMEOUT_ERROR,
2055
- message: "Request was cancelled",
2056
- severity: "info"
2057
- };
2058
- }
2059
- if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
2060
- return {
2061
- code: ERROR_CODES.NETWORK_ERROR,
2062
- message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
2063
- severity: "error"
2064
- };
2065
- }
2066
- return {
2067
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
2068
- message: error.message || "An unexpected error occurred",
2069
- severity: "error",
2070
- details: { originalError: error }
2071
- };
2072
- }
2073
- return {
2074
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
2075
- message: "An unknown error occurred",
2076
- severity: "error",
2077
- details: { originalError: error }
2078
- };
2079
- }
2080
- function handleCrudifyError(error) {
2081
- if (error instanceof Error) {
2082
- return [parseJavaScriptError(error)];
2083
- }
2084
- if (typeof error === "object" && error !== null) {
2085
- const response = error;
2086
- if (response.data && Array.isArray(response.data)) {
2087
- return parseTransactionError(error);
2088
- }
2089
- return parseApiError(error);
2090
- }
2091
- return [
2092
- {
2093
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
2094
- message: "An unknown error occurred",
2095
- severity: "error",
2096
- details: { originalError: error }
2097
- }
2098
- ];
2099
- }
2100
-
2101
- // src/components/CrudifyLogin/Forms/LoginForm.tsx
2102
- var import_jsx_runtime6 = require("react/jsx-runtime");
2103
- var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
2104
- const { crudify: crudify7 } = useCrudify();
2105
- const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
2106
- const { login: sessionLogin } = useSessionContext();
2107
- const translationContext = useTranslation();
2108
- const { t } = translationContext;
2109
- const i18n = translationContext.i18n;
2110
- const usernameInputRef = (0, import_react8.useRef)(null);
2111
- const errorTranslator = createErrorTranslator(t, {
2112
- currentLanguage: i18n?.language,
2113
- enableDebug: false
2114
- });
2115
- const getRedirectUrl = () => {
2116
- if (state.searchParams.redirect) {
2117
- try {
2118
- const decodedPath = decodeURIComponent(state.searchParams.redirect);
2119
- if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
2120
- return decodedPath;
2121
- }
2122
- } catch (error) {
2123
- }
2124
- }
2125
- return redirectUrl || "/";
2126
- };
2127
- (0, import_react8.useEffect)(() => {
2128
- const timer = setTimeout(() => {
2129
- if (usernameInputRef.current) usernameInputRef.current.focus();
2130
- }, 100);
2131
- return () => clearTimeout(timer);
2132
- }, []);
2133
- const translateError2 = (parsedError) => {
2134
- console.log("\u{1F50D} [LoginForm] Translating parsed error:", parsedError);
2135
- const result = errorTranslator.translateError({
2136
- code: parsedError.code,
2137
- message: parsedError.message,
2138
- field: parsedError.field
2139
- });
2140
- console.log("\u{1F50D} [LoginForm] Translation result:", result);
2141
- return result;
2142
- };
2143
- const handleLogin = async () => {
2144
- if (state.loading) return;
2145
- if (!state.formData.username.trim()) {
2146
- setFieldError("username", t("login.usernameRequired"));
2147
- return;
2148
- }
2149
- if (!state.formData.password.trim()) {
2150
- setFieldError("password", t("login.passwordRequired"));
2151
- return;
2152
- }
2153
- clearErrors();
2154
- setLoading(true);
2155
- try {
2156
- const response = await sessionLogin(state.formData.username, state.formData.password);
2157
- setLoading(false);
2158
- if (response.success) {
2159
- console.log("\u{1F510} LoginForm - Login successful via SessionProvider, calling onLoginSuccess");
2160
- const finalRedirectUrl = getRedirectUrl();
2161
- if (onLoginSuccess) {
2162
- onLoginSuccess(response.data, finalRedirectUrl);
2163
- }
2164
- } else {
2165
- const errorToHandle = response.rawResponse || response;
2166
- handleLoginError(errorToHandle);
2167
- }
2168
- } catch (error) {
2169
- setLoading(false);
2170
- const parsedErrors = handleCrudifyError(error);
2171
- const translatedErrors = parsedErrors.map(translateError2);
2172
- setFieldError("global", translatedErrors);
2173
- if (onError) {
2174
- onError(translatedErrors.join(", "));
2175
- }
2176
- }
2177
- };
2178
- const handleLoginError = (response) => {
2179
- const parsedErrors = handleCrudifyError(response);
2180
- parsedErrors.forEach((error) => {
2181
- if (error.field) {
2182
- setFieldError(error.field, translateError2(error));
2183
- } else {
2184
- const currentGlobalErrors = state.errors.global || [];
2185
- setFieldError("global", [...currentGlobalErrors, translateError2(error)]);
2186
- }
2187
- });
2188
- };
2189
- const handleSubmit = (e) => {
2190
- e.preventDefault();
2191
- handleLogin();
2192
- };
2193
- const handleKeyDown = (e) => {
2194
- if (e.key === "Enter" && !state.loading) {
2195
- e.preventDefault();
2196
- handleLogin();
2197
- }
2198
- };
2199
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2200
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2201
- import_material2.Box,
2202
- {
2203
- component: "form",
2204
- noValidate: true,
2205
- onSubmit: handleSubmit,
2206
- onKeyDown: handleKeyDown,
2207
- sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
2208
- children: [
2209
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
2210
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2211
- import_material2.Typography,
2212
- {
2213
- variant: "body2",
2214
- component: "label",
2215
- htmlFor: "email",
2216
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2217
- children: t("login.usernameOrEmailLabel")
2218
- }
2219
- ),
2220
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2221
- import_material2.TextField,
2222
- {
2223
- fullWidth: true,
2224
- id: "email",
2225
- name: "email",
2226
- type: "email",
2227
- value: state.formData.username,
2228
- disabled: state.loading,
2229
- onChange: (e) => updateFormData({ username: e.target.value }),
2230
- error: !!state.errors.username,
2231
- helperText: state.errors.username,
2232
- autoComplete: "email",
2233
- placeholder: t("login.usernameOrEmailPlaceholder"),
2234
- inputRef: usernameInputRef,
2235
- required: true
2236
- }
2237
- )
2238
- ] }),
2239
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
2240
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2241
- import_material2.Typography,
2242
- {
2243
- variant: "body2",
2244
- component: "label",
2245
- htmlFor: "password",
2246
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2247
- children: t("login.passwordLabel")
2248
- }
2249
- ),
2250
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2251
- import_material2.TextField,
2252
- {
2253
- fullWidth: true,
2254
- id: "password",
2255
- name: "password",
2256
- type: "password",
2257
- value: state.formData.password,
2258
- disabled: state.loading,
2259
- onChange: (e) => updateFormData({ password: e.target.value }),
2260
- error: !!state.errors.password,
2261
- helperText: state.errors.password,
2262
- autoComplete: "current-password",
2263
- placeholder: t("login.passwordPlaceholder"),
2264
- required: true
2265
- }
2266
- )
2267
- ] }),
2268
- state.config.loginActions?.includes("forgotPassword") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Box, { sx: { display: "flex", justifyContent: "flex-end", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2269
- import_material2.Link,
2270
- {
2271
- sx: { cursor: "pointer" },
2272
- onClick: () => {
2273
- onScreenChange?.("forgotPassword", state.searchParams);
2274
- },
2275
- variant: "body2",
2276
- color: "secondary",
2277
- children: t("login.forgotPasswordLink")
2278
- }
2279
- ) }),
2280
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Button, { disabled: state.loading, type: "submit", fullWidth: true, variant: "contained", color: "primary", sx: { mt: 1, mb: 2 }, children: state.loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.CircularProgress, { size: 20 }) : t("login.loginButton") })
2281
- ]
2282
- }
2283
- ),
2284
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Box, { children: state.errors.global && state.errors.global.length > 0 && state.errors.global.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: error }) }, index)) }),
2285
- state.config.loginActions?.includes("createUser") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Typography, { variant: "body2", align: "center", sx: { color: "text.secondary", mt: 3 }, children: [
2286
- t("login.noAccountPrompt"),
2287
- " ",
2288
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2289
- import_material2.Link,
2290
- {
2291
- sx: { cursor: "pointer" },
2292
- onClick: () => {
2293
- const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
2294
- const signupUrl = `/public/users/create${searchString}`;
2295
- onExternalNavigate?.(signupUrl);
2296
- },
2297
- fontWeight: "medium",
2298
- color: "secondary",
2299
- children: t("login.signUpLink")
2300
- }
2301
- )
2302
- ] })
2303
- ] });
2304
- };
2305
- var LoginForm_default = LoginForm;
2306
-
2307
- // src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
2308
- var import_react9 = require("react");
2309
- var import_material3 = require("@mui/material");
2310
- var import_jsx_runtime7 = require("react/jsx-runtime");
2311
- var ForgotPasswordForm = ({ onScreenChange, onError }) => {
2312
- const { crudify: crudify7 } = useCrudify();
2313
- const [email, setEmail] = (0, import_react9.useState)("");
2314
- const [loading, setLoading] = (0, import_react9.useState)(false);
2315
- const [errors, setErrors] = (0, import_react9.useState)([]);
2316
- const [helperTextEmail, setHelperTextEmail] = (0, import_react9.useState)(null);
2317
- const [emailSent, setEmailSent] = (0, import_react9.useState)(false);
2318
- const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react9.useState)(false);
2319
- const { t } = useTranslation();
2320
- const translateError2 = (parsedError) => {
2321
- const possibleKeys = [
2322
- `errors.auth.${parsedError.code}`,
2323
- `errors.data.${parsedError.code}`,
2324
- `errors.system.${parsedError.code}`,
2325
- `errors.${parsedError.code}`,
2326
- `forgotPassword.${parsedError.code.toLowerCase()}`
2327
- ];
2328
- for (const key of possibleKeys) {
2329
- const translated = t(key);
2330
- if (translated !== key) {
2331
- return translated;
2332
- }
2333
- }
2334
- return parsedError.message || t("error.unknown");
2335
- };
2336
- const validateEmail = (email2) => {
2337
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2338
- return emailRegex.test(email2);
2339
- };
2340
- const handleSubmit = async () => {
2341
- if (loading || !crudify7) return;
2342
- setErrors([]);
2343
- setHelperTextEmail(null);
2344
- if (!email) {
2345
- setHelperTextEmail(t("forgotPassword.emailRequired"));
2346
- return;
2347
- }
2348
- if (!validateEmail(email)) {
2349
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
2350
- return;
2351
- }
2352
- setLoading(true);
2353
- try {
2354
- const data = [{ operation: "requestPasswordReset", data: { email } }];
2355
- const response = await crudify7.transaction(data);
2356
- if (response.success) {
2357
- if (response.data && response.data.existingCodeValid) {
2358
- setCodeAlreadyExists(true);
2359
- } else {
2360
- setEmailSent(true);
2361
- }
2362
- } else {
2363
- const parsedErrors = handleCrudifyError(response);
2364
- const translatedErrors = parsedErrors.map(translateError2);
2365
- setErrors(translatedErrors);
2366
- }
2367
- } catch (error) {
2368
- const parsedErrors = handleCrudifyError(error);
2369
- const translatedErrors = parsedErrors.map(translateError2);
2370
- setErrors(translatedErrors);
2371
- if (onError) {
2372
- onError(translatedErrors.join(", "));
2373
- }
2374
- } finally {
2375
- setLoading(false);
2376
- }
2377
- };
2378
- const handleBack = () => {
2379
- onScreenChange?.("login");
2380
- };
2381
- const handleGoToCheckCode = () => {
2382
- if (emailSent || codeAlreadyExists) {
2383
- onScreenChange?.("checkCode", { email });
2384
- return;
2385
- }
2386
- if (!email) {
2387
- setHelperTextEmail(t("forgotPassword.emailRequired"));
2388
- return;
2389
- }
2390
- if (!validateEmail(email)) {
2391
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
2392
- return;
2393
- }
2394
- onScreenChange?.("checkCode", { email });
2395
- };
2396
- if (emailSent || codeAlreadyExists) {
2397
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2, textAlign: "center" }, children: [
2398
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
2399
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: codeAlreadyExists ? t("forgotPassword.codeAlreadyExistsMessage") : t("forgotPassword.emailSentMessage") }),
2400
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "body2", sx: { color: codeAlreadyExists ? "success.main" : "grey.600" }, children: codeAlreadyExists ? t("forgotPassword.checkEmailInstructions") : t("forgotPassword.checkEmailInstructions") })
2401
- ] }),
2402
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Button, { type: "button", onClick: handleGoToCheckCode, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: t("forgotPassword.enterCodeLink") }),
2403
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
2404
- ] }) });
2405
- }
2406
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2407
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2408
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
2409
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
2410
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
2411
- ] }),
2412
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
2413
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2414
- import_material3.Typography,
2415
- {
2416
- variant: "body2",
2417
- component: "label",
2418
- htmlFor: "email",
2419
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2420
- children: t("forgotPassword.emailLabel")
2421
- }
2422
- ),
2423
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2424
- import_material3.TextField,
2425
- {
2426
- fullWidth: true,
2427
- id: "email",
2428
- name: "email",
2429
- type: "email",
2430
- value: email,
2431
- disabled: loading,
2432
- onChange: (e) => setEmail(e.target.value),
2433
- error: !!helperTextEmail,
2434
- helperText: helperTextEmail,
2435
- autoComplete: "email",
2436
- placeholder: t("forgotPassword.emailPlaceholder"),
2437
- required: true
2438
- }
2439
- )
2440
- ] }),
2441
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Button, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.CircularProgress, { size: 20 }) : t("forgotPassword.sendCodeButton") }),
2442
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
2443
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
2444
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
2445
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Link, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
2446
- ] })
2447
- ] }),
2448
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
2449
- ] });
2450
- };
2451
- var ForgotPasswordForm_default = ForgotPasswordForm;
2452
-
2453
- // src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
2454
- var import_react10 = require("react");
2455
- var import_material4 = require("@mui/material");
2456
- var import_jsx_runtime8 = require("react/jsx-runtime");
2457
- var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
2458
- const { crudify: crudify7 } = useCrudify();
2459
- const [newPassword, setNewPassword] = (0, import_react10.useState)("");
2460
- const [confirmPassword, setConfirmPassword] = (0, import_react10.useState)("");
2461
- const [loading, setLoading] = (0, import_react10.useState)(false);
2462
- const [errors, setErrors] = (0, import_react10.useState)([]);
2463
- const [helperTextNewPassword, setHelperTextNewPassword] = (0, import_react10.useState)(null);
2464
- const [helperTextConfirmPassword, setHelperTextConfirmPassword] = (0, import_react10.useState)(null);
2465
- const [email, setEmail] = (0, import_react10.useState)("");
2466
- const [code, setCode] = (0, import_react10.useState)("");
2467
- const [fromCodeVerification, setFromCodeVerification] = (0, import_react10.useState)(false);
2468
- const [validatingCode, setValidatingCode] = (0, import_react10.useState)(true);
2469
- const [codeValidated, setCodeValidated] = (0, import_react10.useState)(false);
2470
- const [pendingValidation, setPendingValidation] = (0, import_react10.useState)(null);
2471
- const [isValidating, setIsValidating] = (0, import_react10.useState)(false);
2472
- const { t } = useTranslation();
2473
- const translateError2 = (parsedError) => {
2474
- const possibleKeys = [
2475
- `errors.auth.${parsedError.code}`,
2476
- `errors.data.${parsedError.code}`,
2477
- `errors.system.${parsedError.code}`,
2478
- `errors.${parsedError.code}`,
2479
- `resetPassword.${parsedError.code.toLowerCase()}`
2480
- ];
2481
- for (const key of possibleKeys) {
2482
- const translated = t(key);
2483
- if (translated !== key) {
2484
- return translated;
2485
- }
2486
- }
2487
- return parsedError.message || t("error.unknown");
2488
- };
2489
- const getParam = (key) => {
2490
- if (!searchParams) return null;
2491
- if (searchParams instanceof URLSearchParams) {
2492
- return searchParams.get(key);
2493
- }
2494
- return searchParams[key] || null;
2495
- };
2496
- (0, import_react10.useEffect)(() => {
2497
- if (!searchParams) {
2498
- return;
2499
- }
2500
- if (searchParams) {
2501
- const fromCodeVerificationParam = getParam("fromCodeVerification");
2502
- const emailParam = getParam("email");
2503
- const codeParam = getParam("code");
2504
- if (fromCodeVerificationParam === "true" && emailParam && codeParam) {
2505
- setEmail(emailParam);
2506
- setCode(codeParam);
2507
- setFromCodeVerification(true);
2508
- setCodeValidated(true);
2509
- setValidatingCode(false);
2510
- return;
2511
- }
2512
- const linkParam = getParam("link");
2513
- if (linkParam) {
2514
- try {
2515
- const decodedLink = decodeURIComponent(linkParam);
2516
- const [linkCode, linkEmail] = decodedLink.split("/");
2517
- if (linkCode && linkEmail && linkCode.length === 6) {
2518
- setCode(linkCode);
2519
- setEmail(linkEmail);
2520
- setFromCodeVerification(false);
2521
- setPendingValidation({ email: linkEmail, code: linkCode });
2522
- return;
2523
- }
2524
- } catch (error) {
2525
- }
2526
- }
2527
- if (emailParam && codeParam) {
2528
- setEmail(emailParam);
2529
- setCode(codeParam);
2530
- setFromCodeVerification(false);
2531
- setPendingValidation({ email: emailParam, code: codeParam });
2532
- return;
2533
- }
2534
- }
2535
- setErrors([t("resetPassword.invalidCode")]);
2536
- setValidatingCode(false);
2537
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2538
- }, [searchParams, crudify7, t, onScreenChange]);
2539
- (0, import_react10.useEffect)(() => {
2540
- if (crudify7 && pendingValidation && !isValidating) {
2541
- setIsValidating(true);
2542
- const validateCode = async (emailToValidate, codeToValidate) => {
2543
- try {
2544
- const data = [
2545
- {
2546
- operation: "validatePasswordResetCode",
2547
- data: { email: emailToValidate, codePassword: codeToValidate }
2548
- }
2549
- ];
2550
- const response = await crudify7.transaction(data);
2551
- if (response.data && Array.isArray(response.data)) {
2552
- const validationResult = response.data[0];
2553
- if (validationResult && validationResult.response && validationResult.response.status === "OK") {
2554
- setCodeValidated(true);
2555
- return;
2556
- }
2557
- }
2558
- if (response.success) {
2559
- setCodeValidated(true);
2560
- } else {
2561
- const parsedErrors = handleCrudifyError(response);
2562
- const translatedErrors = parsedErrors.map(translateError2);
2563
- setErrors(translatedErrors);
2564
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2565
- }
2566
- } catch (error) {
2567
- const parsedErrors = handleCrudifyError(error);
2568
- const translatedErrors = parsedErrors.map(translateError2);
2569
- setErrors(translatedErrors);
2570
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2571
- } finally {
2572
- setValidatingCode(false);
2573
- setPendingValidation(null);
2574
- setIsValidating(false);
2575
- }
2576
- };
2577
- validateCode(pendingValidation.email, pendingValidation.code);
2578
- }
2579
- }, [crudify7, pendingValidation, t, onScreenChange]);
2580
- const validatePassword = (password) => {
2581
- if (password.length < 8) {
2582
- return t("resetPassword.passwordTooShort");
2583
- }
2584
- return null;
2585
- };
2586
- const handleSubmit = async () => {
2587
- if (loading || !crudify7) return;
2588
- setErrors([]);
2589
- setHelperTextNewPassword(null);
2590
- setHelperTextConfirmPassword(null);
2591
- let hasErrors = false;
2592
- if (!newPassword) {
2593
- setHelperTextNewPassword(t("resetPassword.newPasswordRequired"));
2594
- hasErrors = true;
2595
- } else {
2596
- const passwordError = validatePassword(newPassword);
2597
- if (passwordError) {
2598
- setHelperTextNewPassword(passwordError);
2599
- hasErrors = true;
2600
- }
2601
- }
2602
- if (!confirmPassword) {
2603
- setHelperTextConfirmPassword(t("resetPassword.confirmPasswordRequired"));
2604
- hasErrors = true;
2605
- } else if (newPassword !== confirmPassword) {
2606
- setHelperTextConfirmPassword(t("resetPassword.passwordsDoNotMatch"));
2607
- hasErrors = true;
2608
- }
2609
- if (hasErrors) return;
2610
- setLoading(true);
2611
- try {
2612
- const data = [
2613
- {
2614
- operation: "validateAndResetPassword",
2615
- data: { email, codePassword: code, newPassword }
2616
- }
2617
- ];
2618
- const response = await crudify7.transaction(data);
2619
- if (response.success) {
2620
- setErrors([]);
2621
- setTimeout(() => {
2622
- onResetSuccess?.();
2623
- }, 1e3);
2624
- } else {
2625
- const parsedErrors = handleCrudifyError(response);
2626
- const translatedErrors = parsedErrors.map(translateError2);
2627
- setErrors(translatedErrors);
2628
- }
2629
- } catch (error) {
2630
- const parsedErrors = handleCrudifyError(error);
2631
- const translatedErrors = parsedErrors.map(translateError2);
2632
- setErrors(translatedErrors);
2633
- if (onError) {
2634
- onError(translatedErrors.join(", "));
2635
- }
2636
- }
2637
- setLoading(false);
2638
- };
2639
- const handleBack = () => {
2640
- if (fromCodeVerification) {
2641
- onScreenChange?.("checkCode", { email });
2642
- } else {
2643
- onScreenChange?.("forgotPassword");
2644
- }
2645
- };
2646
- if (validatingCode) {
2647
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "300px" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.CircularProgress, {}) });
2648
- }
2649
- if (!codeValidated) {
2650
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) });
2651
- }
2652
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2653
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2654
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 2 }, children: [
2655
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
2656
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
2657
- ] }),
2658
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
2659
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2660
- import_material4.Typography,
2661
- {
2662
- variant: "body2",
2663
- component: "label",
2664
- htmlFor: "newPassword",
2665
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2666
- children: t("resetPassword.newPasswordLabel")
2667
- }
2668
- ),
2669
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2670
- import_material4.TextField,
2671
- {
2672
- fullWidth: true,
2673
- id: "newPassword",
2674
- name: "newPassword",
2675
- type: "password",
2676
- value: newPassword,
2677
- disabled: loading,
2678
- onChange: (e) => setNewPassword(e.target.value),
2679
- error: !!helperTextNewPassword,
2680
- helperText: helperTextNewPassword,
2681
- autoComplete: "new-password",
2682
- placeholder: t("resetPassword.newPasswordPlaceholder"),
2683
- required: true
2684
- }
2685
- )
2686
- ] }),
2687
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
2688
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2689
- import_material4.Typography,
2690
- {
2691
- variant: "body2",
2692
- component: "label",
2693
- htmlFor: "confirmPassword",
2694
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2695
- children: t("resetPassword.confirmPasswordLabel")
2696
- }
2697
- ),
2698
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2699
- import_material4.TextField,
2700
- {
2701
- fullWidth: true,
2702
- id: "confirmPassword",
2703
- name: "confirmPassword",
2704
- type: "password",
2705
- value: confirmPassword,
2706
- disabled: loading,
2707
- onChange: (e) => setConfirmPassword(e.target.value),
2708
- error: !!helperTextConfirmPassword,
2709
- helperText: helperTextConfirmPassword,
2710
- autoComplete: "new-password",
2711
- placeholder: t("resetPassword.confirmPasswordPlaceholder"),
2712
- required: true
2713
- }
2714
- )
2715
- ] }),
2716
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Button, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.CircularProgress, { size: 20 }) : t("resetPassword.resetPasswordButton") }),
2717
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
2718
- ] }),
2719
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
2720
- ] });
2721
- };
2722
- var ResetPasswordForm_default = ResetPasswordForm;
2723
-
2724
- // src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
2725
- var import_react11 = require("react");
2726
- var import_material5 = require("@mui/material");
2727
- var import_jsx_runtime9 = require("react/jsx-runtime");
2728
- var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
2729
- const { crudify: crudify7 } = useCrudify();
2730
- const [code, setCode] = (0, import_react11.useState)("");
2731
- const [loading, setLoading] = (0, import_react11.useState)(false);
2732
- const [errors, setErrors] = (0, import_react11.useState)([]);
2733
- const [helperTextCode, setHelperTextCode] = (0, import_react11.useState)(null);
2734
- const [email, setEmail] = (0, import_react11.useState)("");
2735
- const { t } = useTranslation();
2736
- const getParam = (key) => {
2737
- if (!searchParams) return null;
2738
- if (searchParams instanceof URLSearchParams) {
2739
- return searchParams.get(key);
2740
- }
2741
- return searchParams[key] || null;
2742
- };
2743
- const translateError2 = (parsedError) => {
2744
- const possibleKeys = [
2745
- `errors.auth.${parsedError.code}`,
2746
- `errors.data.${parsedError.code}`,
2747
- `errors.system.${parsedError.code}`,
2748
- `errors.${parsedError.code}`,
2749
- `checkCode.${parsedError.code.toLowerCase()}`
2750
- ];
2751
- for (const key of possibleKeys) {
2752
- const translated = t(key);
2753
- if (translated !== key) {
2754
- return translated;
2755
- }
2756
- }
2757
- return parsedError.message || t("error.unknown");
2758
- };
2759
- (0, import_react11.useEffect)(() => {
2760
- const emailParam = getParam("email");
2761
- if (emailParam) {
2762
- setEmail(emailParam);
2763
- } else {
2764
- onScreenChange?.("forgotPassword");
2765
- }
2766
- }, [searchParams, onScreenChange]);
2767
- const handleSubmit = async () => {
2768
- if (loading || !crudify7) return;
2769
- setErrors([]);
2770
- setHelperTextCode(null);
2771
- if (!code) {
2772
- setHelperTextCode(t("checkCode.codeRequired"));
2773
- return;
2774
- }
2775
- if (code.length !== 6) {
2776
- setHelperTextCode(t("checkCode.codeRequired"));
2777
- return;
2778
- }
2779
- setLoading(true);
2780
- try {
2781
- const data = [
2782
- {
2783
- operation: "validatePasswordResetCode",
2784
- data: { email, codePassword: code }
2785
- }
2786
- ];
2787
- const response = await crudify7.transaction(data);
2788
- if (response.success) {
2789
- onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
2790
- } else {
2791
- const parsedErrors = handleCrudifyError(response);
2792
- const translatedErrors = parsedErrors.map(translateError2);
2793
- setErrors(translatedErrors);
2794
- setLoading(false);
2795
- }
2796
- } catch (error) {
2797
- const parsedErrors = handleCrudifyError(error);
2798
- const translatedErrors = parsedErrors.map(translateError2);
2799
- setErrors(translatedErrors);
2800
- setLoading(false);
2801
- if (onError) {
2802
- onError(translatedErrors.join(", "));
2803
- }
2804
- }
2805
- };
2806
- const handleBack = () => {
2807
- onScreenChange?.("forgotPassword");
2808
- };
2809
- const handleCodeChange = (event) => {
2810
- const value = event.target.value.replace(/\D/g, "").slice(0, 6);
2811
- setCode(value);
2812
- };
2813
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2814
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material5.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2815
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material5.Box, { sx: { mb: 2 }, children: [
2816
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
2817
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
2818
- ] }),
2819
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material5.Box, { sx: { mb: 1 }, children: [
2820
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2821
- import_material5.Typography,
2822
- {
2823
- variant: "body2",
2824
- component: "label",
2825
- htmlFor: "code",
2826
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2827
- children: t("checkCode.codeLabel")
2828
- }
2829
- ),
2830
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2831
- import_material5.TextField,
2832
- {
2833
- fullWidth: true,
2834
- id: "code",
2835
- name: "code",
2836
- type: "text",
2837
- value: code,
2838
- disabled: loading,
2839
- onChange: handleCodeChange,
2840
- error: !!helperTextCode,
2841
- helperText: helperTextCode,
2842
- placeholder: t("checkCode.codePlaceholder"),
2843
- inputProps: {
2844
- maxLength: 6,
2845
- style: { textAlign: "center", fontSize: "1.5rem", letterSpacing: "0.4rem" }
2846
- },
2847
- required: true
2848
- }
2849
- )
2850
- ] }),
2851
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2852
- import_material5.Button,
2853
- {
2854
- disabled: loading || code.length !== 6,
2855
- type: "button",
2856
- onClick: handleSubmit,
2857
- fullWidth: true,
2858
- variant: "contained",
2859
- color: "primary",
2860
- sx: { mt: 2, mb: 2 },
2861
- children: loading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.CircularProgress, { size: 20 }) : t("checkCode.verifyButton")
2862
- }
2863
- ),
2864
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
2865
- ] }),
2866
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Alert, { sx: { mt: 2 }, severity: "error", children: error }, index)) })
2867
- ] });
2868
- };
2869
- var CheckCodeForm_default = CheckCodeForm;
2870
-
2871
- // src/components/CrudifyLogin/components/CrudifyInitializer.tsx
2872
- var import_material6 = require("@mui/material");
2873
- var import_jsx_runtime10 = require("react/jsx-runtime");
2874
- var CrudifyInitializer = ({ children, fallback }) => {
2875
- const { isLoading, error, isInitialized } = useCrudify();
2876
- const { t } = useTranslation();
2877
- if (isLoading) {
2878
- return fallback || /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2879
- import_material6.Box,
2880
- {
2881
- sx: {
2882
- display: "flex",
2883
- flexDirection: "column",
2884
- alignItems: "center",
2885
- justifyContent: "center",
2886
- minHeight: "200px",
2887
- gap: 2
2888
- },
2889
- children: [
2890
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.CircularProgress, {}),
2891
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.Typography, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
2892
- ]
2893
- }
2894
- );
2895
- }
2896
- if (error) {
2897
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.Alert, { severity: "error", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material6.Typography, { variant: "body2", children: [
2898
- t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
2899
- ":",
2900
- " ",
2901
- error
2902
- ] }) });
2903
- }
2904
- if (!isInitialized) {
2905
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.Alert, { severity: "warning", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.Typography, { variant: "body2", children: t("login.notInitialized") !== "login.notInitialized" ? t("login.notInitialized") : "System not initialized" }) });
2906
- }
2907
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children });
2908
- };
2909
-
2910
- // src/components/CrudifyLogin/index.tsx
2911
- var import_jsx_runtime11 = require("react/jsx-runtime");
2912
- var CrudifyLoginInternal = ({
2913
- onScreenChange,
2914
- onExternalNavigate,
2915
- onLoginSuccess,
2916
- onError,
2917
- redirectUrl = "/"
2918
- }) => {
2919
- const { t } = useTranslation();
2920
- const { state, setScreen } = useLoginState();
2921
- const { config } = useSessionContext();
2922
- const { showNotification } = useGlobalNotification();
2923
- const handleScreenChange = (screen2, params) => {
2924
- let finalParams = params;
2925
- if (screen2 === "login") {
2926
- finalParams = {};
2927
- } else if (screen2 === "forgotPassword" && !params) {
2928
- finalParams = {};
2929
- }
2930
- setScreen(screen2, finalParams);
2931
- onScreenChange?.(screen2, finalParams);
2932
- };
2933
- const renderCurrentForm = () => {
2934
- const commonProps = {
2935
- onScreenChange: handleScreenChange,
2936
- onExternalNavigate,
2937
- onError,
2938
- redirectUrl
2939
- };
2940
- switch (state.currentScreen) {
2941
- case "forgotPassword":
2942
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ForgotPasswordForm_default, { ...commonProps });
2943
- case "checkCode":
2944
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CheckCodeForm_default, { ...commonProps, searchParams: state.searchParams });
2945
- case "resetPassword":
2946
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2947
- ResetPasswordForm_default,
2948
- {
2949
- ...commonProps,
2950
- searchParams: state.searchParams,
2951
- onResetSuccess: () => {
2952
- const message = t("resetPassword.successMessage");
2953
- showNotification(message, "success");
2954
- handleScreenChange("login");
2955
- }
2956
- }
2957
- );
2958
- default:
2959
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LoginForm_default, { ...commonProps, onLoginSuccess });
2960
- }
2961
- };
2962
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(CrudifyInitializer, { children: [
2963
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Box, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2964
- "img",
2965
- {
2966
- src: config.logo || "/nocios-default.png",
2967
- alt: t("login.logoAlt"),
2968
- style: { width: "100%", maxWidth: "150px", height: "auto" },
2969
- onError: (e) => {
2970
- const target = e.target;
2971
- target.src = "/nocios-default.png";
2972
- }
2973
- }
2974
- ) }),
2975
- !config.logo && config.appName && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "h6", component: "h1", sx: { textAlign: "center", mb: 2 }, children: config.appName }),
2976
- renderCurrentForm()
2977
- ] });
2978
- };
2979
- var CrudifyLogin = ({
2980
- translations,
2981
- translationsUrl,
2982
- language = "en",
2983
- initialScreen = "login",
2984
- autoReadFromCookies = true,
2985
- ...props
2986
- }) => {
2987
- const { config } = useSessionContext();
2988
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(I18nProvider, { translations, translationsUrl, language, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CrudifyProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LoginStateProvider, { config, initialScreen, autoReadFromCookies, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CrudifyLoginInternal, { ...props }) }) }) });
2989
- };
2990
- var CrudifyLogin_default = CrudifyLogin;
2991
-
2992
- // src/components/UserProfile/UserProfileDisplay.tsx
2993
- var import_material8 = require("@mui/material");
2994
- var import_icons_material = require("@mui/icons-material");
2995
-
2996
- // src/hooks/useUserProfile.ts
2997
- var import_react12 = require("react");
2998
- var import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
2999
- var useUserProfile = (options = {}) => {
3000
- const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
3001
- const [userProfile, setUserProfile] = (0, import_react12.useState)(null);
3002
- const [loading, setLoading] = (0, import_react12.useState)(false);
3003
- const [error, setError] = (0, import_react12.useState)(null);
3004
- const [extendedData, setExtendedData] = (0, import_react12.useState)({});
3005
- const abortControllerRef = (0, import_react12.useRef)(null);
3006
- const mountedRef = (0, import_react12.useRef)(true);
3007
- const requestIdRef = (0, import_react12.useRef)(0);
3008
- const retryCountRef = (0, import_react12.useRef)(0);
3009
- const clearProfile = (0, import_react12.useCallback)(() => {
3010
- setUserProfile(null);
3011
- setError(null);
3012
- setLoading(false);
3013
- setExtendedData({});
3014
- }, []);
3015
- const refreshProfile = (0, import_react12.useCallback)(async () => {
3016
- const userEmail = getCurrentUserEmail();
3017
- if (!userEmail) {
3018
- if (mountedRef.current) {
3019
- setError("No user email available");
3020
- setLoading(false);
3021
- }
3022
- return;
3023
- }
3024
- if (abortControllerRef.current) {
3025
- abortControllerRef.current.abort();
3026
- }
3027
- const abortController = new AbortController();
3028
- abortControllerRef.current = abortController;
3029
- const currentRequestId = ++requestIdRef.current;
3030
- try {
3031
- if (mountedRef.current) {
3032
- setLoading(true);
3033
- setError(null);
3034
- }
3035
- const response = await import_crudify_browser3.default.readItems("users", {
3036
- filter: { email: userEmail },
3037
- pagination: { limit: 1 }
3038
- });
3039
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
3040
- if (response.success && response.data && response.data.length > 0) {
3041
- const userData = response.data[0];
3042
- setUserProfile(userData);
3043
- const additionalData = {
3044
- fullProfile: userData,
3045
- totalFields: Object.keys(userData).length,
3046
- displayData: {
3047
- id: userData.id,
3048
- email: userData.email,
3049
- username: userData.username,
3050
- firstName: userData.firstName,
3051
- lastName: userData.lastName,
3052
- fullName: userData.fullName || `${userData.firstName || ""} ${userData.lastName || ""}`.trim(),
3053
- role: userData.role,
3054
- permissions: userData.permissions || [],
3055
- isActive: userData.isActive,
3056
- lastLogin: userData.lastLogin,
3057
- createdAt: userData.createdAt,
3058
- updatedAt: userData.updatedAt,
3059
- // Include any custom fields
3060
- ...Object.keys(userData).filter(
3061
- (key) => ![
3062
- "id",
3063
- "email",
3064
- "username",
3065
- "firstName",
3066
- "lastName",
3067
- "fullName",
3068
- "role",
3069
- "permissions",
3070
- "isActive",
3071
- "lastLogin",
3072
- "createdAt",
3073
- "updatedAt"
3074
- ].includes(key)
3075
- ).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
3076
- }
3077
- };
3078
- setExtendedData(additionalData);
3079
- setError(null);
3080
- retryCountRef.current = 0;
3081
- } else {
3082
- setError("User profile not found");
3083
- setUserProfile(null);
3084
- setExtendedData({});
3085
- }
3086
- }
3087
- } catch (err) {
3088
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
3089
- const error2 = err;
3090
- if (error2.name === "AbortError") {
3091
- return;
3092
- }
3093
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
3094
- if (shouldRetry) {
3095
- retryCountRef.current++;
3096
- setTimeout(() => {
3097
- if (mountedRef.current) {
3098
- refreshProfile();
3099
- }
3100
- }, 1e3 * retryCountRef.current);
3101
- } else {
3102
- setError("Failed to load user profile");
3103
- setUserProfile(null);
3104
- setExtendedData({});
3105
- }
3106
- }
3107
- } finally {
3108
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
3109
- setLoading(false);
3110
- }
3111
- if (abortControllerRef.current === abortController) {
3112
- abortControllerRef.current = null;
3113
- }
3114
- }
3115
- }, [retryOnError, maxRetries]);
3116
- (0, import_react12.useEffect)(() => {
3117
- if (autoFetch) {
3118
- refreshProfile();
3119
- }
3120
- }, [autoFetch, refreshProfile]);
3121
- (0, import_react12.useEffect)(() => {
3122
- mountedRef.current = true;
3123
- return () => {
3124
- mountedRef.current = false;
3125
- if (abortControllerRef.current) {
3126
- abortControllerRef.current.abort();
3127
- abortControllerRef.current = null;
3128
- }
3129
- };
3130
- }, []);
3131
- return {
3132
- userProfile,
3133
- loading,
3134
- error,
3135
- extendedData,
3136
- refreshProfile,
3137
- clearProfile
3138
- };
3139
- };
3140
-
3141
- // src/components/UserProfile/UserProfileDisplay.tsx
3142
- var import_react13 = require("react");
3143
- var import_jsx_runtime12 = require("react/jsx-runtime");
3144
- var UserProfileDisplay = ({
3145
- showExtendedData = true,
3146
- showProfileCard = true,
3147
- autoRefresh = true
3148
- }) => {
3149
- const { userProfile, loading, error, extendedData, refreshProfile } = useUserProfile({
3150
- autoFetch: autoRefresh,
3151
- retryOnError: true,
3152
- maxRetries: 3
3153
- });
3154
- const [showAllFields, setShowAllFields] = (0, import_react13.useState)(false);
3155
- if (loading) {
3156
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", justifyContent: "center", alignItems: "center", p: 3, children: [
3157
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.CircularProgress, {}),
3158
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", sx: { ml: 2 }, children: "Cargando perfil de usuario..." })
3159
- ] });
3160
- }
3161
- if (error) {
3162
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3163
- import_material8.Alert,
3164
- {
3165
- severity: "error",
3166
- action: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.IconButton, { color: "inherit", size: "small", onClick: refreshProfile, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "caption", children: "Reintentar" }) }),
3167
- children: [
3168
- "Error al cargar el perfil: ",
3169
- error
3170
- ]
3171
- }
3172
- );
3173
- }
3174
- if (!userProfile) {
3175
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Alert, { severity: "warning", children: "No se encontr\xF3 informaci\xF3n del usuario" });
3176
- }
3177
- const displayData = extendedData?.displayData || {};
3178
- const totalFields = extendedData?.totalFields || 0;
3179
- const formatDate = (dateString) => {
3180
- if (!dateString) return "No disponible";
3181
- try {
3182
- return new Date(dateString).toLocaleString("es-ES", {
3183
- year: "numeric",
3184
- month: "short",
3185
- day: "numeric",
3186
- hour: "2-digit",
3187
- minute: "2-digit"
3188
- });
3189
- } catch {
3190
- return dateString;
3191
- }
3192
- };
3193
- const renderFieldValue = (key, value) => {
3194
- if (value === null || value === void 0) return "No disponible";
3195
- if (typeof value === "boolean") return value ? "S\xED" : "No";
3196
- if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "Ninguno";
3197
- if (typeof value === "object") return JSON.stringify(value, null, 2);
3198
- return String(value);
3199
- };
3200
- const basicFields = [
3201
- { key: "id", label: "ID", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Badge, {}) },
3202
- { key: "email", label: "Email", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Email, {}) },
3203
- { key: "username", label: "Usuario", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Person, {}) },
3204
- { key: "fullName", label: "Nombre completo", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.AccountCircle, {}) },
3205
- { key: "role", label: "Rol", icon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Security, {}) }
3206
- ];
3207
- const extendedFields = [
3208
- { key: "firstName", label: "Nombre" },
3209
- { key: "lastName", label: "Apellido" },
3210
- { key: "isActive", label: "Activo" },
3211
- { key: "lastLogin", label: "\xDAltimo login" },
3212
- { key: "createdAt", label: "Creado" },
3213
- { key: "updatedAt", label: "Actualizado" }
3214
- ];
3215
- const knownFields = [...basicFields.map((f) => f.key), ...extendedFields.map((f) => f.key), "permissions"];
3216
- const customFields = Object.keys(displayData).filter((key) => !knownFields.includes(key)).map((key) => ({ key, label: key }));
3217
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { children: [
3218
- showProfileCard && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Card, { sx: { mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.CardContent, { children: [
3219
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", alignItems: "center", mb: 2, children: [
3220
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3221
- import_material8.Avatar,
3222
- {
3223
- src: displayData.avatar,
3224
- sx: { width: 56, height: 56, mr: 2 },
3225
- children: displayData.fullName?.[0] || displayData.username?.[0] || displayData.email?.[0]
3226
- }
3227
- ),
3228
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { children: [
3229
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "h6", children: displayData.fullName || displayData.username || displayData.email }),
3230
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", color: "text.secondary", children: displayData.role || "Usuario" }),
3231
- displayData.isActive !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3232
- import_material8.Chip,
3233
- {
3234
- label: displayData.isActive ? "Activo" : "Inactivo",
3235
- color: displayData.isActive ? "success" : "error",
3236
- size: "small",
3237
- sx: { mt: 0.5 }
3238
- }
3239
- )
3240
- ] })
3241
- ] }),
3242
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Box, { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: 2, children: basicFields.map(
3243
- ({ key, label, icon }) => displayData[key] ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", alignItems: "center", children: [
3244
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Box, { sx: { mr: 1, color: "text.secondary" }, children: icon }),
3245
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { children: [
3246
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "caption", color: "text.secondary", children: label }),
3247
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", children: renderFieldValue(key, displayData[key]) })
3248
- ] })
3249
- ] }, key) : null
3250
- ) }),
3251
- displayData.permissions && Array.isArray(displayData.permissions) && displayData.permissions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { mt: 2, children: [
3252
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "caption", color: "text.secondary", display: "block", children: "Permisos" }),
3253
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", flexWrap: "wrap", gap: 0.5, mt: 0.5, children: [
3254
- displayData.permissions.slice(0, 5).map((permission, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Chip, { label: permission, size: "small", variant: "outlined" }, index)),
3255
- displayData.permissions.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Chip, { label: `+${displayData.permissions.length - 5} m\xE1s`, size: "small" })
3256
- ] })
3257
- ] })
3258
- ] }) }),
3259
- showExtendedData && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Card, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.CardContent, { children: [
3260
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2, children: [
3261
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Typography, { variant: "h6", display: "flex", alignItems: "center", children: [
3262
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Info, { sx: { mr: 1 } }),
3263
- "Informaci\xF3n Detallada"
3264
- ] }),
3265
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Chip, { label: `${totalFields} campos totales`, size: "small" })
3266
- ] }),
3267
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.List, { dense: true, children: [
3268
- extendedFields.map(({ key, label }) => displayData[key] !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.ListItem, { divider: true, children: [
3269
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.Schedule, { fontSize: "small" }) }),
3270
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3271
- import_material8.ListItemText,
3272
- {
3273
- primary: label,
3274
- secondary: key.includes("At") || key.includes("Login") ? formatDate(displayData[key]) : renderFieldValue(key, displayData[key])
3275
- }
3276
- )
3277
- ] }, key)),
3278
- customFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3279
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Divider, { sx: { my: 1 } }),
3280
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.ListItem, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3281
- import_material8.ListItemText,
3282
- {
3283
- primary: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
3284
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Typography, { variant: "subtitle2", children: [
3285
- "Campos Personalizados (",
3286
- customFields.length,
3287
- ")"
3288
- ] }),
3289
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.IconButton, { size: "small", onClick: () => setShowAllFields(!showAllFields), children: showAllFields ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.ExpandLess, {}) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material.ExpandMore, {}) })
3290
- ] })
3291
- }
3292
- ) }),
3293
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Collapse, { in: showAllFields, children: customFields.map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.ListItem, { sx: { pl: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3294
- import_material8.ListItemText,
3295
- {
3296
- primary: label,
3297
- secondary: renderFieldValue(key, displayData[key])
3298
- }
3299
- ) }, key)) })
3300
- ] })
3301
- ] }),
3302
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { mt: 2, display: "flex", justifyContent: "space-between", alignItems: "center", children: [
3303
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Typography, { variant: "caption", color: "text.secondary", children: [
3304
- "\xDAltima actualizaci\xF3n: ",
3305
- formatDate(displayData.updatedAt)
3306
- ] }),
3307
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.IconButton, { size: "small", onClick: refreshProfile, disabled: loading, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "caption", children: "Actualizar" }) })
3308
- ] })
3309
- ] }) })
3310
- ] });
3311
- };
3312
- var UserProfileDisplay_default = UserProfileDisplay;
3313
-
3314
- // src/components/PublicPolicies/Policies.tsx
3315
- var import_react16 = require("react");
3316
- var import_react_i18next3 = require("react-i18next");
3317
- var import_material11 = require("@mui/material");
3318
- var import_icons_material4 = require("@mui/icons-material");
3319
-
3320
- // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
3321
- var import_react15 = require("react");
3322
- var import_react_i18next2 = require("react-i18next");
3323
- var import_material10 = require("@mui/material");
3324
- var import_icons_material3 = require("@mui/icons-material");
3325
-
3326
- // src/components/PublicPolicies/FieldSelector/FieldSelector.tsx
3327
- var import_react14 = require("react");
3328
- var import_react_i18next = require("react-i18next");
3329
- var import_material9 = require("@mui/material");
3330
- var import_icons_material2 = require("@mui/icons-material");
3331
- var import_jsx_runtime13 = require("react/jsx-runtime");
3332
- var FieldSelector = ({
3333
- value,
3334
- onChange,
3335
- availableFields,
3336
- error,
3337
- disabled = false
3338
- }) => {
3339
- const { t } = (0, import_react_i18next.useTranslation)();
3340
- const [mode, setMode] = (0, import_react14.useState)("custom");
3341
- const isUpdatingRef = (0, import_react14.useRef)(false);
3342
- (0, import_react14.useEffect)(() => {
3343
- const current = value || { allow: [], owner_allow: [], deny: [] };
3344
- const all = new Set(availableFields);
3345
- const allow = (current.allow || []).filter((f) => all.has(f));
3346
- const owner = (current.owner_allow || []).filter((f) => all.has(f));
3347
- const deny = (current.deny || []).filter((f) => all.has(f));
3348
- availableFields.forEach((f) => {
3349
- if (!allow.includes(f) && !owner.includes(f) && !deny.includes(f)) deny.push(f);
3350
- });
3351
- const normalized = { allow, owner_allow: owner, deny };
3352
- if (JSON.stringify(normalized) !== JSON.stringify(current)) {
3353
- onChange(normalized);
3354
- }
3355
- if (allow.length === availableFields.length) setMode("all");
3356
- else if (deny.length === availableFields.length) setMode("none");
3357
- else setMode("custom");
3358
- }, [availableFields, value]);
3359
- const setAllAllow = () => {
3360
- isUpdatingRef.current = true;
3361
- onChange({ allow: [...availableFields], owner_allow: [], deny: [] });
3362
- setMode("all");
3363
- setTimeout(() => {
3364
- isUpdatingRef.current = false;
3365
- }, 0);
3366
- };
3367
- const setAllDeny = () => {
3368
- isUpdatingRef.current = true;
3369
- onChange({ allow: [], owner_allow: [], deny: [...availableFields] });
3370
- setMode("none");
3371
- setTimeout(() => {
3372
- isUpdatingRef.current = false;
3373
- }, 0);
3374
- };
3375
- const getFieldState = (fieldName) => {
3376
- if (value?.allow?.includes(fieldName)) return "allow";
3377
- if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
3378
- return "deny";
3379
- };
3380
- const setFieldState = (fieldName, state) => {
3381
- isUpdatingRef.current = true;
3382
- const allow = new Set(value?.allow || []);
3383
- const owner = new Set(value?.owner_allow || []);
3384
- const deny = new Set(value?.deny || []);
3385
- allow.delete(fieldName);
3386
- owner.delete(fieldName);
3387
- deny.delete(fieldName);
3388
- if (state === "allow") allow.add(fieldName);
3389
- if (state === "owner_allow") owner.add(fieldName);
3390
- if (state === "deny") deny.add(fieldName);
3391
- onChange({ allow: Array.from(allow), owner_allow: Array.from(owner), deny: Array.from(deny) });
3392
- setMode("custom");
3393
- setTimeout(() => {
3394
- isUpdatingRef.current = false;
3395
- }, 0);
3396
- };
3397
- if (availableFields.length === 0) {
3398
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { children: [
3399
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
3400
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: t("modules.form.publicPolicies.fields.conditions.noFieldsAvailable") }),
3401
- error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
3402
- ] });
3403
- }
3404
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { children: [
3405
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
3406
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
3407
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3408
- import_material9.Button,
3409
- {
3410
- variant: mode === "all" ? "contained" : "outlined",
3411
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material2.SelectAll, {}),
3412
- onClick: setAllAllow,
3413
- disabled,
3414
- size: "small",
3415
- sx: {
3416
- minWidth: 120,
3417
- ...mode === "all" && {
3418
- backgroundColor: "#16a34a",
3419
- "&:hover": { backgroundColor: "#15803d" }
3420
- }
3421
- },
3422
- children: t("modules.form.publicPolicies.fields.conditions.allFields")
3423
- }
3424
- ),
3425
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3426
- import_material9.Button,
3427
- {
3428
- variant: mode === "none" ? "contained" : "outlined",
3429
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material2.ClearAll, {}),
3430
- onClick: setAllDeny,
3431
- disabled,
3432
- size: "small",
3433
- sx: {
3434
- minWidth: 120,
3435
- ...mode === "none" && {
3436
- backgroundColor: "#cf222e",
3437
- "&:hover": { backgroundColor: "#bc1f2c" }
3438
- }
3439
- },
3440
- children: t("modules.form.publicPolicies.fields.conditions.noFields")
3441
- }
3442
- )
3443
- ] }),
3444
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { sx: { p: 2, border: "1px solid #d1d9e0", borderRadius: 1, backgroundColor: "#f6f8fa" }, children: [
3445
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.help") }),
3446
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Stack, { spacing: 1, children: availableFields.map((fieldName) => {
3447
- const fieldState = getFieldState(fieldName);
3448
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
3449
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", sx: { minWidth: 100, fontFamily: "monospace" }, children: fieldName }),
3450
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.ToggleButtonGroup, { value: fieldState, exclusive: true, size: "small", children: [
3451
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3452
- import_material9.ToggleButton,
3453
- {
3454
- value: "allow",
3455
- onClick: () => setFieldState(fieldName, "allow"),
3456
- disabled,
3457
- sx: {
3458
- px: 2,
3459
- color: fieldState === "allow" ? "#ffffff" : "#6b7280",
3460
- backgroundColor: fieldState === "allow" ? "#16a34a" : "#f3f4f6",
3461
- borderColor: fieldState === "allow" ? "#16a34a" : "#d1d5db",
3462
- "&:hover": {
3463
- backgroundColor: fieldState === "allow" ? "#15803d" : "#e5e7eb",
3464
- borderColor: fieldState === "allow" ? "#15803d" : "#9ca3af"
3465
- },
3466
- "&.Mui-selected": {
3467
- backgroundColor: "#16a34a",
3468
- color: "#ffffff",
3469
- "&:hover": {
3470
- backgroundColor: "#15803d"
3471
- }
3472
- }
3473
- },
3474
- children: [
3475
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material2.CheckCircle, { sx: { fontSize: 16, mr: 0.5 } }),
3476
- t("modules.form.publicPolicies.fields.conditions.states.allow")
3477
- ]
3478
- }
3479
- ),
3480
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3481
- import_material9.ToggleButton,
3482
- {
3483
- value: "owner_allow",
3484
- onClick: () => setFieldState(fieldName, "owner_allow"),
3485
- disabled,
3486
- sx: {
3487
- px: 2,
3488
- color: fieldState === "owner_allow" ? "#ffffff" : "#6b7280",
3489
- backgroundColor: fieldState === "owner_allow" ? "#0ea5e9" : "#f3f4f6",
3490
- borderColor: fieldState === "owner_allow" ? "#0ea5e9" : "#d1d5db",
3491
- "&:hover": {
3492
- backgroundColor: fieldState === "owner_allow" ? "#0284c7" : "#e5e7eb",
3493
- borderColor: fieldState === "owner_allow" ? "#0284c7" : "#9ca3af"
3494
- },
3495
- "&.Mui-selected": {
3496
- backgroundColor: "#0ea5e9",
3497
- color: "#ffffff",
3498
- "&:hover": {
3499
- backgroundColor: "#0284c7"
3500
- }
3501
- }
3502
- },
3503
- children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
3504
- }
3505
- ),
3506
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3507
- import_material9.ToggleButton,
3508
- {
3509
- value: "deny",
3510
- onClick: () => setFieldState(fieldName, "deny"),
3511
- disabled,
3512
- sx: {
3513
- px: 2,
3514
- color: fieldState === "deny" ? "#ffffff" : "#6b7280",
3515
- backgroundColor: fieldState === "deny" ? "#dc2626" : "#f3f4f6",
3516
- borderColor: fieldState === "deny" ? "#dc2626" : "#d1d5db",
3517
- "&:hover": {
3518
- backgroundColor: fieldState === "deny" ? "#b91c1c" : "#e5e7eb",
3519
- borderColor: fieldState === "deny" ? "#b91c1c" : "#9ca3af"
3520
- },
3521
- "&.Mui-selected": {
3522
- backgroundColor: "#dc2626",
3523
- color: "#ffffff",
3524
- "&:hover": {
3525
- backgroundColor: "#b91c1c"
3526
- }
3527
- }
3528
- },
3529
- children: [
3530
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material2.Cancel, { sx: { fontSize: 16, mr: 0.5 } }),
3531
- t("modules.form.publicPolicies.fields.conditions.states.deny")
3532
- ]
3533
- }
3534
- )
3535
- ] })
3536
- ] }, fieldName);
3537
- }) })
3538
- ] }),
3539
- error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
3540
- ] });
3541
- };
3542
- var FieldSelector_default = FieldSelector;
3543
-
3544
- // src/components/PublicPolicies/constants.ts
3545
- var POLICY_ACTIONS = ["create", "read", "update", "delete"];
3546
- var PREFERRED_POLICY_ORDER = [
3547
- "create",
3548
- "read",
3549
- "update",
3550
- "delete"
3551
- ];
3552
-
3553
- // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
3554
- var import_jsx_runtime14 = require("react/jsx-runtime");
3555
- var PolicyItem = (0, import_react15.forwardRef)(({
3556
- policy,
3557
- onChange,
3558
- onRemove,
3559
- availableFields,
3560
- isSubmitting = false,
3561
- usedActions,
3562
- error
3563
- }, ref) => {
3564
- const { t } = (0, import_react_i18next2.useTranslation)();
3565
- const takenActions = new Set(Array.from(usedActions || []));
3566
- takenActions.delete(policy.action);
3567
- const actionOptions = POLICY_ACTIONS.map((a) => ({
3568
- value: a,
3569
- label: t(`modules.form.publicPolicies.fields.action.options.${a}`)
3570
- }));
3571
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3572
- import_material10.Paper,
3573
- {
3574
- ref,
3575
- sx: {
3576
- p: 3,
3577
- border: "1px solid #d1d9e0",
3578
- borderRadius: 2,
3579
- position: "relative",
3580
- backgroundColor: "#ffffff"
3581
- },
3582
- children: [
3583
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { sx: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", mb: 3 }, children: [
3584
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3585
- import_material10.Typography,
3586
- {
3587
- variant: "subtitle1",
3588
- sx: {
3589
- fontWeight: 600,
3590
- color: "#111418",
3591
- fontSize: "1rem"
3592
- },
3593
- children: t("modules.form.publicPolicies.policyTitle")
3594
- }
3595
- ),
3596
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3597
- import_material10.IconButton,
3598
- {
3599
- onClick: onRemove,
3600
- size: "small",
3601
- disabled: isSubmitting,
3602
- "aria-label": t("modules.form.publicPolicies.removePolicy"),
3603
- sx: {
3604
- color: "#656d76",
3605
- "&:hover": {
3606
- color: "#cf222e",
3607
- backgroundColor: "rgba(207, 34, 46, 0.1)"
3608
- }
3609
- },
3610
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material3.Delete, {})
3611
- }
3612
- )
3613
- ] }),
3614
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Stack, { spacing: 3, children: [
3615
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Stack, { direction: { xs: "column", md: "row" }, spacing: 2, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Box, { sx: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.FormControl, { fullWidth: true, children: [
3616
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.InputLabel, { children: t("modules.form.publicPolicies.fields.action.label") }),
3617
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3618
- import_material10.Select,
3619
- {
3620
- value: policy.action,
3621
- label: t("modules.form.publicPolicies.fields.action.label"),
3622
- disabled: isSubmitting,
3623
- onChange: (e) => {
3624
- const newAction = e.target.value;
3625
- const next = { ...policy, action: newAction };
3626
- if (newAction === "delete") {
3627
- next.permission = "deny";
3628
- delete next.fields;
3629
- } else {
3630
- next.fields = { allow: [], owner_allow: [], deny: availableFields };
3631
- delete next.permission;
3632
- }
3633
- onChange(next);
3634
- },
3635
- sx: {
3636
- backgroundColor: "#ffffff",
3637
- "&:hover .MuiOutlinedInput-notchedOutline": {
3638
- borderColor: "#8c959f"
3639
- },
3640
- "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
3641
- borderColor: "#0969da",
3642
- borderWidth: 2
3643
- }
3644
- },
3645
- children: actionOptions.map((option) => {
3646
- const disabledOption = takenActions.has(option.value);
3647
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.MenuItem, { value: option.value, disabled: disabledOption, children: option.label }, option.value);
3648
- })
3649
- }
3650
- ),
3651
- error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.FormHelperText, { error: true, children: error })
3652
- ] }) }) }),
3653
- policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { children: [
3654
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
3655
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
3656
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3657
- import_material10.Button,
3658
- {
3659
- variant: policy.permission === "*" ? "contained" : "outlined",
3660
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material3.SelectAll, {}),
3661
- onClick: () => onChange({ ...policy, permission: "*" }),
3662
- disabled: isSubmitting,
3663
- size: "small",
3664
- sx: {
3665
- minWidth: 140,
3666
- whiteSpace: "nowrap",
3667
- ...policy.permission === "*" && {
3668
- backgroundColor: "#16a34a",
3669
- "&:hover": { backgroundColor: "#15803d" }
3670
- }
3671
- },
3672
- children: t("modules.form.publicPolicies.fields.conditions.allFields")
3673
- }
3674
- ),
3675
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3676
- import_material10.Button,
3677
- {
3678
- variant: policy.permission === "owner" ? "contained" : "outlined",
3679
- onClick: () => onChange({ ...policy, permission: "owner" }),
3680
- disabled: isSubmitting,
3681
- size: "small",
3682
- sx: {
3683
- minWidth: 140,
3684
- whiteSpace: "nowrap",
3685
- ...policy.permission === "owner" && {
3686
- backgroundColor: "#0ea5e9",
3687
- "&:hover": { backgroundColor: "#0284c7" }
3688
- }
3689
- },
3690
- children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
3691
- }
3692
- ),
3693
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3694
- import_material10.Button,
3695
- {
3696
- variant: policy.permission === "deny" ? "contained" : "outlined",
3697
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material3.ClearAll, {}),
3698
- onClick: () => onChange({ ...policy, permission: "deny" }),
3699
- disabled: isSubmitting,
3700
- size: "small",
3701
- sx: {
3702
- minWidth: 140,
3703
- whiteSpace: "nowrap",
3704
- ...policy.permission === "deny" && {
3705
- backgroundColor: "#cf222e",
3706
- "&:hover": { backgroundColor: "#bc1f2c" }
3707
- }
3708
- },
3709
- children: t("modules.form.publicPolicies.fields.conditions.noFields")
3710
- }
3711
- )
3712
- ] })
3713
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3714
- FieldSelector_default,
3715
- {
3716
- value: policy.fields || { allow: [], owner_allow: [], deny: [] },
3717
- onChange: (nextFields) => onChange({ ...policy, fields: nextFields }),
3718
- availableFields,
3719
- disabled: isSubmitting
3720
- }
3721
- ),
3722
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Paper, { variant: "outlined", sx: { p: 2, backgroundColor: "#f9fafb" }, children: policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3723
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { component: "span", sx: {
3724
- color: policy.permission === "*" ? "#16a34a" : policy.permission === "owner" ? "#0ea5e9" : "#dc2626"
3725
- }, children: [
3726
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
3727
- ":"
3728
- ] }),
3729
- " ",
3730
- policy.permission || "-"
3731
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Stack, { spacing: 0.5, divider: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Divider, { sx: { borderColor: "#e5e7eb" } }), children: [
3732
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3733
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { component: "span", sx: { color: "#16a34a" }, children: [
3734
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
3735
- ":"
3736
- ] }),
3737
- " ",
3738
- (policy?.fields?.allow || []).join(", ") || "-"
3739
- ] }),
3740
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3741
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { component: "span", sx: { color: "#0ea5e9" }, children: [
3742
- t("modules.form.publicPolicies.fields.conditions.states.ownerAllow"),
3743
- ":"
3744
- ] }),
3745
- " ",
3746
- (policy?.fields?.owner_allow || []).join(", ") || "-"
3747
- ] }),
3748
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3749
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { component: "span", sx: { color: "#dc2626" }, children: [
3750
- t("modules.form.publicPolicies.fields.conditions.states.deny"),
3751
- ":"
3752
- ] }),
3753
- " ",
3754
- (policy?.fields?.deny || []).join(", ") || "-"
3755
- ] })
3756
- ] }) })
3757
- ] })
3758
- ]
3759
- }
3760
- );
3761
- });
3762
- var PolicyItem_default = PolicyItem;
3763
-
3764
- // src/components/PublicPolicies/Policies.tsx
3765
- var import_jsx_runtime15 = require("react/jsx-runtime");
3766
- var generateId = () => {
3767
- const c = globalThis?.crypto;
3768
- if (c && typeof c.randomUUID === "function") return c.randomUUID();
3769
- return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
3770
- };
3771
- var Policies = ({
3772
- policies,
3773
- onChange,
3774
- availableFields,
3775
- errors,
3776
- isSubmitting = false
3777
- }) => {
3778
- const { t } = (0, import_react_i18next3.useTranslation)();
3779
- const policyRefs = (0, import_react16.useRef)({});
3780
- const takenActions = new Set((policies || []).map((p) => p.action).filter(Boolean));
3781
- const remainingActions = PREFERRED_POLICY_ORDER.filter((a) => !takenActions.has(a));
3782
- const canAddPolicy = remainingActions.length > 0;
3783
- const addPolicy = () => {
3784
- const defaultAction = remainingActions[0] || "create";
3785
- const newPolicy = {
3786
- id: generateId(),
3787
- action: defaultAction
3788
- };
3789
- if (defaultAction === "delete") {
3790
- newPolicy.permission = "deny";
3791
- } else {
3792
- newPolicy.fields = {
3793
- allow: [],
3794
- owner_allow: [],
3795
- deny: availableFields
3796
- };
3797
- }
3798
- const next = [...policies || [], newPolicy];
3799
- onChange(next);
3800
- setTimeout(() => {
3801
- const newIndex = next.length - 1;
3802
- const el = policyRefs.current[newIndex];
3803
- if (el) {
3804
- el.scrollIntoView({ behavior: "smooth", block: "center" });
3805
- }
3806
- }, 100);
3807
- };
3808
- const removePolicy = (index) => {
3809
- const next = [...policies];
3810
- next.splice(index, 1);
3811
- onChange(next);
3812
- };
3813
- const arrayError = (() => {
3814
- if (!errors) return null;
3815
- if (typeof errors === "string") return errors;
3816
- const msg = errors._error;
3817
- return typeof msg === "string" ? msg : null;
3818
- })();
3819
- const usedActions = new Set((policies || []).map((p) => p.action));
3820
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3821
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Divider, { sx: { borderColor: "#e0e4e7" } }),
3822
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Box, { children: [
3823
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Box, { children: [
3824
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3825
- import_material11.Typography,
3826
- {
3827
- variant: "h6",
3828
- sx: {
3829
- fontWeight: 600,
3830
- color: "#111418",
3831
- mb: 1
3832
- },
3833
- children: t("modules.form.publicPolicies.title")
3834
- }
3835
- ),
3836
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3837
- import_material11.Typography,
3838
- {
3839
- variant: "body2",
3840
- color: "text.secondary",
3841
- sx: { fontSize: "0.875rem" },
3842
- children: t("modules.form.publicPolicies.description")
3843
- }
3844
- )
3845
- ] }) }),
3846
- arrayError && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Alert, { severity: "error", sx: { mb: 3 }, children: arrayError }),
3847
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material11.Stack, { spacing: 3, children: [
3848
- (policies || []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Alert, { severity: "info", children: t("modules.form.publicPolicies.noPolicies") }) : policies.map((policy, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3849
- PolicyItem_default,
3850
- {
3851
- ref: (el) => {
3852
- policyRefs.current[index] = el;
3853
- },
3854
- policy,
3855
- onChange: (nextPolicy) => {
3856
- const next = [...policies];
3857
- next[index] = nextPolicy;
3858
- onChange(next);
3859
- },
3860
- onRemove: () => removePolicy(index),
3861
- availableFields,
3862
- isSubmitting,
3863
- usedActions,
3864
- error: typeof errors === "object" && errors && policy.id in errors ? errors[policy.id] : void 0
3865
- },
3866
- policy.id
3867
- )),
3868
- canAddPolicy && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material11.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3869
- import_material11.Button,
3870
- {
3871
- type: "button",
3872
- variant: "outlined",
3873
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material4.Add, {}),
3874
- onClick: addPolicy,
3875
- disabled: isSubmitting,
3876
- sx: {
3877
- borderColor: "#d0d7de",
3878
- color: "#656d76",
3879
- "&:hover": {
3880
- borderColor: "#8c959f",
3881
- backgroundColor: "transparent"
3882
- }
3883
- },
3884
- children: t("modules.form.publicPolicies.addPolicy")
3885
- }
3886
- ) })
3887
- ] })
3888
- ] })
3889
- ] });
3890
- };
3891
- var Policies_default = Policies;
3892
-
3893
- // src/components/LoginComponent.tsx
3894
- var import_react17 = require("react");
3895
- var import_material12 = require("@mui/material");
3896
- var import_jsx_runtime16 = require("react/jsx-runtime");
3897
- function LoginComponent() {
3898
- const [email, setEmail] = (0, import_react17.useState)("");
3899
- const [password, setPassword] = (0, import_react17.useState)("");
3900
- const [showForm, setShowForm] = (0, import_react17.useState)(false);
3901
- const {
3902
- isAuthenticated,
3903
- isLoading,
3904
- error,
3905
- login,
3906
- logout,
3907
- refreshTokens,
3908
- clearError,
3909
- isExpiringSoon,
3910
- expiresIn
3911
- } = useSessionContext();
3912
- const handleLogin = async (e) => {
3913
- e.preventDefault();
3914
- if (!email || !password) {
3915
- return;
3916
- }
3917
- const result = await login(email, password);
3918
- if (result.success) {
3919
- setEmail("");
3920
- setPassword("");
3921
- setShowForm(false);
3922
- }
3923
- };
3924
- const handleLogout = async () => {
3925
- await logout();
3926
- };
3927
- const handleRefreshTokens = async () => {
3928
- await refreshTokens();
3929
- };
3930
- if (isAuthenticated) {
3931
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { sx: { maxWidth: 600, mx: "auto", p: 3 }, children: [
3932
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "h4", gutterBottom: true, children: "Welcome! \u{1F389}" }),
3933
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Alert, { severity: "success", sx: { mb: 3 }, children: "You are successfully logged in with Refresh Token Pattern enabled" }),
3934
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { sx: { mb: 3, p: 2, bgcolor: "background.paper", border: 1, borderColor: "divider", borderRadius: 1 }, children: [
3935
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "h6", gutterBottom: true, children: "Token Status" }),
3936
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Typography, { variant: "body2", color: "text.secondary", children: [
3937
- "Access Token expires in: ",
3938
- Math.round(expiresIn / 1e3 / 60),
3939
- " minutes"
3940
- ] }),
3941
- isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Alert, { severity: "warning", sx: { mt: 1 }, children: "Token expires soon - automatic refresh will happen" })
3942
- ] }),
3943
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { sx: { display: "flex", gap: 2, flexWrap: "wrap" }, children: [
3944
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3945
- import_material12.Button,
3946
- {
3947
- variant: "contained",
3948
- onClick: handleRefreshTokens,
3949
- disabled: isLoading,
3950
- startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.CircularProgress, { size: 16 }) : null,
3951
- children: "Refresh Tokens"
3952
- }
3953
- ),
3954
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3955
- import_material12.Button,
3956
- {
3957
- variant: "outlined",
3958
- color: "error",
3959
- onClick: handleLogout,
3960
- disabled: isLoading,
3961
- children: "Logout"
3962
- }
3963
- )
3964
- ] }),
3965
- error && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
3966
- ] });
3967
- }
3968
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { sx: { maxWidth: 400, mx: "auto", p: 3 }, children: [
3969
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "h4", gutterBottom: true, align: "center", children: "Login with Refresh Tokens" }),
3970
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Alert, { severity: "info", sx: { mb: 3 }, children: "This demo shows the new Refresh Token Pattern with automatic session management" }),
3971
- !showForm ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3972
- import_material12.Button,
3973
- {
3974
- fullWidth: true,
3975
- variant: "contained",
3976
- size: "large",
3977
- onClick: () => setShowForm(true),
3978
- sx: { mt: 2 },
3979
- children: "Show Login Form"
3980
- }
3981
- ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("form", { onSubmit: handleLogin, children: [
3982
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3983
- import_material12.TextField,
3984
- {
3985
- fullWidth: true,
3986
- label: "Email",
3987
- type: "email",
3988
- value: email,
3989
- onChange: (e) => setEmail(e.target.value),
3990
- margin: "normal",
3991
- required: true,
3992
- autoComplete: "email"
3993
- }
3994
- ),
3995
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3996
- import_material12.TextField,
3997
- {
3998
- fullWidth: true,
3999
- label: "Password",
4000
- type: "password",
4001
- value: password,
4002
- onChange: (e) => setPassword(e.target.value),
4003
- margin: "normal",
4004
- required: true,
4005
- autoComplete: "current-password"
4006
- }
4007
- ),
4008
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4009
- import_material12.Button,
4010
- {
4011
- type: "submit",
4012
- fullWidth: true,
4013
- variant: "contained",
4014
- size: "large",
4015
- disabled: isLoading,
4016
- startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.CircularProgress, { size: 16 }) : null,
4017
- sx: { mt: 3, mb: 2 },
4018
- children: isLoading ? "Logging in..." : "Login"
4019
- }
4020
- )
4021
- ] }),
4022
- error && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
4023
- ] });
4024
- }
4025
- function SessionStatus() {
4026
- const { isAuthenticated, isLoading, isExpiringSoon, expiresIn } = useSessionContext();
4027
- if (isLoading) {
4028
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
4029
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.CircularProgress, { size: 16 }),
4030
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "caption", children: "Loading session..." })
4031
- ] });
4032
- }
4033
- if (!isAuthenticated) {
4034
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "caption", color: "text.secondary", children: "Not logged in" });
4035
- }
4036
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Box, { children: [
4037
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material12.Typography, { variant: "caption", color: "success.main", children: "\u2713 Authenticated" }),
4038
- isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material12.Typography, { variant: "caption", color: "warning.main", display: "block", children: [
4039
- "\u26A0 Token expires in ",
4040
- Math.round(expiresIn / 1e3 / 60),
4041
- " min"
4042
- ] })
4043
- ] });
4044
- }
4045
-
4046
- // src/hooks/useUserData.ts
4047
- var import_react18 = require("react");
4048
- var import_crudify_browser4 = __toESM(require("@nocios/crudify-browser"));
4049
- var useUserData = (options = {}) => {
4050
- const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
4051
- const { isAuthenticated, isInitialized, sessionData, tokens } = useSessionContext();
4052
- const [userData, setUserData] = (0, import_react18.useState)(null);
4053
- const [loading, setLoading] = (0, import_react18.useState)(false);
4054
- const [error, setError] = (0, import_react18.useState)(null);
4055
- const abortControllerRef = (0, import_react18.useRef)(null);
4056
- const mountedRef = (0, import_react18.useRef)(true);
4057
- const requestIdRef = (0, import_react18.useRef)(0);
4058
- const retryCountRef = (0, import_react18.useRef)(0);
4059
- const getUserEmail = (0, import_react18.useCallback)(() => {
4060
- if (!sessionData) return null;
4061
- return sessionData.email || sessionData["cognito:username"] || null;
4062
- }, [sessionData]);
4063
- const clearProfile = (0, import_react18.useCallback)(() => {
4064
- setUserData(null);
4065
- setError(null);
4066
- setLoading(false);
4067
- retryCountRef.current = 0;
4068
- }, []);
4069
- const refreshProfile = (0, import_react18.useCallback)(async () => {
4070
- const userEmail = getUserEmail();
4071
- if (!userEmail) {
4072
- if (mountedRef.current) {
4073
- setError("No user email available from session data");
4074
- setLoading(false);
4075
- }
4076
- return;
4077
- }
4078
- if (!isInitialized) {
4079
- if (mountedRef.current) {
4080
- setError("Session not initialized");
4081
- setLoading(false);
4082
- }
4083
- return;
4084
- }
4085
- if (abortControllerRef.current) {
4086
- abortControllerRef.current.abort();
4087
- }
4088
- const abortController = new AbortController();
4089
- abortControllerRef.current = abortController;
4090
- const currentRequestId = ++requestIdRef.current;
4091
- try {
4092
- if (mountedRef.current) {
4093
- setLoading(true);
4094
- setError(null);
4095
- }
4096
- const response = await import_crudify_browser4.default.readItems("users", {
4097
- filter: { email: userEmail },
4098
- pagination: { limit: 1 }
4099
- });
4100
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
4101
- let userData2 = null;
4102
- if (response.success) {
4103
- if (Array.isArray(response.data) && response.data.length > 0) {
4104
- userData2 = response.data[0];
4105
- } else if (response.data?.response?.data) {
4106
- try {
4107
- const rawData = response.data.response.data;
4108
- const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
4109
- if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
4110
- userData2 = parsedData.items[0];
4111
- } else {
4112
- }
4113
- } catch (parseError) {
4114
- }
4115
- } else if (response.data && typeof response.data === "object") {
4116
- if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
4117
- userData2 = response.data.items[0];
4118
- } else {
4119
- }
4120
- } else if (response.data?.data?.response?.data) {
4121
- try {
4122
- const rawData = response.data.data.response.data;
4123
- const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
4124
- if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
4125
- userData2 = parsedData.items[0];
4126
- }
4127
- } catch (parseError) {
4128
- }
4129
- }
4130
- }
4131
- if (userData2) {
4132
- setUserData(userData2);
4133
- setError(null);
4134
- retryCountRef.current = 0;
4135
- } else {
4136
- setError("User profile not found in database");
4137
- setUserData(null);
4138
- }
4139
- }
4140
- } catch (err) {
4141
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
4142
- const error2 = err;
4143
- if (error2.name === "AbortError") {
4144
- return;
4145
- }
4146
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
4147
- if (shouldRetry) {
4148
- retryCountRef.current++;
4149
- setTimeout(() => {
4150
- if (mountedRef.current) {
4151
- refreshProfile();
4152
- }
4153
- }, 1e3 * retryCountRef.current);
4154
- } else {
4155
- setError("Failed to load user profile from database");
4156
- setUserData(null);
4157
- }
4158
- }
4159
- } finally {
4160
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
4161
- setLoading(false);
4162
- }
4163
- if (abortControllerRef.current === abortController) {
4164
- abortControllerRef.current = null;
4165
- }
4166
- }
4167
- }, [isInitialized, getUserEmail, retryOnError, maxRetries]);
4168
- (0, import_react18.useEffect)(() => {
4169
- if (autoFetch && isAuthenticated && isInitialized) {
4170
- refreshProfile();
4171
- } else if (!isAuthenticated) {
4172
- clearProfile();
4173
- }
4174
- }, [autoFetch, isAuthenticated, isInitialized, refreshProfile, clearProfile]);
4175
- (0, import_react18.useEffect)(() => {
4176
- mountedRef.current = true;
4177
- return () => {
4178
- mountedRef.current = false;
4179
- if (abortControllerRef.current) {
4180
- abortControllerRef.current.abort();
4181
- abortControllerRef.current = null;
4182
- }
4183
- };
4184
- }, []);
4185
- const user = {
4186
- session: sessionData,
4187
- // Usar sessionData del nuevo sistema
4188
- data: userData
4189
- // Mantener userData del database igual que legacy
4190
- };
4191
- return {
4192
- user,
4193
- loading,
4194
- error,
4195
- refreshProfile,
4196
- clearProfile
4197
- };
4198
- };
4199
-
4200
- // src/hooks/useAuth.ts
4201
- var import_react19 = require("react");
4202
- var useAuth = () => {
4203
- const {
4204
- isAuthenticated,
4205
- isLoading,
4206
- isInitialized,
4207
- tokens,
4208
- error,
4209
- sessionData,
4210
- login,
4211
- logout,
4212
- refreshTokens,
4213
- clearError,
4214
- getTokenInfo,
4215
- isExpiringSoon,
4216
- expiresIn,
4217
- refreshExpiresIn
4218
- } = useSessionContext();
4219
- const setToken = (0, import_react19.useCallback)((token) => {
4220
- if (token) {
4221
- console.warn("useAuth.setToken() is deprecated. Use login() method instead for better security.");
4222
- } else {
4223
- logout();
4224
- }
4225
- }, [logout]);
4226
- const tokenExpiration = tokens?.expiresAt ? new Date(tokens.expiresAt) : null;
4227
- return {
4228
- // Estado básico (compatible con legacy)
4229
- isAuthenticated,
4230
- loading: isLoading,
4231
- // En el nuevo sistema se llama isLoading
4232
- error,
4233
- // Datos del token (compatible con legacy + mejorado)
4234
- token: tokens?.accessToken || null,
4235
- user: sessionData,
4236
- // sessionData del nuevo sistema (más rico que legacy)
4237
- tokenExpiration,
4238
- // Acciones (compatible con legacy + mejorado)
4239
- setToken,
4240
- logout,
4241
- refreshToken: refreshTokens,
4242
- // Funcionalidad real en el nuevo sistema
4243
- // Nuevas funcionalidades del sistema de refresh tokens
4244
- login,
4245
- isExpiringSoon,
4246
- expiresIn,
4247
- refreshExpiresIn,
4248
- getTokenInfo,
4249
- clearError
4250
- };
4251
- };
4252
-
4253
- // src/hooks/useData.ts
4254
- var import_react20 = require("react");
4255
- var import_crudify_browser5 = __toESM(require("@nocios/crudify-browser"));
4256
- var useData = () => {
4257
- const {
4258
- isInitialized,
4259
- isLoading,
4260
- error,
4261
- isAuthenticated,
4262
- login: sessionLogin
4263
- } = useSessionContext();
4264
- const isReady = (0, import_react20.useCallback)(() => {
4265
- return isInitialized && !isLoading && !error;
4266
- }, [isInitialized, isLoading, error]);
4267
- const waitForReady = (0, import_react20.useCallback)(async () => {
4268
- return new Promise((resolve, reject) => {
4269
- const checkReady = () => {
4270
- if (isReady()) {
4271
- resolve();
4272
- } else if (error) {
4273
- reject(new Error(error));
4274
- } else {
4275
- setTimeout(checkReady, 100);
4276
- }
4277
- };
4278
- checkReady();
4279
- });
4280
- }, [isReady, error]);
4281
- const ensureReady = (0, import_react20.useCallback)(async () => {
4282
- if (!isReady()) {
4283
- throw new Error("System not ready. Check isInitialized, isLoading, and error states.");
4284
- }
4285
- }, [isReady]);
4286
- const readItems = (0, import_react20.useCallback)(async (moduleKey, filter, options) => {
4287
- await ensureReady();
4288
- return await import_crudify_browser5.default.readItems(moduleKey, filter || {}, options);
4289
- }, [ensureReady]);
4290
- const readItem = (0, import_react20.useCallback)(async (moduleKey, filter, options) => {
4291
- await ensureReady();
4292
- return await import_crudify_browser5.default.readItem(moduleKey, filter, options);
4293
- }, [ensureReady]);
4294
- const createItem = (0, import_react20.useCallback)(async (moduleKey, data, options) => {
4295
- await ensureReady();
4296
- return await import_crudify_browser5.default.createItem(moduleKey, data, options);
4297
- }, [ensureReady]);
4298
- const updateItem = (0, import_react20.useCallback)(async (moduleKey, data, options) => {
4299
- await ensureReady();
4300
- return await import_crudify_browser5.default.updateItem(moduleKey, data, options);
4301
- }, [ensureReady]);
4302
- const deleteItem = (0, import_react20.useCallback)(async (moduleKey, id, options) => {
4303
- await ensureReady();
4304
- return await import_crudify_browser5.default.deleteItem(moduleKey, id, options);
4305
- }, [ensureReady]);
4306
- const transaction = (0, import_react20.useCallback)(async (operations, options) => {
4307
- await ensureReady();
4308
- return await import_crudify_browser5.default.transaction(operations, options);
4309
- }, [ensureReady]);
4310
- const login = (0, import_react20.useCallback)(async (email, password) => {
4311
- try {
4312
- const result = await sessionLogin(email, password);
4313
- if (result.success) {
4314
- return {
4315
- success: true,
4316
- data: result.tokens
4317
- };
4318
- } else {
4319
- return {
4320
- success: false,
4321
- errors: result.error || "Login failed"
4322
- };
4323
- }
4324
- } catch (error2) {
4325
- return {
4326
- success: false,
4327
- errors: error2 instanceof Error ? error2.message : "Login failed"
4328
- };
4329
- }
4330
- }, [sessionLogin]);
4331
- return {
4332
- // CRUD operations
4333
- readItems,
4334
- readItem,
4335
- createItem,
4336
- updateItem,
4337
- deleteItem,
4338
- transaction,
4339
- login,
4340
- // Estado
4341
- isInitialized,
4342
- isInitializing: isLoading,
4343
- // El nuevo sistema usa isLoading
4344
- initializationError: error,
4345
- // Utilidades
4346
- isReady,
4347
- waitForReady
4348
- };
4349
- };
4350
-
4351
- // src/components/CrudifyLogin/utils/secureStorage.ts
4352
- var import_crypto_js2 = __toESM(require("crypto-js"));
4353
- var SecureStorage = class {
4354
- constructor(storageType = "sessionStorage") {
4355
- this.encryptionKey = this.generateEncryptionKey();
4356
- this.storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
4357
- }
4358
- generateEncryptionKey() {
4359
- const browserFingerprint = [
4360
- navigator.userAgent,
4361
- navigator.language,
4362
- (/* @__PURE__ */ new Date()).getTimezoneOffset(),
4363
- screen.colorDepth,
4364
- screen.width,
4365
- screen.height,
4366
- "crudify-login"
4367
- ].join("|");
4368
- return import_crypto_js2.default.SHA256(browserFingerprint).toString();
4369
- }
4370
- setItem(key, value, expiryMinutes) {
4371
- try {
4372
- const encrypted = import_crypto_js2.default.AES.encrypt(value, this.encryptionKey).toString();
4373
- this.storage.setItem(key, encrypted);
4374
- if (expiryMinutes) {
4375
- const expiryTime = (/* @__PURE__ */ new Date()).getTime() + expiryMinutes * 60 * 1e3;
4376
- this.storage.setItem(`${key}_expiry`, expiryTime.toString());
4377
- }
4378
- } catch (error) {
4379
- console.error("Failed to encrypt and store data:", error);
4380
- }
4381
- }
4382
- getItem(key) {
4383
- try {
4384
- const expiryKey = `${key}_expiry`;
4385
- const expiry = this.storage.getItem(expiryKey);
4386
- if (expiry) {
4387
- const expiryTime = parseInt(expiry, 10);
4388
- if ((/* @__PURE__ */ new Date()).getTime() > expiryTime) {
4389
- this.removeItem(key);
4390
- return null;
4391
- }
4392
- }
4393
- const encrypted = this.storage.getItem(key);
4394
- if (!encrypted) return null;
4395
- const decrypted = import_crypto_js2.default.AES.decrypt(encrypted, this.encryptionKey);
4396
- const result = decrypted.toString(import_crypto_js2.default.enc.Utf8);
4397
- if (!result) {
4398
- console.warn("Failed to decrypt stored data - may be corrupted");
4399
- this.removeItem(key);
4400
- return null;
4401
- }
4402
- return result;
4403
- } catch (error) {
4404
- console.error("Failed to decrypt data:", error);
4405
- this.removeItem(key);
4406
- return null;
4407
- }
4408
- }
4409
- removeItem(key) {
4410
- this.storage.removeItem(key);
4411
- this.storage.removeItem(`${key}_expiry`);
4412
- }
4413
- setToken(token) {
4414
- try {
4415
- const parts = token.split(".");
4416
- if (parts.length === 3) {
4417
- const payload = JSON.parse(atob(parts[1]));
4418
- if (payload.exp) {
4419
- const expiryTime = payload.exp * 1e3;
4420
- const now = (/* @__PURE__ */ new Date()).getTime();
4421
- const minutesUntilExpiry = Math.floor((expiryTime - now) / (60 * 1e3));
4422
- if (minutesUntilExpiry > 0) {
4423
- this.setItem("authToken", token, minutesUntilExpiry);
4424
- return;
4425
- }
4426
- }
4427
- }
4428
- } catch (error) {
4429
- console.warn("Failed to parse token expiry, using default expiry");
4430
- }
4431
- this.setItem("authToken", token, 24 * 60);
4432
- }
4433
- getToken() {
4434
- const token = this.getItem("authToken");
4435
- if (token) {
4436
- try {
4437
- const parts = token.split(".");
4438
- if (parts.length === 3) {
4439
- const payload = JSON.parse(atob(parts[1]));
4440
- if (payload.exp) {
4441
- const now = Math.floor(Date.now() / 1e3);
4442
- if (payload.exp < now) {
4443
- this.removeItem("authToken");
4444
- return null;
4445
- }
4446
- }
4447
- }
4448
- } catch (error) {
4449
- console.warn("Failed to validate token expiry");
4450
- this.removeItem("authToken");
4451
- return null;
4452
- }
4453
- }
4454
- return token;
4455
- }
4456
- };
4457
- var secureSessionStorage = new SecureStorage("sessionStorage");
4458
- var secureLocalStorage = new SecureStorage("localStorage");
4459
-
4460
- // src/hooks/useCrudifyWithNotifications.ts
4461
- var import_react21 = require("react");
4462
- var import_crudify_browser6 = __toESM(require("@nocios/crudify-browser"));
4463
- var ERROR_SEVERITY_MAP2 = {
4464
- // Errores de autenticación - warning porque el usuario puede corregirlos
4465
- INVALID_CREDENTIALS: "warning",
4466
- UNAUTHORIZED: "warning",
4467
- INVALID_API_KEY: "error",
4468
- // Errores de usuario/permisos - warning
4469
- USER_NOT_FOUND: "warning",
4470
- USER_NOT_ACTIVE: "warning",
4471
- NO_PERMISSION: "warning",
4472
- // Errores de datos - info porque pueden ser esperados
4473
- ITEM_NOT_FOUND: "info",
4474
- NOT_FOUND: "info",
4475
- IN_USE: "warning",
4476
- // Errores de validación - warning
4477
- FIELD_ERROR: "warning",
4478
- BAD_REQUEST: "warning",
4479
- // Errores del sistema - error
4480
- INTERNAL_SERVER_ERROR: "error",
4481
- DATABASE_CONNECTION_ERROR: "error",
4482
- INVALID_CONFIGURATION: "error",
4483
- UNKNOWN_OPERATION: "error",
4484
- // Rate limiting - warning con mayor duración
4485
- TOO_MANY_REQUESTS: "warning"
4486
- };
4487
- var ERROR_TRANSLATION_MAP = {
4488
- INVALID_CREDENTIALS: "errors.auth.INVALID_CREDENTIALS",
4489
- UNAUTHORIZED: "errors.auth.UNAUTHORIZED",
4490
- INVALID_API_KEY: "errors.auth.INVALID_API_KEY",
4491
- USER_NOT_FOUND: "errors.auth.USER_NOT_FOUND",
4492
- USER_NOT_ACTIVE: "errors.auth.USER_NOT_ACTIVE",
4493
- NO_PERMISSION: "errors.auth.NO_PERMISSION",
4494
- ITEM_NOT_FOUND: "errors.data.ITEM_NOT_FOUND",
4495
- NOT_FOUND: "errors.data.NOT_FOUND",
4496
- IN_USE: "errors.data.IN_USE",
4497
- FIELD_ERROR: "errors.data.FIELD_ERROR",
4498
- BAD_REQUEST: "errors.data.BAD_REQUEST",
4499
- INTERNAL_SERVER_ERROR: "errors.system.INTERNAL_SERVER_ERROR",
4500
- DATABASE_CONNECTION_ERROR: "errors.system.DATABASE_CONNECTION_ERROR",
4501
- INVALID_CONFIGURATION: "errors.system.INVALID_CONFIGURATION",
4502
- UNKNOWN_OPERATION: "errors.system.UNKNOWN_OPERATION",
4503
- TOO_MANY_REQUESTS: "errors.system.TOO_MANY_REQUESTS"
4504
- };
4505
- var useCrudifyWithNotifications = (options = {}) => {
4506
- const { showNotification } = useGlobalNotification();
4507
- const {
4508
- showSuccessNotifications = false,
4509
- showErrorNotifications = true,
4510
- customErrorMessages = {},
4511
- defaultErrorMessage = "Ha ocurrido un error inesperado",
4512
- autoHideDuration = 6e3,
4513
- appStructure = [],
4514
- translateFn = (key) => key
4515
- // Fallback si no hay función de traducción
4516
- } = options;
4517
- const shouldShowNotification = (0, import_react21.useCallback)((response) => {
4518
- if (!response.success && response.errors) {
4519
- const hasFieldErrors = Object.keys(response.errors).some((key) => key !== "_error" && key !== "_graphql" && key !== "_transaction");
4520
- if (hasFieldErrors) return false;
4521
- if (response.errors._transaction?.includes("ONE_OR_MORE_OPERATIONS_FAILED")) return false;
4522
- if (response.errors._error?.includes("TOO_MANY_REQUESTS")) return false;
4523
- }
4524
- if (!response.success && response.data?.response?.status === "TOO_MANY_REQUESTS") return false;
4525
- return true;
4526
- }, []);
4527
- const getSafeTranslation = (0, import_react21.useCallback)(
4528
- (key, fallback) => {
4529
- const translated = translateFn(key);
4530
- if (translated === key) return fallback || translateFn("error.unknown");
4531
- return translated;
4532
- },
4533
- [translateFn]
4534
- );
4535
- const isCrudOperation = (0, import_react21.useCallback)((operation) => {
4536
- return ["create", "update", "delete"].includes(operation);
4537
- }, []);
4538
- const shouldShowSuccessNotification = (0, import_react21.useCallback)(
4539
- (operation, moduleKey) => {
4540
- if (!showSuccessNotifications) return false;
4541
- if (isCrudOperation(operation) && moduleKey) return true;
4542
- return appStructure.some((action) => action.key === operation);
4543
- },
4544
- [showSuccessNotifications, appStructure, isCrudOperation]
4545
- );
4546
- const getSuccessMessage = (0, import_react21.useCallback)(
4547
- (operation, moduleKey, actionConfig) => {
4548
- const operationKey = actionConfig?.key && typeof actionConfig.key === "string" ? actionConfig.key : operation;
4549
- const successKey = `action.onSuccess.${operationKey}`;
4550
- const successMessage = getSafeTranslation(successKey);
4551
- if (successMessage !== translateFn("error.unknown")) {
4552
- if (isCrudOperation(operationKey) && moduleKey) {
4553
- const itemNameKey = `action.${moduleKey}Singular`;
4554
- const itemName = getSafeTranslation(itemNameKey);
4555
- if (itemName !== translateFn("error.unknown")) {
4556
- return translateFn(successKey, { item: itemName });
4557
- } else {
4558
- const withoutItemKey = `action.onSuccess.${operationKey}WithoutItem`;
4559
- const withoutItemMessage = getSafeTranslation(withoutItemKey);
4560
- return withoutItemMessage !== translateFn("error.unknown") ? withoutItemMessage : successMessage;
4561
- }
4562
- }
4563
- return successMessage;
4564
- }
4565
- return translateFn("success.transaction");
4566
- },
4567
- [getSafeTranslation, translateFn, isCrudOperation]
4568
- );
4569
- const getErrorMessage2 = (0, import_react21.useCallback)(
4570
- (response) => {
4571
- if (response.errorCode && customErrorMessages[response.errorCode]) {
4572
- return customErrorMessages[response.errorCode];
4573
- }
4574
- if (response.errorCode && ERROR_TRANSLATION_MAP[response.errorCode]) {
4575
- return getSafeTranslation(ERROR_TRANSLATION_MAP[response.errorCode]);
4576
- }
4577
- if (response.errorCode) {
4578
- const possibleKeys = [
4579
- `errors.auth.${response.errorCode}`,
4580
- `errors.data.${response.errorCode}`,
4581
- `errors.system.${response.errorCode}`,
4582
- `errors.${response.errorCode}`
4583
- ];
4584
- for (const key of possibleKeys) {
4585
- const translated = getSafeTranslation(key);
4586
- if (translated !== translateFn("error.unknown")) {
4587
- return translated;
4588
- }
4589
- }
4590
- }
4591
- if (typeof response.data === "string" && response.data.startsWith("errors.")) {
4592
- const translated = getSafeTranslation(response.data);
4593
- if (translated !== translateFn("error.unknown")) {
4594
- return translated;
4595
- }
4596
- }
4597
- if (response.errors && Object.keys(response.errors).length > 0) {
4598
- const errorFields = Object.keys(response.errors);
4599
- if (errorFields.length === 1 && errorFields[0] === "_transaction") {
4600
- const transactionErrors = response.errors["_transaction"];
4601
- if (transactionErrors?.includes("ONE_OR_MORE_OPERATIONS_FAILED")) {
4602
- return "";
4603
- }
4604
- if (Array.isArray(transactionErrors) && transactionErrors.length > 0) {
4605
- const firstError = transactionErrors[0];
4606
- if (typeof firstError === "string" && firstError !== "ONE_OR_MORE_OPERATIONS_FAILED") {
4607
- try {
4608
- const parsed = JSON.parse(firstError);
4609
- if (Array.isArray(parsed) && parsed.length > 0) {
4610
- const firstTransactionError = parsed[0];
4611
- if (firstTransactionError?.response?.errorCode) {
4612
- const errorCode = firstTransactionError.response.errorCode;
4613
- if (ERROR_TRANSLATION_MAP[errorCode]) {
4614
- return getSafeTranslation(ERROR_TRANSLATION_MAP[errorCode]);
4615
- }
4616
- const possibleKeys = [
4617
- `errors.auth.${errorCode}`,
4618
- `errors.data.${errorCode}`,
4619
- `errors.system.${errorCode}`,
4620
- `errors.${errorCode}`
4621
- ];
4622
- for (const key of possibleKeys) {
4623
- const translated = getSafeTranslation(key);
4624
- if (translated !== getSafeTranslation("error.unknown")) {
4625
- return translated;
4626
- }
4627
- }
4628
- }
4629
- if (firstTransactionError?.response?.data) {
4630
- return firstTransactionError.response.data;
4631
- }
4632
- }
4633
- if (parsed?.response?.message) {
4634
- const errorMsg = parsed.response.message.toLowerCase();
4635
- if (errorMsg.includes("expired")) {
4636
- return getSafeTranslation("resetPassword.linkExpired", "El enlace ha expirado");
4637
- } else if (errorMsg.includes("invalid")) {
4638
- return getSafeTranslation("resetPassword.invalidCode", "C\xF3digo inv\xE1lido");
4639
- }
4640
- return parsed.response.message;
4641
- }
4642
- } catch {
4643
- if (firstError.toLowerCase().includes("expired")) {
4644
- return getSafeTranslation("resetPassword.linkExpired", "El enlace ha expirado");
4645
- } else if (firstError.toLowerCase().includes("invalid")) {
4646
- return getSafeTranslation("resetPassword.invalidCode", "C\xF3digo inv\xE1lido");
4647
- }
4648
- return firstError;
4649
- }
4650
- }
4651
- }
4652
- return getSafeTranslation("error.transaction", "Error en la operaci\xF3n");
4653
- }
4654
- if (errorFields.length === 1 && errorFields[0] === "_error") {
4655
- const errorMessages = response.errors["_error"];
4656
- return Array.isArray(errorMessages) ? errorMessages[0] : String(errorMessages);
4657
- }
4658
- if (errorFields.length === 1 && errorFields[0] === "_graphql") {
4659
- return getSafeTranslation("errors.system.DATABASE_CONNECTION_ERROR");
4660
- }
4661
- return `${getSafeTranslation("errors.data.FIELD_ERROR")}: ${errorFields.join(", ")}`;
4662
- }
4663
- return defaultErrorMessage || translateFn("error.unknown");
4664
- },
4665
- [customErrorMessages, defaultErrorMessage, translateFn, getSafeTranslation]
4666
- );
4667
- const getErrorSeverity = (0, import_react21.useCallback)((response) => {
4668
- if (response.errorCode && ERROR_SEVERITY_MAP2[response.errorCode]) {
4669
- return ERROR_SEVERITY_MAP2[response.errorCode];
4670
- }
4671
- return "error";
4672
- }, []);
4673
- const createItem = (0, import_react21.useCallback)(
4674
- async (moduleKey, data, options2) => {
4675
- const response = await import_crudify_browser6.default.createItem(moduleKey, data, options2);
4676
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4677
- const message = getErrorMessage2(response);
4678
- const severity = getErrorSeverity(response);
4679
- showNotification(message, severity, { autoHideDuration });
4680
- } else if (response.success) {
4681
- const actionConfig = options2?.actionConfig;
4682
- const operation = actionConfig?.key || "create";
4683
- const effectiveModuleKey = actionConfig?.moduleKey || moduleKey;
4684
- if (shouldShowSuccessNotification(operation, effectiveModuleKey)) {
4685
- const message = getSuccessMessage(operation, effectiveModuleKey, actionConfig);
4686
- showNotification(message, "success", { autoHideDuration });
4687
- }
4688
- }
4689
- return response;
4690
- },
4691
- [
4692
- showErrorNotifications,
4693
- shouldShowSuccessNotification,
4694
- showNotification,
4695
- getErrorMessage2,
4696
- getErrorSeverity,
4697
- getSuccessMessage,
4698
- autoHideDuration,
4699
- shouldShowNotification
4700
- ]
4701
- );
4702
- const updateItem = (0, import_react21.useCallback)(
4703
- async (moduleKey, data, options2) => {
4704
- const response = await import_crudify_browser6.default.updateItem(moduleKey, data, options2);
4705
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4706
- const message = getErrorMessage2(response);
4707
- const severity = getErrorSeverity(response);
4708
- showNotification(message, severity, { autoHideDuration });
4709
- } else if (response.success) {
4710
- const actionConfig = options2?.actionConfig;
4711
- const operation = actionConfig?.key || "update";
4712
- const effectiveModuleKey = actionConfig?.moduleKey || moduleKey;
4713
- if (shouldShowSuccessNotification(operation, effectiveModuleKey)) {
4714
- const message = getSuccessMessage(operation, effectiveModuleKey, actionConfig);
4715
- showNotification(message, "success", { autoHideDuration });
4716
- }
4717
- }
4718
- return response;
4719
- },
4720
- [
4721
- showErrorNotifications,
4722
- shouldShowSuccessNotification,
4723
- showNotification,
4724
- getErrorMessage2,
4725
- getErrorSeverity,
4726
- getSuccessMessage,
4727
- autoHideDuration,
4728
- shouldShowNotification
4729
- ]
4730
- );
4731
- const deleteItem = (0, import_react21.useCallback)(
4732
- async (moduleKey, id, options2) => {
4733
- const response = await import_crudify_browser6.default.deleteItem(moduleKey, id, options2);
4734
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4735
- const message = getErrorMessage2(response);
4736
- const severity = getErrorSeverity(response);
4737
- showNotification(message, severity, { autoHideDuration });
4738
- } else if (response.success) {
4739
- const actionConfig = options2?.actionConfig;
4740
- const operation = actionConfig?.key || "delete";
4741
- const effectiveModuleKey = actionConfig?.moduleKey || moduleKey;
4742
- if (shouldShowSuccessNotification(operation, effectiveModuleKey)) {
4743
- const message = getSuccessMessage(operation, effectiveModuleKey, actionConfig);
4744
- showNotification(message, "success", { autoHideDuration });
4745
- }
4746
- }
4747
- return response;
4748
- },
4749
- [
4750
- showErrorNotifications,
4751
- shouldShowSuccessNotification,
4752
- showNotification,
4753
- getErrorMessage2,
4754
- getErrorSeverity,
4755
- getSuccessMessage,
4756
- autoHideDuration,
4757
- shouldShowNotification
4758
- ]
4759
- );
4760
- const readItem = (0, import_react21.useCallback)(
4761
- async (moduleKey, filter, options2) => {
4762
- const response = await import_crudify_browser6.default.readItem(moduleKey, filter, options2);
4763
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4764
- const message = getErrorMessage2(response);
4765
- const severity = getErrorSeverity(response);
4766
- showNotification(message, severity, { autoHideDuration });
4767
- }
4768
- return response;
4769
- },
4770
- [showErrorNotifications, showNotification, getErrorMessage2, getErrorSeverity, autoHideDuration, shouldShowNotification]
4771
- );
4772
- const readItems = (0, import_react21.useCallback)(
4773
- async (moduleKey, filter, options2) => {
4774
- const response = await import_crudify_browser6.default.readItems(moduleKey, filter, options2);
4775
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4776
- const message = getErrorMessage2(response);
4777
- const severity = getErrorSeverity(response);
4778
- showNotification(message, severity, { autoHideDuration });
4779
- }
4780
- return response;
4781
- },
4782
- [showErrorNotifications, showNotification, getErrorMessage2, getErrorSeverity, autoHideDuration, shouldShowNotification]
4783
- );
4784
- const transaction = (0, import_react21.useCallback)(
4785
- async (data, options2) => {
4786
- const response = await import_crudify_browser6.default.transaction(data, options2);
4787
- const skipNotifications = options2?.skipNotifications === true;
4788
- if (!skipNotifications && !response.success && showErrorNotifications && shouldShowNotification(response)) {
4789
- const message = getErrorMessage2(response);
4790
- const severity = getErrorSeverity(response);
4791
- showNotification(message, severity, { autoHideDuration });
4792
- } else if (!skipNotifications && response.success) {
4793
- let operation = "transaction";
4794
- let moduleKey;
4795
- let actionConfig = null;
4796
- if (options2?.actionConfig) {
4797
- actionConfig = options2.actionConfig;
4798
- operation = actionConfig.key;
4799
- moduleKey = actionConfig.moduleKey;
4800
- } else if (Array.isArray(data) && data.length > 0 && data[0].operation) {
4801
- operation = data[0].operation;
4802
- actionConfig = appStructure.find((action) => action.key === operation);
4803
- if (actionConfig) {
4804
- moduleKey = actionConfig.moduleKey;
4805
- }
4806
- }
4807
- if (shouldShowSuccessNotification(operation, moduleKey)) {
4808
- const message = getSuccessMessage(operation, moduleKey, actionConfig);
4809
- showNotification(message, "success", { autoHideDuration });
4810
- }
4811
- }
4812
- return response;
4813
- },
4814
- [
4815
- showErrorNotifications,
4816
- shouldShowSuccessNotification,
4817
- showNotification,
4818
- getErrorMessage2,
4819
- getErrorSeverity,
4820
- getSuccessMessage,
4821
- autoHideDuration,
4822
- shouldShowNotification,
4823
- appStructure
4824
- ]
4825
- );
4826
- const handleResponse = (0, import_react21.useCallback)(
4827
- (response, successMessage) => {
4828
- if (!response.success && showErrorNotifications && shouldShowNotification(response)) {
4829
- const message = getErrorMessage2(response);
4830
- const severity = getErrorSeverity(response);
4831
- showNotification(message, severity, { autoHideDuration });
4832
- } else if (response.success && showSuccessNotifications && successMessage) {
4833
- showNotification(successMessage, "success", { autoHideDuration });
4834
- }
4835
- return response;
4836
- },
4837
- [
4838
- showErrorNotifications,
4839
- showSuccessNotifications,
4840
- showNotification,
4841
- getErrorMessage2,
4842
- getErrorSeverity,
4843
- autoHideDuration,
4844
- shouldShowNotification,
4845
- translateFn
4846
- ]
4847
- );
4848
- return {
4849
- // Métodos de crudify con notificaciones automáticas
4850
- createItem,
4851
- updateItem,
4852
- deleteItem,
4853
- readItem,
4854
- readItems,
4855
- transaction,
4856
- // Método genérico para manejar respuestas
4857
- handleResponse,
4858
- // Funciones de utilidad
4859
- getErrorMessage: getErrorMessage2,
4860
- getErrorSeverity,
4861
- shouldShowNotification
4862
- };
4863
- };
4864
- // Annotate the CommonJS export names for ESM import in node:
4865
- 0 && (module.exports = {
4866
- CrudifyLogin,
4867
- ERROR_CODES,
4868
- ERROR_SEVERITY_MAP,
4869
- GlobalNotificationProvider,
4870
- LoginComponent,
4871
- POLICY_ACTIONS,
4872
- PREFERRED_POLICY_ORDER,
4873
- Policies,
4874
- ProtectedRoute,
4875
- SessionDebugInfo,
4876
- SessionManager,
4877
- SessionProvider,
4878
- SessionStatus,
4879
- TokenStorage,
4880
- UserProfileDisplay,
4881
- createErrorTranslator,
4882
- crudify,
4883
- decodeJwtSafely,
4884
- getCookie,
4885
- getCurrentUserEmail,
4886
- getErrorMessage,
4887
- handleCrudifyError,
4888
- isTokenExpired,
4889
- parseApiError,
4890
- parseJavaScriptError,
4891
- parseTransactionError,
4892
- secureLocalStorage,
4893
- secureSessionStorage,
4894
- translateError,
4895
- translateErrorCode,
4896
- translateErrorCodes,
4897
- useAuth,
4898
- useCrudifyWithNotifications,
4899
- useData,
4900
- useGlobalNotification,
4901
- useSession,
4902
- useSessionContext,
4903
- useUserData,
4904
- useUserProfile,
4905
- ...require("@nocios/crudify-browser")
4906
- });
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _createStarExport(obj) { Object.keys(obj) .filter((key) => key !== "default" && key !== "__esModule") .forEach((key) => { if (exports.hasOwnProperty(key)) { return; } Object.defineProperty(exports, key, {enumerable: true, configurable: true, get: () => obj[key]}); }); }var _chunk2IJSKTGWjs = require('./chunk-2IJSKTGW.js');var _chunkYZZ6A6CRjs = require('./chunk-YZZ6A6CR.js');var _chunkEP4KANK7js = require('./chunk-EP4KANK7.js');var _chunkNNY4A73Vjs = require('./chunk-NNY4A73V.js');var _chunkYIIUEOXCjs = require('./chunk-YIIUEOXC.js');var _chunk6EBMA4HZjs = require('./chunk-6EBMA4HZ.js');var _crudifybrowser = require('@nocios/crudify-browser'); var _crudifybrowser2 = _interopRequireDefault(_crudifybrowser); _createStarExport(_crudifybrowser);exports.CrudifyLogin = _chunk2IJSKTGWjs.a; exports.ERROR_CODES = _chunkYIIUEOXCjs.a; exports.ERROR_SEVERITY_MAP = _chunkYIIUEOXCjs.b; exports.GlobalNotificationProvider = _chunkEP4KANK7js.d; exports.LoginComponent = _chunk2IJSKTGWjs.f; exports.POLICY_ACTIONS = _chunk2IJSKTGWjs.c; exports.PREFERRED_POLICY_ORDER = _chunk2IJSKTGWjs.d; exports.Policies = _chunk2IJSKTGWjs.e; exports.ProtectedRoute = _chunkEP4KANK7js.h; exports.SessionDebugInfo = _chunkEP4KANK7js.i; exports.SessionManager = _chunkEP4KANK7js.b; exports.SessionProvider = _chunkEP4KANK7js.f; exports.SessionStatus = _chunk2IJSKTGWjs.g; exports.TokenStorage = _chunkEP4KANK7js.a; exports.UserProfileDisplay = _chunk2IJSKTGWjs.b; exports.createErrorTranslator = _chunk6EBMA4HZjs.e; exports.crudify = _crudifybrowser2.default; exports.decodeJwtSafely = _chunk6EBMA4HZjs.f; exports.getCookie = _chunk6EBMA4HZjs.a; exports.getCurrentUserEmail = _chunk6EBMA4HZjs.g; exports.getErrorMessage = _chunkYIIUEOXCjs.e; exports.handleCrudifyError = _chunkYIIUEOXCjs.g; exports.isTokenExpired = _chunk6EBMA4HZjs.h; exports.parseApiError = _chunkYIIUEOXCjs.c; exports.parseJavaScriptError = _chunkYIIUEOXCjs.f; exports.parseTransactionError = _chunkYIIUEOXCjs.d; exports.secureLocalStorage = _chunkNNY4A73Vjs.b; exports.secureSessionStorage = _chunkNNY4A73Vjs.a; exports.translateError = _chunk6EBMA4HZjs.d; exports.translateErrorCode = _chunk6EBMA4HZjs.b; exports.translateErrorCodes = _chunk6EBMA4HZjs.c; exports.useAuth = _chunkYZZ6A6CRjs.b; exports.useCrudifyWithNotifications = _chunkYZZ6A6CRjs.d; exports.useData = _chunkYZZ6A6CRjs.c; exports.useGlobalNotification = _chunkEP4KANK7js.e; exports.useSession = _chunkEP4KANK7js.c; exports.useSessionContext = _chunkEP4KANK7js.g; exports.useUserData = _chunkYZZ6A6CRjs.a; exports.useUserProfile = _chunkEP4KANK7js.j;