@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/README.md +12 -0
- package/dist/GlobalNotificationProvider-C3iWgM1z.d.mts +35 -0
- package/dist/GlobalNotificationProvider-C3iWgM1z.d.ts +35 -0
- package/dist/api-Djqihi4n.d.mts +82 -0
- package/dist/api-Djqihi4n.d.ts +82 -0
- package/dist/chunk-2IJSKTGW.js +1 -0
- package/dist/chunk-6EBMA4HZ.js +1 -0
- package/dist/chunk-BJ6PIVZR.mjs +1 -0
- package/dist/chunk-EP4KANK7.js +1 -0
- package/dist/chunk-JFXC3E4B.mjs +1 -0
- package/dist/chunk-NNY4A73V.js +1 -0
- package/dist/chunk-PVQVPSNT.mjs +1 -0
- package/dist/chunk-T2CPA46I.mjs +1 -0
- package/dist/chunk-TKYA4Q4U.mjs +1 -0
- package/dist/chunk-YIIUEOXC.js +1 -0
- package/dist/chunk-YS3C7YG5.mjs +1 -0
- package/dist/chunk-YZZ6A6CR.js +1 -0
- package/dist/components.d.mts +4 -0
- package/dist/components.d.ts +4 -0
- package/dist/components.js +1 -0
- package/dist/components.mjs +1 -0
- package/dist/hooks.d.mts +5 -0
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.js +1 -0
- package/dist/hooks.mjs +1 -0
- package/dist/index-B2ZtMz3v.d.ts +433 -0
- package/dist/index-CY6Qkw3q.d.mts +78 -0
- package/dist/index-CoCUhX7W.d.mts +433 -0
- package/dist/index-DxFMT2hN.d.ts +78 -0
- package/dist/index.d.mts +8 -732
- package/dist/index.d.ts +8 -732
- package/dist/index.js +1 -4906
- package/dist/index.mjs +1 -4890
- package/dist/utils.d.mts +124 -0
- package/dist/utils.d.ts +124 -0
- package/dist/utils.js +1 -0
- package/dist/utils.mjs +1 -0
- package/package.json +24 -14
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;
|