@nocios/crudify-ui 3.0.10 → 3.0.14

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.
Files changed (3) hide show
  1. package/dist/index.js +1784 -1774
  2. package/dist/index.mjs +1784 -1774
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -456,1910 +456,1920 @@ var useLoginState = () => {
456
456
  return context;
457
457
  };
458
458
 
459
- // src/components/CrudifyLogin/Forms/LoginForm.tsx
459
+ // src/providers/SessionProvider.tsx
460
+ var import_react6 = require("react");
461
+
462
+ // src/hooks/useSession.ts
460
463
  var import_react5 = require("react");
461
- var import_material = require("@mui/material");
462
464
 
463
- // src/utils/errorHandler.ts
464
- var ERROR_CODES = {
465
- // Authentication Errors
466
- INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
467
- UNAUTHORIZED: "UNAUTHORIZED",
468
- INVALID_API_KEY: "INVALID_API_KEY",
469
- USER_NOT_FOUND: "USER_NOT_FOUND",
470
- USER_NOT_ACTIVE: "USER_NOT_ACTIVE",
471
- NO_PERMISSION: "NO_PERMISSION",
472
- // Data Errors
473
- ITEM_NOT_FOUND: "ITEM_NOT_FOUND",
474
- NOT_FOUND: "NOT_FOUND",
475
- IN_USE: "IN_USE",
476
- // Validation Errors
477
- FIELD_ERROR: "FIELD_ERROR",
478
- BAD_REQUEST: "BAD_REQUEST",
479
- INVALID_EMAIL: "INVALID_EMAIL",
480
- INVALID_CODE: "INVALID_CODE",
481
- // System Errors
482
- INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR",
483
- DATABASE_CONNECTION_ERROR: "DATABASE_CONNECTION_ERROR",
484
- INVALID_CONFIGURATION: "INVALID_CONFIGURATION",
485
- UNKNOWN_OPERATION: "UNKNOWN_OPERATION",
486
- // Rate Limiting
487
- TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
488
- // Network Errors
489
- NETWORK_ERROR: "NETWORK_ERROR",
490
- TIMEOUT_ERROR: "TIMEOUT_ERROR"
491
- };
492
- var ERROR_SEVERITY_MAP = {
493
- // Authentication - warning (user can fix)
494
- [ERROR_CODES.INVALID_CREDENTIALS]: "warning",
495
- [ERROR_CODES.UNAUTHORIZED]: "warning",
496
- [ERROR_CODES.INVALID_API_KEY]: "error",
497
- [ERROR_CODES.USER_NOT_FOUND]: "warning",
498
- [ERROR_CODES.USER_NOT_ACTIVE]: "warning",
499
- [ERROR_CODES.NO_PERMISSION]: "warning",
500
- // Data - info (might be expected)
501
- [ERROR_CODES.ITEM_NOT_FOUND]: "info",
502
- [ERROR_CODES.NOT_FOUND]: "info",
503
- [ERROR_CODES.IN_USE]: "warning",
504
- // Validation - warning (user input issue)
505
- [ERROR_CODES.FIELD_ERROR]: "warning",
506
- [ERROR_CODES.BAD_REQUEST]: "warning",
507
- [ERROR_CODES.INVALID_EMAIL]: "warning",
508
- [ERROR_CODES.INVALID_CODE]: "warning",
509
- // System - error (server issue)
510
- [ERROR_CODES.INTERNAL_SERVER_ERROR]: "error",
511
- [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "error",
512
- [ERROR_CODES.INVALID_CONFIGURATION]: "error",
513
- [ERROR_CODES.UNKNOWN_OPERATION]: "error",
514
- // Rate limiting - warning with higher duration
515
- [ERROR_CODES.TOO_MANY_REQUESTS]: "warning",
516
- // Network - error
517
- [ERROR_CODES.NETWORK_ERROR]: "error",
518
- [ERROR_CODES.TIMEOUT_ERROR]: "error"
519
- };
520
- function parseApiError(response) {
521
- const errors = [];
522
- try {
523
- const apiResponse = response;
524
- if (apiResponse.data && typeof apiResponse.data === "object") {
525
- const responseData = apiResponse.data;
526
- if (responseData.response) {
527
- const { status, fieldsWarning } = responseData.response;
528
- if (fieldsWarning && typeof fieldsWarning === "object") {
529
- Object.entries(fieldsWarning).forEach(([field, messages]) => {
530
- if (Array.isArray(messages) && messages.length > 0) {
531
- errors.push({
532
- code: ERROR_CODES.FIELD_ERROR,
533
- message: messages[0],
534
- severity: "warning",
535
- field
536
- });
537
- }
538
- });
539
- }
540
- if (status && typeof status === "string") {
541
- const errorCode = status;
542
- if (ERROR_SEVERITY_MAP[errorCode]) {
543
- errors.push({
544
- code: errorCode,
545
- message: getErrorMessage(errorCode),
546
- severity: ERROR_SEVERITY_MAP[errorCode]
547
- });
548
- }
549
- }
550
- }
551
- }
552
- if (apiResponse.errors) {
553
- if (typeof apiResponse.errors === "string") {
554
- errors.push({
555
- code: ERROR_CODES.BAD_REQUEST,
556
- message: apiResponse.errors,
557
- severity: "warning"
558
- });
559
- } else if (typeof apiResponse.errors === "object") {
560
- const errorObj = apiResponse.errors;
561
- Object.entries(errorObj).forEach(([field, messages]) => {
562
- if (Array.isArray(messages) && messages.length > 0) {
563
- if (field === "_error") {
564
- messages.forEach((msg) => {
565
- const errorCode = typeof msg === "string" && isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
566
- errors.push({
567
- code: errorCode,
568
- message: typeof msg === "string" ? msg : getErrorMessage(errorCode),
569
- severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
570
- });
571
- });
572
- } else if (field === "_graphql") {
573
- messages.forEach((msg) => {
574
- if (typeof msg === "string") {
575
- const errorCode = isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
576
- errors.push({
577
- code: errorCode,
578
- message: getErrorMessage(errorCode),
579
- severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
580
- });
581
- }
582
- });
583
- } else {
584
- errors.push({
585
- code: ERROR_CODES.FIELD_ERROR,
586
- message: typeof messages[0] === "string" ? messages[0] : "Validation error",
587
- severity: "warning",
588
- field
589
- });
590
- }
591
- }
592
- });
593
- }
465
+ // src/core/SessionManager.ts
466
+ var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
467
+
468
+ // src/utils/tokenStorage.ts
469
+ var import_crypto_js = __toESM(require("crypto-js"));
470
+ var _TokenStorage = class _TokenStorage {
471
+ /**
472
+ * Configurar tipo de almacenamiento
473
+ */
474
+ static setStorageType(type) {
475
+ _TokenStorage.storageType = type;
476
+ }
477
+ /**
478
+ * Verificar si el storage está disponible
479
+ */
480
+ static isStorageAvailable(type) {
481
+ try {
482
+ const storage = window[type];
483
+ const testKey = "__storage_test__";
484
+ storage.setItem(testKey, "test");
485
+ storage.removeItem(testKey);
486
+ return true;
487
+ } catch {
488
+ return false;
594
489
  }
595
- if (errors.length === 0 && apiResponse.success === false) {
596
- errors.push({
597
- code: ERROR_CODES.BAD_REQUEST,
598
- message: "Request failed",
599
- severity: "warning"
600
- });
490
+ }
491
+ /**
492
+ * Obtener instancia de storage
493
+ */
494
+ static getStorage() {
495
+ if (_TokenStorage.storageType === "none") return null;
496
+ if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
497
+ console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
498
+ return null;
601
499
  }
602
- } catch (error) {
603
- errors.push({
604
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
605
- message: "Failed to parse error response",
606
- severity: "error",
607
- details: { originalError: error }
608
- });
500
+ return window[_TokenStorage.storageType];
609
501
  }
610
- return errors.length > 0 ? errors : [
611
- {
612
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
613
- message: "Unknown error occurred",
614
- severity: "error"
502
+ /**
503
+ * Encriptar datos sensibles
504
+ */
505
+ static encrypt(data) {
506
+ try {
507
+ return import_crypto_js.default.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
508
+ } catch (error) {
509
+ console.error("Crudify: Encryption failed", error);
510
+ return data;
615
511
  }
616
- ];
617
- }
618
- function parseTransactionError(response) {
619
- try {
620
- const transactionResponse = response;
621
- if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
622
- const errors = [];
623
- transactionResponse.data.forEach((item, index) => {
624
- if (item.response?.status === "TOO_MANY_REQUESTS") {
625
- errors.push({
626
- code: ERROR_CODES.TOO_MANY_REQUESTS,
627
- message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
628
- severity: "warning",
629
- details: { transactionIndex: index }
630
- });
631
- } else if (!item.response || item.response.status !== "OK") {
632
- errors.push({
633
- code: ERROR_CODES.BAD_REQUEST,
634
- message: "Transaction failed",
635
- severity: "warning",
636
- details: { transactionIndex: index, response: item.response }
637
- });
638
- }
639
- });
640
- return errors;
512
+ }
513
+ /**
514
+ * Desencriptar datos
515
+ */
516
+ static decrypt(encryptedData) {
517
+ try {
518
+ const bytes = import_crypto_js.default.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
519
+ const decrypted = bytes.toString(import_crypto_js.default.enc.Utf8);
520
+ return decrypted || encryptedData;
521
+ } catch (error) {
522
+ console.error("Crudify: Decryption failed", error);
523
+ return encryptedData;
641
524
  }
642
- return parseApiError(response);
643
- } catch (error) {
644
- return [
645
- {
646
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
647
- message: "Failed to parse transaction error",
648
- severity: "error",
649
- details: { originalError: error }
650
- }
651
- ];
652
525
  }
653
- }
654
- function isValidErrorCode(code) {
655
- return Object.values(ERROR_CODES).includes(code);
656
- }
657
- function getErrorMessage(code) {
658
- const messages = {
659
- [ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
660
- [ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
661
- [ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
662
- [ERROR_CODES.USER_NOT_FOUND]: "User not found",
663
- [ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
664
- [ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
665
- [ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
666
- [ERROR_CODES.NOT_FOUND]: "Resource not found",
667
- [ERROR_CODES.IN_USE]: "Resource is currently in use",
668
- [ERROR_CODES.FIELD_ERROR]: "Validation error",
669
- [ERROR_CODES.BAD_REQUEST]: "Invalid request",
670
- [ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
671
- [ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
672
- [ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
673
- [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
674
- [ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
675
- [ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
676
- [ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
677
- [ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
678
- [ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
679
- };
680
- return messages[code] || "An unknown error occurred";
681
- }
682
- function parseJavaScriptError(error) {
683
- if (error instanceof Error) {
684
- if (error.name === "AbortError") {
685
- return {
686
- code: ERROR_CODES.TIMEOUT_ERROR,
687
- message: "Request was cancelled",
688
- severity: "info"
526
+ /**
527
+ * Guardar tokens de forma segura
528
+ */
529
+ static saveTokens(tokens) {
530
+ const storage = _TokenStorage.getStorage();
531
+ if (!storage) return;
532
+ try {
533
+ const tokenData = {
534
+ accessToken: tokens.accessToken,
535
+ refreshToken: tokens.refreshToken,
536
+ expiresAt: tokens.expiresAt,
537
+ refreshExpiresAt: tokens.refreshExpiresAt,
538
+ savedAt: Date.now()
689
539
  };
540
+ const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
541
+ storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
542
+ console.debug("Crudify: Tokens saved successfully");
543
+ } catch (error) {
544
+ console.error("Crudify: Failed to save tokens", error);
690
545
  }
691
- if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
546
+ }
547
+ /**
548
+ * Obtener tokens guardados
549
+ */
550
+ static getTokens() {
551
+ const storage = _TokenStorage.getStorage();
552
+ if (!storage) return null;
553
+ try {
554
+ const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
555
+ if (!encrypted) return null;
556
+ const decrypted = _TokenStorage.decrypt(encrypted);
557
+ const tokenData = JSON.parse(decrypted);
558
+ if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
559
+ console.warn("Crudify: Incomplete token data found, clearing storage");
560
+ _TokenStorage.clearTokens();
561
+ return null;
562
+ }
563
+ if (Date.now() >= tokenData.refreshExpiresAt) {
564
+ console.info("Crudify: Refresh token expired, clearing storage");
565
+ _TokenStorage.clearTokens();
566
+ return null;
567
+ }
692
568
  return {
693
- code: ERROR_CODES.NETWORK_ERROR,
694
- message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
695
- severity: "error"
569
+ accessToken: tokenData.accessToken,
570
+ refreshToken: tokenData.refreshToken,
571
+ expiresAt: tokenData.expiresAt,
572
+ refreshExpiresAt: tokenData.refreshExpiresAt
696
573
  };
574
+ } catch (error) {
575
+ console.error("Crudify: Failed to retrieve tokens", error);
576
+ _TokenStorage.clearTokens();
577
+ return null;
578
+ }
579
+ }
580
+ /**
581
+ * Limpiar tokens almacenados
582
+ */
583
+ static clearTokens() {
584
+ const storage = _TokenStorage.getStorage();
585
+ if (!storage) return;
586
+ try {
587
+ storage.removeItem(_TokenStorage.TOKEN_KEY);
588
+ console.debug("Crudify: Tokens cleared from storage");
589
+ } catch (error) {
590
+ console.error("Crudify: Failed to clear tokens", error);
697
591
  }
592
+ }
593
+ /**
594
+ * Verificar si hay tokens válidos guardados
595
+ */
596
+ static hasValidTokens() {
597
+ const tokens = _TokenStorage.getTokens();
598
+ return tokens !== null;
599
+ }
600
+ /**
601
+ * Obtener información de expiración
602
+ */
603
+ static getExpirationInfo() {
604
+ const tokens = _TokenStorage.getTokens();
605
+ if (!tokens) return null;
606
+ const now = Date.now();
698
607
  return {
699
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
700
- message: error.message || "An unexpected error occurred",
701
- severity: "error",
702
- details: { originalError: error }
608
+ accessExpired: now >= tokens.expiresAt,
609
+ refreshExpired: now >= tokens.refreshExpiresAt,
610
+ accessExpiresIn: Math.max(0, tokens.expiresAt - now),
611
+ refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
703
612
  };
704
613
  }
705
- return {
706
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
707
- message: "An unknown error occurred",
708
- severity: "error",
709
- details: { originalError: error }
710
- };
711
- }
712
- function handleCrudifyError(error) {
713
- if (error instanceof Error) {
714
- return [parseJavaScriptError(error)];
715
- }
716
- if (typeof error === "object" && error !== null) {
717
- const response = error;
718
- if (response.data && Array.isArray(response.data)) {
719
- return parseTransactionError(error);
614
+ /**
615
+ * Actualizar solo el access token (después de refresh)
616
+ */
617
+ static updateAccessToken(newAccessToken, newExpiresAt) {
618
+ const existingTokens = _TokenStorage.getTokens();
619
+ if (!existingTokens) {
620
+ console.warn("Crudify: Cannot update access token, no existing tokens found");
621
+ return;
720
622
  }
721
- return parseApiError(error);
623
+ _TokenStorage.saveTokens({
624
+ ...existingTokens,
625
+ accessToken: newAccessToken,
626
+ expiresAt: newExpiresAt
627
+ });
722
628
  }
723
- return [
724
- {
725
- code: ERROR_CODES.INTERNAL_SERVER_ERROR,
726
- message: "An unknown error occurred",
727
- severity: "error",
728
- details: { originalError: error }
729
- }
730
- ];
731
- }
629
+ };
630
+ _TokenStorage.TOKEN_KEY = "crudify_tokens";
631
+ _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
632
+ _TokenStorage.storageType = "localStorage";
633
+ var TokenStorage = _TokenStorage;
732
634
 
733
- // src/components/CrudifyLogin/Forms/LoginForm.tsx
734
- var import_jsx_runtime4 = require("react/jsx-runtime");
735
- var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
736
- const { crudify: crudify6 } = useCrudify();
737
- const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
738
- const { t } = useTranslation();
739
- const usernameInputRef = (0, import_react5.useRef)(null);
740
- const getRedirectUrl = () => {
741
- if (state.searchParams.redirect) {
742
- try {
743
- const decodedPath = decodeURIComponent(state.searchParams.redirect);
744
- if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
745
- return decodedPath;
746
- }
747
- } catch (error) {
748
- }
749
- }
750
- return redirectUrl || "/";
751
- };
752
- (0, import_react5.useEffect)(() => {
753
- const timer = setTimeout(() => {
754
- if (usernameInputRef.current) usernameInputRef.current.focus();
755
- }, 100);
756
- return () => clearTimeout(timer);
757
- }, []);
758
- const translateError = (parsedError) => {
759
- const possibleKeys = [
760
- `errors.auth.${parsedError.code}`,
761
- `errors.data.${parsedError.code}`,
762
- `errors.system.${parsedError.code}`,
763
- `errors.${parsedError.code}`,
764
- `login.${parsedError.code.toLowerCase()}`
765
- ];
766
- for (const key of possibleKeys) {
767
- const translated = t(key);
768
- if (translated !== key) {
769
- return translated;
770
- }
635
+ // src/core/SessionManager.ts
636
+ var SessionManager = class _SessionManager {
637
+ constructor() {
638
+ this.config = {};
639
+ this.initialized = false;
640
+ }
641
+ static getInstance() {
642
+ if (!_SessionManager.instance) {
643
+ _SessionManager.instance = new _SessionManager();
771
644
  }
772
- return parsedError.message || t("error.unknown");
773
- };
774
- const handleLogin = async () => {
775
- if (state.loading) return;
776
- if (!state.formData.username.trim()) {
777
- setFieldError("username", t("login.usernameRequired"));
645
+ return _SessionManager.instance;
646
+ }
647
+ /**
648
+ * Inicializar el SessionManager
649
+ */
650
+ async initialize(config = {}) {
651
+ if (this.initialized) {
652
+ console.warn("SessionManager: Already initialized");
778
653
  return;
779
654
  }
780
- if (!state.formData.password.trim()) {
781
- setFieldError("password", t("login.passwordRequired"));
782
- return;
655
+ this.config = {
656
+ storageType: "localStorage",
657
+ autoRestore: true,
658
+ enableLogging: false,
659
+ ...config
660
+ };
661
+ TokenStorage.setStorageType(this.config.storageType || "localStorage");
662
+ if (this.config.enableLogging) {
783
663
  }
784
- clearErrors();
785
- setLoading(true);
664
+ if (this.config.autoRestore) {
665
+ await this.restoreSession();
666
+ }
667
+ this.initialized = true;
668
+ this.log("SessionManager initialized successfully");
669
+ }
670
+ /**
671
+ * Login con persistencia automática
672
+ */
673
+ async login(email, password) {
786
674
  try {
787
- if (!crudify6) {
788
- throw new Error("Crudify not initialized");
789
- }
790
- const response = await crudify6.login(state.formData.username, state.formData.password);
791
- setLoading(false);
792
- if (response.success) {
793
- console.log("\u{1F510} LoginForm - Login successful, calling onLoginSuccess");
794
- const finalRedirectUrl = getRedirectUrl();
795
- if (onLoginSuccess) {
796
- onLoginSuccess(response.data, finalRedirectUrl);
797
- }
798
- } else {
799
- handleLoginError(response);
675
+ this.log("Attempting login...");
676
+ const response = await import_crudify_browser2.default.login(email, password);
677
+ if (!response.success) {
678
+ this.log("Login failed:", response.errors);
679
+ return {
680
+ success: false,
681
+ error: this.formatError(response.errors)
682
+ };
800
683
  }
684
+ const tokens = {
685
+ accessToken: response.data.token,
686
+ refreshToken: response.data.refreshToken,
687
+ expiresAt: response.data.expiresAt,
688
+ refreshExpiresAt: response.data.refreshExpiresAt
689
+ };
690
+ TokenStorage.saveTokens(tokens);
691
+ this.log("Login successful, tokens saved");
692
+ this.config.onLoginSuccess?.(tokens);
693
+ return {
694
+ success: true,
695
+ tokens
696
+ };
801
697
  } catch (error) {
802
- setLoading(false);
803
- const parsedErrors = handleCrudifyError(error);
804
- const translatedErrors = parsedErrors.map(translateError);
805
- setFieldError("global", translatedErrors);
806
- if (onError) {
807
- onError(translatedErrors.join(", "));
808
- }
809
- }
810
- };
811
- const handleLoginError = (response) => {
812
- const parsedErrors = handleCrudifyError(response);
813
- parsedErrors.forEach((error) => {
814
- if (error.field) {
815
- setFieldError(error.field, translateError(error));
816
- } else {
817
- const currentGlobalErrors = state.errors.global || [];
818
- setFieldError("global", [...currentGlobalErrors, translateError(error)]);
819
- }
820
- });
821
- };
822
- const handleSubmit = (e) => {
823
- e.preventDefault();
824
- handleLogin();
825
- };
826
- const handleKeyDown = (e) => {
827
- if (e.key === "Enter" && !state.loading) {
828
- e.preventDefault();
829
- handleLogin();
830
- }
831
- };
832
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
833
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
834
- import_material.Box,
835
- {
836
- component: "form",
837
- noValidate: true,
838
- onSubmit: handleSubmit,
839
- onKeyDown: handleKeyDown,
840
- sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
841
- children: [
842
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
843
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
844
- import_material.Typography,
845
- {
846
- variant: "body2",
847
- component: "label",
848
- htmlFor: "email",
849
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
850
- children: t("login.usernameOrEmailLabel")
851
- }
852
- ),
853
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
854
- import_material.TextField,
855
- {
856
- fullWidth: true,
857
- id: "email",
858
- name: "email",
859
- type: "email",
860
- value: state.formData.username,
861
- disabled: state.loading,
862
- onChange: (e) => updateFormData({ username: e.target.value }),
863
- error: !!state.errors.username,
864
- helperText: state.errors.username,
865
- autoComplete: "email",
866
- placeholder: t("login.usernameOrEmailPlaceholder"),
867
- inputRef: usernameInputRef,
868
- required: true
869
- }
870
- )
871
- ] }),
872
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
873
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
874
- import_material.Typography,
875
- {
876
- variant: "body2",
877
- component: "label",
878
- htmlFor: "password",
879
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
880
- children: t("login.passwordLabel")
881
- }
882
- ),
883
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
884
- import_material.TextField,
885
- {
886
- fullWidth: true,
887
- id: "password",
888
- name: "password",
889
- type: "password",
890
- value: state.formData.password,
891
- disabled: state.loading,
892
- onChange: (e) => updateFormData({ password: e.target.value }),
893
- error: !!state.errors.password,
894
- helperText: state.errors.password,
895
- autoComplete: "current-password",
896
- placeholder: t("login.passwordPlaceholder"),
897
- required: true
898
- }
899
- )
900
- ] }),
901
- state.config.loginActions?.includes("forgotPassword") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.Box, { sx: { display: "flex", justifyContent: "flex-end", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
902
- import_material.Link,
903
- {
904
- sx: { cursor: "pointer" },
905
- onClick: () => {
906
- onScreenChange?.("forgotPassword", state.searchParams);
907
- },
908
- variant: "body2",
909
- color: "secondary",
910
- children: t("login.forgotPasswordLink")
911
- }
912
- ) }),
913
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.Button, { disabled: state.loading, type: "submit", fullWidth: true, variant: "contained", color: "primary", sx: { mt: 1, mb: 2 }, children: state.loading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.CircularProgress, { size: 20 }) : t("login.loginButton") })
914
- ]
915
- }
916
- ),
917
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.Box, { children: state.errors.global && state.errors.global.length > 0 && state.errors.global.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_material.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: error }) }, index)) }),
918
- state.config.loginActions?.includes("createUser") && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_material.Typography, { variant: "body2", align: "center", sx: { color: "text.secondary", mt: 3 }, children: [
919
- t("login.noAccountPrompt"),
920
- " ",
921
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
922
- import_material.Link,
923
- {
924
- sx: { cursor: "pointer" },
925
- onClick: () => {
926
- const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
927
- const signupUrl = `/public/users/create${searchString}`;
928
- onExternalNavigate?.(signupUrl);
929
- },
930
- fontWeight: "medium",
931
- color: "secondary",
932
- children: t("login.signUpLink")
933
- }
934
- )
935
- ] })
936
- ] });
937
- };
938
- var LoginForm_default = LoginForm;
939
-
940
- // src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
941
- var import_react6 = require("react");
942
- var import_material2 = require("@mui/material");
943
- var import_jsx_runtime5 = require("react/jsx-runtime");
944
- var ForgotPasswordForm = ({ onScreenChange, onError }) => {
945
- const { crudify: crudify6 } = useCrudify();
946
- const [email, setEmail] = (0, import_react6.useState)("");
947
- const [loading, setLoading] = (0, import_react6.useState)(false);
948
- const [errors, setErrors] = (0, import_react6.useState)([]);
949
- const [helperTextEmail, setHelperTextEmail] = (0, import_react6.useState)(null);
950
- const [emailSent, setEmailSent] = (0, import_react6.useState)(false);
951
- const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react6.useState)(false);
952
- const { t } = useTranslation();
953
- const translateError = (parsedError) => {
954
- const possibleKeys = [
955
- `errors.auth.${parsedError.code}`,
956
- `errors.data.${parsedError.code}`,
957
- `errors.system.${parsedError.code}`,
958
- `errors.${parsedError.code}`,
959
- `forgotPassword.${parsedError.code.toLowerCase()}`
960
- ];
961
- for (const key of possibleKeys) {
962
- const translated = t(key);
963
- if (translated !== key) {
964
- return translated;
965
- }
966
- }
967
- return parsedError.message || t("error.unknown");
968
- };
969
- const validateEmail = (email2) => {
970
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
971
- return emailRegex.test(email2);
972
- };
973
- const handleSubmit = async () => {
974
- if (loading || !crudify6) return;
975
- setErrors([]);
976
- setHelperTextEmail(null);
977
- if (!email) {
978
- setHelperTextEmail(t("forgotPassword.emailRequired"));
979
- return;
698
+ this.log("Login error:", error);
699
+ return {
700
+ success: false,
701
+ error: error instanceof Error ? error.message : "Unknown error"
702
+ };
980
703
  }
981
- if (!validateEmail(email)) {
982
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
983
- return;
704
+ }
705
+ /**
706
+ * Logout con limpieza de tokens
707
+ */
708
+ async logout() {
709
+ try {
710
+ this.log("Logging out...");
711
+ await import_crudify_browser2.default.logout();
712
+ TokenStorage.clearTokens();
713
+ this.log("Logout successful");
714
+ this.config.onLogout?.();
715
+ } catch (error) {
716
+ this.log("Logout error:", error);
717
+ TokenStorage.clearTokens();
984
718
  }
985
- setLoading(true);
719
+ }
720
+ /**
721
+ * Restaurar sesión desde storage
722
+ */
723
+ async restoreSession() {
986
724
  try {
987
- const data = [{ operation: "requestPasswordReset", data: { email } }];
988
- const response = await crudify6.transaction(data);
989
- if (response.success) {
990
- if (response.data && response.data.existingCodeValid) {
991
- setCodeAlreadyExists(true);
992
- } else {
993
- setEmailSent(true);
725
+ this.log("Attempting to restore session...");
726
+ const savedTokens = TokenStorage.getTokens();
727
+ if (!savedTokens) {
728
+ this.log("No valid tokens found in storage");
729
+ return false;
730
+ }
731
+ import_crudify_browser2.default.setTokens({
732
+ accessToken: savedTokens.accessToken,
733
+ refreshToken: savedTokens.refreshToken,
734
+ expiresAt: savedTokens.expiresAt,
735
+ refreshExpiresAt: savedTokens.refreshExpiresAt
736
+ });
737
+ try {
738
+ const isValid = import_crudify_browser2.default.isLogin();
739
+ if (!isValid) {
740
+ this.log("Restored tokens are invalid, clearing storage");
741
+ TokenStorage.clearTokens();
742
+ return false;
994
743
  }
995
- } else {
996
- const parsedErrors = handleCrudifyError(response);
997
- const translatedErrors = parsedErrors.map(translateError);
998
- setErrors(translatedErrors);
744
+ } catch (validationError) {
745
+ this.log("Token validation failed:", validationError);
746
+ TokenStorage.clearTokens();
747
+ return false;
999
748
  }
749
+ this.log("Session restored successfully");
750
+ this.config.onSessionRestored?.(savedTokens);
751
+ return true;
1000
752
  } catch (error) {
1001
- const parsedErrors = handleCrudifyError(error);
1002
- const translatedErrors = parsedErrors.map(translateError);
1003
- setErrors(translatedErrors);
1004
- if (onError) {
1005
- onError(translatedErrors.join(", "));
1006
- }
1007
- } finally {
1008
- setLoading(false);
1009
- }
1010
- };
1011
- const handleBack = () => {
1012
- onScreenChange?.("login");
1013
- };
1014
- const handleGoToCheckCode = () => {
1015
- if (emailSent || codeAlreadyExists) {
1016
- onScreenChange?.("checkCode", { email });
1017
- return;
1018
- }
1019
- if (!email) {
1020
- setHelperTextEmail(t("forgotPassword.emailRequired"));
1021
- return;
753
+ this.log("Session restore error:", error);
754
+ TokenStorage.clearTokens();
755
+ return false;
1022
756
  }
1023
- if (!validateEmail(email)) {
1024
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
1025
- return;
1026
- }
1027
- onScreenChange?.("checkCode", { email });
1028
- };
1029
- if (emailSent || codeAlreadyExists) {
1030
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2, textAlign: "center" }, children: [
1031
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1032
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: codeAlreadyExists ? t("forgotPassword.codeAlreadyExistsMessage") : t("forgotPassword.emailSentMessage") }),
1033
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "body2", sx: { color: codeAlreadyExists ? "success.main" : "grey.600" }, children: codeAlreadyExists ? t("forgotPassword.checkEmailInstructions") : t("forgotPassword.checkEmailInstructions") })
1034
- ] }),
1035
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Button, { type: "button", onClick: handleGoToCheckCode, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: t("forgotPassword.enterCodeLink") }),
1036
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
1037
- ] }) });
1038
757
  }
1039
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1040
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1041
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1042
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
1043
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
1044
- ] }),
1045
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
1046
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1047
- import_material2.Typography,
1048
- {
1049
- variant: "body2",
1050
- component: "label",
1051
- htmlFor: "email",
1052
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1053
- children: t("forgotPassword.emailLabel")
1054
- }
1055
- ),
1056
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1057
- import_material2.TextField,
1058
- {
1059
- fullWidth: true,
1060
- id: "email",
1061
- name: "email",
1062
- type: "email",
1063
- value: email,
1064
- disabled: loading,
1065
- onChange: (e) => setEmail(e.target.value),
1066
- error: !!helperTextEmail,
1067
- helperText: helperTextEmail,
1068
- autoComplete: "email",
1069
- placeholder: t("forgotPassword.emailPlaceholder"),
1070
- required: true
1071
- }
1072
- )
1073
- ] }),
1074
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Button, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.CircularProgress, { size: 20 }) : t("forgotPassword.sendCodeButton") }),
1075
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
1076
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
1077
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
1078
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
1079
- ] })
1080
- ] }),
1081
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
1082
- ] });
1083
- };
1084
- var ForgotPasswordForm_default = ForgotPasswordForm;
1085
-
1086
- // src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
1087
- var import_react7 = require("react");
1088
- var import_material3 = require("@mui/material");
1089
- var import_jsx_runtime6 = require("react/jsx-runtime");
1090
- var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
1091
- const { crudify: crudify6 } = useCrudify();
1092
- const [newPassword, setNewPassword] = (0, import_react7.useState)("");
1093
- const [confirmPassword, setConfirmPassword] = (0, import_react7.useState)("");
1094
- const [loading, setLoading] = (0, import_react7.useState)(false);
1095
- const [errors, setErrors] = (0, import_react7.useState)([]);
1096
- const [helperTextNewPassword, setHelperTextNewPassword] = (0, import_react7.useState)(null);
1097
- const [helperTextConfirmPassword, setHelperTextConfirmPassword] = (0, import_react7.useState)(null);
1098
- const [email, setEmail] = (0, import_react7.useState)("");
1099
- const [code, setCode] = (0, import_react7.useState)("");
1100
- const [fromCodeVerification, setFromCodeVerification] = (0, import_react7.useState)(false);
1101
- const [validatingCode, setValidatingCode] = (0, import_react7.useState)(true);
1102
- const [codeValidated, setCodeValidated] = (0, import_react7.useState)(false);
1103
- const [pendingValidation, setPendingValidation] = (0, import_react7.useState)(null);
1104
- const [isValidating, setIsValidating] = (0, import_react7.useState)(false);
1105
- const { t } = useTranslation();
1106
- const translateError = (parsedError) => {
1107
- const possibleKeys = [
1108
- `errors.auth.${parsedError.code}`,
1109
- `errors.data.${parsedError.code}`,
1110
- `errors.system.${parsedError.code}`,
1111
- `errors.${parsedError.code}`,
1112
- `resetPassword.${parsedError.code.toLowerCase()}`
1113
- ];
1114
- for (const key of possibleKeys) {
1115
- const translated = t(key);
1116
- if (translated !== key) {
1117
- return translated;
758
+ /**
759
+ * Verificar si el usuario está autenticado
760
+ */
761
+ isAuthenticated() {
762
+ return import_crudify_browser2.default.isLogin() || TokenStorage.hasValidTokens();
763
+ }
764
+ /**
765
+ * Obtener información de tokens actuales
766
+ */
767
+ getTokenInfo() {
768
+ const crudifyTokens = import_crudify_browser2.default.getTokenData();
769
+ const storageInfo = TokenStorage.getExpirationInfo();
770
+ return {
771
+ isLoggedIn: this.isAuthenticated(),
772
+ crudifyTokens,
773
+ storageInfo,
774
+ hasValidTokens: TokenStorage.hasValidTokens()
775
+ };
776
+ }
777
+ /**
778
+ * Refrescar tokens manualmente
779
+ */
780
+ async refreshTokens() {
781
+ try {
782
+ this.log("Manually refreshing tokens...");
783
+ const response = await import_crudify_browser2.default.refreshAccessToken();
784
+ if (!response.success) {
785
+ this.log("Token refresh failed:", response.errors);
786
+ TokenStorage.clearTokens();
787
+ this.config.onSessionExpired?.();
788
+ return false;
1118
789
  }
790
+ const newTokens = {
791
+ accessToken: response.data.token,
792
+ refreshToken: response.data.refreshToken,
793
+ expiresAt: response.data.expiresAt,
794
+ refreshExpiresAt: response.data.refreshExpiresAt
795
+ };
796
+ TokenStorage.saveTokens(newTokens);
797
+ this.log("Tokens refreshed and saved successfully");
798
+ return true;
799
+ } catch (error) {
800
+ this.log("Token refresh error:", error);
801
+ TokenStorage.clearTokens();
802
+ this.config.onSessionExpired?.();
803
+ return false;
1119
804
  }
1120
- return parsedError.message || t("error.unknown");
1121
- };
1122
- const getParam = (key) => {
1123
- if (!searchParams) return null;
1124
- if (searchParams instanceof URLSearchParams) {
1125
- return searchParams.get(key);
1126
- }
1127
- return searchParams[key] || null;
1128
- };
1129
- (0, import_react7.useEffect)(() => {
1130
- if (!searchParams) {
1131
- return;
1132
- }
1133
- if (searchParams) {
1134
- const fromCodeVerificationParam = getParam("fromCodeVerification");
1135
- const emailParam = getParam("email");
1136
- const codeParam = getParam("code");
1137
- if (fromCodeVerificationParam === "true" && emailParam && codeParam) {
1138
- setEmail(emailParam);
1139
- setCode(codeParam);
1140
- setFromCodeVerification(true);
1141
- setCodeValidated(true);
1142
- setValidatingCode(false);
1143
- return;
1144
- }
1145
- const linkParam = getParam("link");
1146
- if (linkParam) {
1147
- try {
1148
- const decodedLink = decodeURIComponent(linkParam);
1149
- const [linkCode, linkEmail] = decodedLink.split("/");
1150
- if (linkCode && linkEmail && linkCode.length === 6) {
1151
- setCode(linkCode);
1152
- setEmail(linkEmail);
1153
- setFromCodeVerification(false);
1154
- setPendingValidation({ email: linkEmail, code: linkCode });
1155
- return;
805
+ }
806
+ /**
807
+ * Configurar interceptor de respuesta para manejo automático de errores
808
+ */
809
+ setupResponseInterceptor() {
810
+ import_crudify_browser2.default.setResponseInterceptor(async (response) => {
811
+ if (response.errors) {
812
+ const hasAuthError = response.errors.some(
813
+ (error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
814
+ );
815
+ if (hasAuthError && TokenStorage.hasValidTokens()) {
816
+ this.log("Auth error detected, attempting token refresh...");
817
+ const refreshSuccess = await this.refreshTokens();
818
+ if (!refreshSuccess) {
819
+ this.log("Session expired, triggering callback");
820
+ this.config.onSessionExpired?.();
1156
821
  }
1157
- } catch (error) {
1158
822
  }
1159
823
  }
1160
- if (emailParam && codeParam) {
1161
- setEmail(emailParam);
1162
- setCode(codeParam);
1163
- setFromCodeVerification(false);
1164
- setPendingValidation({ email: emailParam, code: codeParam });
1165
- return;
1166
- }
1167
- }
1168
- setErrors([t("resetPassword.invalidCode")]);
1169
- setValidatingCode(false);
1170
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1171
- }, [searchParams, crudify6, t, onScreenChange]);
1172
- (0, import_react7.useEffect)(() => {
1173
- if (crudify6 && pendingValidation && !isValidating) {
1174
- setIsValidating(true);
1175
- const validateCode = async (emailToValidate, codeToValidate) => {
1176
- try {
1177
- const data = [
1178
- {
1179
- operation: "validatePasswordResetCode",
1180
- data: { email: emailToValidate, codePassword: codeToValidate }
1181
- }
1182
- ];
1183
- const response = await crudify6.transaction(data);
1184
- if (response.data && Array.isArray(response.data)) {
1185
- const validationResult = response.data[0];
1186
- if (validationResult && validationResult.response && validationResult.response.status === "OK") {
1187
- setCodeValidated(true);
1188
- return;
1189
- }
1190
- }
1191
- if (response.success) {
1192
- setCodeValidated(true);
1193
- } else {
1194
- const parsedErrors = handleCrudifyError(response);
1195
- const translatedErrors = parsedErrors.map(translateError);
1196
- setErrors(translatedErrors);
1197
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1198
- }
1199
- } catch (error) {
1200
- const parsedErrors = handleCrudifyError(error);
1201
- const translatedErrors = parsedErrors.map(translateError);
1202
- setErrors(translatedErrors);
1203
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1204
- } finally {
1205
- setValidatingCode(false);
1206
- setPendingValidation(null);
1207
- setIsValidating(false);
1208
- }
1209
- };
1210
- validateCode(pendingValidation.email, pendingValidation.code);
1211
- }
1212
- }, [crudify6, pendingValidation, t, onScreenChange]);
1213
- const validatePassword = (password) => {
1214
- if (password.length < 8) {
1215
- return t("resetPassword.passwordTooShort");
824
+ return response;
825
+ });
826
+ this.log("Response interceptor configured");
827
+ }
828
+ /**
829
+ * Limpiar sesión completamente
830
+ */
831
+ clearSession() {
832
+ TokenStorage.clearTokens();
833
+ import_crudify_browser2.default.logout();
834
+ this.log("Session cleared completely");
835
+ }
836
+ // Métodos privados
837
+ log(message, ...args) {
838
+ if (this.config.enableLogging) {
839
+ console.log(`[SessionManager] ${message}`, ...args);
1216
840
  }
1217
- return null;
1218
- };
1219
- const handleSubmit = async () => {
1220
- if (loading || !crudify6) return;
1221
- setErrors([]);
1222
- setHelperTextNewPassword(null);
1223
- setHelperTextConfirmPassword(null);
1224
- let hasErrors = false;
1225
- if (!newPassword) {
1226
- setHelperTextNewPassword(t("resetPassword.newPasswordRequired"));
1227
- hasErrors = true;
1228
- } else {
1229
- const passwordError = validatePassword(newPassword);
1230
- if (passwordError) {
1231
- setHelperTextNewPassword(passwordError);
1232
- hasErrors = true;
1233
- }
841
+ }
842
+ formatError(errors) {
843
+ if (!errors) return "Unknown error";
844
+ if (typeof errors === "string") return errors;
845
+ if (typeof errors === "object") {
846
+ const errorMessages = Object.values(errors).flat();
847
+ return errorMessages.join(", ");
1234
848
  }
1235
- if (!confirmPassword) {
1236
- setHelperTextConfirmPassword(t("resetPassword.confirmPasswordRequired"));
1237
- hasErrors = true;
1238
- } else if (newPassword !== confirmPassword) {
1239
- setHelperTextConfirmPassword(t("resetPassword.passwordsDoNotMatch"));
1240
- hasErrors = true;
1241
- }
1242
- if (hasErrors) return;
1243
- setLoading(true);
849
+ return "Authentication failed";
850
+ }
851
+ };
852
+
853
+ // src/hooks/useSession.ts
854
+ function useSession(options = {}) {
855
+ const [state, setState] = (0, import_react5.useState)({
856
+ isAuthenticated: false,
857
+ isLoading: true,
858
+ isInitialized: false,
859
+ tokens: null,
860
+ error: null
861
+ });
862
+ const sessionManager = SessionManager.getInstance();
863
+ const initialize = (0, import_react5.useCallback)(async () => {
1244
864
  try {
1245
- const data = [
1246
- {
1247
- operation: "validateAndResetPassword",
1248
- data: { email, codePassword: code, newPassword }
865
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
866
+ const config = {
867
+ autoRestore: options.autoRestore ?? true,
868
+ enableLogging: options.enableLogging ?? false,
869
+ onSessionExpired: () => {
870
+ setState((prev) => ({
871
+ ...prev,
872
+ isAuthenticated: false,
873
+ tokens: null,
874
+ error: "Session expired"
875
+ }));
876
+ options.onSessionExpired?.();
877
+ },
878
+ onSessionRestored: (tokens) => {
879
+ setState((prev) => ({
880
+ ...prev,
881
+ isAuthenticated: true,
882
+ tokens,
883
+ error: null
884
+ }));
885
+ options.onSessionRestored?.(tokens);
886
+ },
887
+ onLoginSuccess: (tokens) => {
888
+ setState((prev) => ({
889
+ ...prev,
890
+ isAuthenticated: true,
891
+ tokens,
892
+ error: null
893
+ }));
894
+ },
895
+ onLogout: () => {
896
+ setState((prev) => ({
897
+ ...prev,
898
+ isAuthenticated: false,
899
+ tokens: null,
900
+ error: null
901
+ }));
1249
902
  }
1250
- ];
1251
- const response = await crudify6.transaction(data);
1252
- if (response.success) {
1253
- setErrors([]);
1254
- setTimeout(() => {
1255
- onResetSuccess?.();
1256
- }, 1e3);
903
+ };
904
+ await sessionManager.initialize(config);
905
+ sessionManager.setupResponseInterceptor();
906
+ const isAuth = sessionManager.isAuthenticated();
907
+ const tokenInfo = sessionManager.getTokenInfo();
908
+ setState((prev) => ({
909
+ ...prev,
910
+ isAuthenticated: isAuth,
911
+ isInitialized: true,
912
+ isLoading: false,
913
+ tokens: tokenInfo.crudifyTokens.accessToken ? {
914
+ accessToken: tokenInfo.crudifyTokens.accessToken,
915
+ refreshToken: tokenInfo.crudifyTokens.refreshToken,
916
+ expiresAt: tokenInfo.crudifyTokens.expiresAt,
917
+ refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
918
+ } : null
919
+ }));
920
+ } catch (error) {
921
+ setState((prev) => ({
922
+ ...prev,
923
+ isLoading: false,
924
+ isInitialized: true,
925
+ error: error instanceof Error ? error.message : "Initialization failed"
926
+ }));
927
+ }
928
+ }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
929
+ const login = (0, import_react5.useCallback)(async (email, password) => {
930
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
931
+ try {
932
+ const result = await sessionManager.login(email, password);
933
+ if (result.success && result.tokens) {
934
+ setState((prev) => ({
935
+ ...prev,
936
+ isAuthenticated: true,
937
+ tokens: result.tokens,
938
+ isLoading: false,
939
+ error: null
940
+ }));
1257
941
  } else {
1258
- const parsedErrors = handleCrudifyError(response);
1259
- const translatedErrors = parsedErrors.map(translateError);
1260
- setErrors(translatedErrors);
942
+ setState((prev) => ({
943
+ ...prev,
944
+ isAuthenticated: false,
945
+ tokens: null,
946
+ isLoading: false,
947
+ error: result.error || "Login failed"
948
+ }));
1261
949
  }
950
+ return result;
1262
951
  } catch (error) {
1263
- const parsedErrors = handleCrudifyError(error);
1264
- const translatedErrors = parsedErrors.map(translateError);
1265
- setErrors(translatedErrors);
1266
- if (onError) {
1267
- onError(translatedErrors.join(", "));
952
+ const errorMsg = error instanceof Error ? error.message : "Login failed";
953
+ setState((prev) => ({
954
+ ...prev,
955
+ isAuthenticated: false,
956
+ tokens: null,
957
+ isLoading: false,
958
+ error: errorMsg
959
+ }));
960
+ return {
961
+ success: false,
962
+ error: errorMsg
963
+ };
964
+ }
965
+ }, [sessionManager]);
966
+ const logout = (0, import_react5.useCallback)(async () => {
967
+ setState((prev) => ({ ...prev, isLoading: true }));
968
+ try {
969
+ await sessionManager.logout();
970
+ setState((prev) => ({
971
+ ...prev,
972
+ isAuthenticated: false,
973
+ tokens: null,
974
+ isLoading: false,
975
+ error: null
976
+ }));
977
+ } catch (error) {
978
+ setState((prev) => ({
979
+ ...prev,
980
+ isAuthenticated: false,
981
+ tokens: null,
982
+ isLoading: false,
983
+ error: error instanceof Error ? error.message : "Logout error"
984
+ }));
985
+ }
986
+ }, [sessionManager]);
987
+ const refreshTokens = (0, import_react5.useCallback)(async () => {
988
+ try {
989
+ const success = await sessionManager.refreshTokens();
990
+ if (success) {
991
+ const tokenInfo = sessionManager.getTokenInfo();
992
+ setState((prev) => ({
993
+ ...prev,
994
+ tokens: tokenInfo.crudifyTokens.accessToken ? {
995
+ accessToken: tokenInfo.crudifyTokens.accessToken,
996
+ refreshToken: tokenInfo.crudifyTokens.refreshToken,
997
+ expiresAt: tokenInfo.crudifyTokens.expiresAt,
998
+ refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
999
+ } : null,
1000
+ error: null
1001
+ }));
1002
+ } else {
1003
+ setState((prev) => ({
1004
+ ...prev,
1005
+ isAuthenticated: false,
1006
+ tokens: null,
1007
+ error: "Token refresh failed"
1008
+ }));
1268
1009
  }
1010
+ return success;
1011
+ } catch (error) {
1012
+ setState((prev) => ({
1013
+ ...prev,
1014
+ isAuthenticated: false,
1015
+ tokens: null,
1016
+ error: error instanceof Error ? error.message : "Token refresh failed"
1017
+ }));
1018
+ return false;
1269
1019
  }
1270
- setLoading(false);
1020
+ }, [sessionManager]);
1021
+ const clearError = (0, import_react5.useCallback)(() => {
1022
+ setState((prev) => ({ ...prev, error: null }));
1023
+ }, []);
1024
+ const getTokenInfo = (0, import_react5.useCallback)(() => {
1025
+ return sessionManager.getTokenInfo();
1026
+ }, [sessionManager]);
1027
+ (0, import_react5.useEffect)(() => {
1028
+ initialize();
1029
+ }, [initialize]);
1030
+ return {
1031
+ // Estado
1032
+ ...state,
1033
+ // Acciones
1034
+ login,
1035
+ logout,
1036
+ refreshTokens,
1037
+ clearError,
1038
+ getTokenInfo,
1039
+ // Utilidades
1040
+ isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
1041
+ // 5 minutos
1042
+ expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
1043
+ refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
1271
1044
  };
1272
- const handleBack = () => {
1273
- if (fromCodeVerification) {
1274
- onScreenChange?.("checkCode", { email });
1275
- } else {
1276
- onScreenChange?.("forgotPassword");
1045
+ }
1046
+
1047
+ // src/utils/jwtUtils.ts
1048
+ var decodeJwtSafely = (token) => {
1049
+ try {
1050
+ const parts = token.split(".");
1051
+ if (parts.length !== 3) {
1052
+ console.warn("Invalid JWT format: token must have 3 parts");
1053
+ return null;
1277
1054
  }
1278
- };
1279
- if (validatingCode) {
1280
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "300px" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.CircularProgress, {}) });
1281
- }
1282
- if (!codeValidated) {
1283
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) });
1055
+ const payload = parts[1];
1056
+ const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
1057
+ const decodedPayload = JSON.parse(atob(paddedPayload));
1058
+ return decodedPayload;
1059
+ } catch (error) {
1060
+ console.warn("Failed to decode JWT token:", error);
1061
+ return null;
1062
+ }
1063
+ };
1064
+ var getCurrentUserEmail = () => {
1065
+ try {
1066
+ let token = null;
1067
+ token = sessionStorage.getItem("authToken");
1068
+ console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
1069
+ if (!token) {
1070
+ token = sessionStorage.getItem("token");
1071
+ console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
1072
+ }
1073
+ if (!token) {
1074
+ token = localStorage.getItem("authToken") || localStorage.getItem("token");
1075
+ console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
1076
+ }
1077
+ if (!token) {
1078
+ console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
1079
+ return null;
1080
+ }
1081
+ const payload = decodeJwtSafely(token);
1082
+ if (!payload) {
1083
+ console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
1084
+ return null;
1085
+ }
1086
+ const email = payload.email || payload["cognito:username"] || null;
1087
+ console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
1088
+ return email;
1089
+ } catch (error) {
1090
+ console.warn("Failed to get current user email:", error);
1091
+ return null;
1092
+ }
1093
+ };
1094
+ var isTokenExpired = (token) => {
1095
+ try {
1096
+ const payload = decodeJwtSafely(token);
1097
+ if (!payload || !payload.exp) return true;
1098
+ const currentTime = Math.floor(Date.now() / 1e3);
1099
+ return payload.exp < currentTime;
1100
+ } catch {
1101
+ return true;
1284
1102
  }
1285
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1286
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1287
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
1288
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
1289
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
1290
- ] }),
1291
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
1292
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1293
- import_material3.Typography,
1294
- {
1295
- variant: "body2",
1296
- component: "label",
1297
- htmlFor: "newPassword",
1298
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1299
- children: t("resetPassword.newPasswordLabel")
1300
- }
1301
- ),
1302
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1303
- import_material3.TextField,
1304
- {
1305
- fullWidth: true,
1306
- id: "newPassword",
1307
- name: "newPassword",
1308
- type: "password",
1309
- value: newPassword,
1310
- disabled: loading,
1311
- onChange: (e) => setNewPassword(e.target.value),
1312
- error: !!helperTextNewPassword,
1313
- helperText: helperTextNewPassword,
1314
- autoComplete: "new-password",
1315
- placeholder: t("resetPassword.newPasswordPlaceholder"),
1316
- required: true
1317
- }
1318
- )
1319
- ] }),
1320
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
1321
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1322
- import_material3.Typography,
1323
- {
1324
- variant: "body2",
1325
- component: "label",
1326
- htmlFor: "confirmPassword",
1327
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1328
- children: t("resetPassword.confirmPasswordLabel")
1329
- }
1330
- ),
1331
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1332
- import_material3.TextField,
1333
- {
1334
- fullWidth: true,
1335
- id: "confirmPassword",
1336
- name: "confirmPassword",
1337
- type: "password",
1338
- value: confirmPassword,
1339
- disabled: loading,
1340
- onChange: (e) => setConfirmPassword(e.target.value),
1341
- error: !!helperTextConfirmPassword,
1342
- helperText: helperTextConfirmPassword,
1343
- autoComplete: "new-password",
1344
- placeholder: t("resetPassword.confirmPasswordPlaceholder"),
1345
- required: true
1346
- }
1347
- )
1348
- ] }),
1349
- /* @__PURE__ */ (0, import_jsx_runtime6.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_runtime6.jsx)(import_material3.CircularProgress, { size: 20 }) : t("resetPassword.resetPasswordButton") }),
1350
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
1351
- ] }),
1352
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
1353
- ] });
1354
1103
  };
1355
- var ResetPasswordForm_default = ResetPasswordForm;
1356
1104
 
1357
- // src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
1358
- var import_react8 = require("react");
1359
- var import_material4 = require("@mui/material");
1360
- var import_jsx_runtime7 = require("react/jsx-runtime");
1361
- var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
1362
- const { crudify: crudify6 } = useCrudify();
1363
- const [code, setCode] = (0, import_react8.useState)("");
1364
- const [loading, setLoading] = (0, import_react8.useState)(false);
1365
- const [errors, setErrors] = (0, import_react8.useState)([]);
1366
- const [helperTextCode, setHelperTextCode] = (0, import_react8.useState)(null);
1367
- const [email, setEmail] = (0, import_react8.useState)("");
1368
- const { t } = useTranslation();
1369
- const getParam = (key) => {
1370
- if (!searchParams) return null;
1371
- if (searchParams instanceof URLSearchParams) {
1372
- return searchParams.get(key);
1105
+ // src/providers/SessionProvider.tsx
1106
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1107
+ var SessionContext = (0, import_react6.createContext)(void 0);
1108
+ function SessionProvider({ children, options = {}, config: propConfig }) {
1109
+ const sessionHook = useSession(options);
1110
+ const resolvedConfig = (0, import_react6.useMemo)(() => {
1111
+ let publicApiKey;
1112
+ let env;
1113
+ let appName;
1114
+ let loginActions;
1115
+ let logo;
1116
+ let colors;
1117
+ let configSource = "unknown";
1118
+ if (propConfig?.publicApiKey) {
1119
+ publicApiKey = propConfig.publicApiKey;
1120
+ configSource = "props";
1373
1121
  }
1374
- return searchParams[key] || null;
1375
- };
1376
- const translateError = (parsedError) => {
1377
- const possibleKeys = [
1378
- `errors.auth.${parsedError.code}`,
1379
- `errors.data.${parsedError.code}`,
1380
- `errors.system.${parsedError.code}`,
1381
- `errors.${parsedError.code}`,
1382
- `checkCode.${parsedError.code.toLowerCase()}`
1383
- ];
1384
- for (const key of possibleKeys) {
1385
- const translated = t(key);
1386
- if (translated !== key) {
1387
- return translated;
1388
- }
1122
+ if (propConfig?.env) {
1123
+ env = propConfig.env;
1389
1124
  }
1390
- return parsedError.message || t("error.unknown");
1391
- };
1392
- (0, import_react8.useEffect)(() => {
1393
- const emailParam = getParam("email");
1394
- if (emailParam) {
1395
- setEmail(emailParam);
1396
- } else {
1397
- onScreenChange?.("forgotPassword");
1125
+ if (propConfig?.appName) {
1126
+ appName = propConfig.appName;
1398
1127
  }
1399
- }, [searchParams, onScreenChange]);
1400
- const handleSubmit = async () => {
1401
- if (loading || !crudify6) return;
1402
- setErrors([]);
1403
- setHelperTextCode(null);
1404
- if (!code) {
1405
- setHelperTextCode(t("checkCode.codeRequired"));
1406
- return;
1128
+ if (propConfig?.loginActions) {
1129
+ loginActions = propConfig.loginActions;
1407
1130
  }
1408
- if (code.length !== 6) {
1409
- setHelperTextCode(t("checkCode.codeRequired"));
1410
- return;
1131
+ if (propConfig?.logo) {
1132
+ logo = propConfig.logo;
1133
+ }
1134
+ if (propConfig?.colors) {
1135
+ colors = propConfig.colors;
1136
+ }
1137
+ if (!publicApiKey) {
1138
+ const cookieApiKey = getCookie("publicApiKey");
1139
+ const cookieEnv = getCookie("environment");
1140
+ const cookieAppName = getCookie("appName");
1141
+ const cookieLoginActions = getCookie("loginActions");
1142
+ if (cookieApiKey) {
1143
+ publicApiKey = cookieApiKey;
1144
+ configSource = "cookies";
1145
+ }
1146
+ if (cookieEnv && ["dev", "stg", "prod"].includes(cookieEnv)) {
1147
+ env = cookieEnv;
1148
+ }
1149
+ if (cookieAppName) {
1150
+ appName = cookieAppName;
1151
+ }
1152
+ if (cookieLoginActions) {
1153
+ loginActions = cookieLoginActions.split(",").map((s) => s.trim()).filter(Boolean);
1154
+ }
1155
+ }
1156
+ console.log("\u{1F50D} SessionProvider - Configuration Detection:");
1157
+ console.log(" - Config source:", configSource);
1158
+ console.log(" - PublicApiKey:", publicApiKey ? publicApiKey.substring(0, 15) + "..." : "undefined");
1159
+ console.log(" - Environment:", env);
1160
+ console.log(" - App name:", appName);
1161
+ console.log(" - Login actions:", loginActions);
1162
+ return {
1163
+ publicApiKey,
1164
+ env,
1165
+ appName,
1166
+ loginActions,
1167
+ logo,
1168
+ colors
1169
+ };
1170
+ }, [propConfig]);
1171
+ const sessionData = (0, import_react6.useMemo)(() => {
1172
+ if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
1173
+ return null;
1411
1174
  }
1412
- setLoading(true);
1413
1175
  try {
1414
- const data = [
1415
- {
1416
- operation: "validatePasswordResetCode",
1417
- data: { email, codePassword: code }
1418
- }
1419
- ];
1420
- const response = await crudify6.transaction(data);
1421
- if (response.success) {
1422
- onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
1423
- } else {
1424
- const parsedErrors = handleCrudifyError(response);
1425
- const translatedErrors = parsedErrors.map(translateError);
1426
- setErrors(translatedErrors);
1427
- setLoading(false);
1176
+ const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
1177
+ if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
1178
+ const result = {
1179
+ _id: decoded.sub,
1180
+ email: decoded.email,
1181
+ subscriberKey: decoded.subscriber
1182
+ };
1183
+ Object.keys(decoded).forEach((key) => {
1184
+ if (!["sub", "email", "subscriber"].includes(key)) {
1185
+ result[key] = decoded[key];
1186
+ }
1187
+ });
1188
+ return result;
1428
1189
  }
1429
1190
  } catch (error) {
1430
- const parsedErrors = handleCrudifyError(error);
1431
- const translatedErrors = parsedErrors.map(translateError);
1432
- setErrors(translatedErrors);
1433
- setLoading(false);
1434
- if (onError) {
1435
- onError(translatedErrors.join(", "));
1436
- }
1191
+ console.error("Error decoding JWT token for sessionData:", error);
1437
1192
  }
1193
+ return null;
1194
+ }, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
1195
+ const contextValue = {
1196
+ ...sessionHook,
1197
+ sessionData,
1198
+ config: resolvedConfig
1438
1199
  };
1439
- const handleBack = () => {
1440
- onScreenChange?.("forgotPassword");
1441
- };
1442
- const handleCodeChange = (event) => {
1443
- const value = event.target.value.replace(/\D/g, "").slice(0, 6);
1444
- setCode(value);
1445
- };
1446
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1447
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1448
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { sx: { mb: 2 }, children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
1450
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
1451
- ] }),
1452
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
1453
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1454
- import_material4.Typography,
1455
- {
1456
- variant: "body2",
1457
- component: "label",
1458
- htmlFor: "code",
1459
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1460
- children: t("checkCode.codeLabel")
1200
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SessionContext.Provider, { value: contextValue, children });
1201
+ }
1202
+ function useSessionContext() {
1203
+ const context = (0, import_react6.useContext)(SessionContext);
1204
+ if (context === void 0) {
1205
+ throw new Error("useSessionContext must be used within a SessionProvider");
1206
+ }
1207
+ return context;
1208
+ }
1209
+ function ProtectedRoute({ children, fallback = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "Please log in to access this content" }), redirectTo }) {
1210
+ const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
1211
+ if (!isInitialized || isLoading) {
1212
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "Loading..." });
1213
+ }
1214
+ if (!isAuthenticated) {
1215
+ if (redirectTo) {
1216
+ redirectTo();
1217
+ return null;
1218
+ }
1219
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: fallback });
1220
+ }
1221
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
1222
+ }
1223
+ function SessionDebugInfo() {
1224
+ const session = useSessionContext();
1225
+ if (!session.isInitialized) {
1226
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "Session not initialized" });
1227
+ }
1228
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1229
+ "div",
1230
+ {
1231
+ style: {
1232
+ padding: "10px",
1233
+ margin: "10px",
1234
+ border: "1px solid #ccc",
1235
+ borderRadius: "4px",
1236
+ fontSize: "12px",
1237
+ fontFamily: "monospace"
1238
+ },
1239
+ children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { children: "Session Debug Info" }),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1242
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Authenticated:" }),
1243
+ " ",
1244
+ session.isAuthenticated ? "Yes" : "No"
1245
+ ] }),
1246
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1247
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Loading:" }),
1248
+ " ",
1249
+ session.isLoading ? "Yes" : "No"
1250
+ ] }),
1251
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Error:" }),
1253
+ " ",
1254
+ session.error || "None"
1255
+ ] }),
1256
+ session.tokens && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1257
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1258
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Access Token:" }),
1259
+ " ",
1260
+ session.tokens.accessToken.substring(0, 20),
1261
+ "..."
1262
+ ] }),
1263
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1264
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Refresh Token:" }),
1265
+ " ",
1266
+ session.tokens.refreshToken.substring(0, 20),
1267
+ "..."
1268
+ ] }),
1269
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1270
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Access Expires In:" }),
1271
+ " ",
1272
+ Math.round(session.expiresIn / 1e3 / 60),
1273
+ " minutes"
1274
+ ] }),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Refresh Expires In:" }),
1277
+ " ",
1278
+ Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
1279
+ " hours"
1280
+ ] }),
1281
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Expiring Soon:" }),
1283
+ " ",
1284
+ session.isExpiringSoon ? "Yes" : "No"
1285
+ ] })
1286
+ ] })
1287
+ ]
1288
+ }
1289
+ );
1290
+ }
1291
+
1292
+ // src/components/CrudifyLogin/Forms/LoginForm.tsx
1293
+ var import_react7 = require("react");
1294
+ var import_material = require("@mui/material");
1295
+
1296
+ // src/utils/errorHandler.ts
1297
+ var ERROR_CODES = {
1298
+ // Authentication Errors
1299
+ INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
1300
+ UNAUTHORIZED: "UNAUTHORIZED",
1301
+ INVALID_API_KEY: "INVALID_API_KEY",
1302
+ USER_NOT_FOUND: "USER_NOT_FOUND",
1303
+ USER_NOT_ACTIVE: "USER_NOT_ACTIVE",
1304
+ NO_PERMISSION: "NO_PERMISSION",
1305
+ // Data Errors
1306
+ ITEM_NOT_FOUND: "ITEM_NOT_FOUND",
1307
+ NOT_FOUND: "NOT_FOUND",
1308
+ IN_USE: "IN_USE",
1309
+ // Validation Errors
1310
+ FIELD_ERROR: "FIELD_ERROR",
1311
+ BAD_REQUEST: "BAD_REQUEST",
1312
+ INVALID_EMAIL: "INVALID_EMAIL",
1313
+ INVALID_CODE: "INVALID_CODE",
1314
+ // System Errors
1315
+ INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR",
1316
+ DATABASE_CONNECTION_ERROR: "DATABASE_CONNECTION_ERROR",
1317
+ INVALID_CONFIGURATION: "INVALID_CONFIGURATION",
1318
+ UNKNOWN_OPERATION: "UNKNOWN_OPERATION",
1319
+ // Rate Limiting
1320
+ TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
1321
+ // Network Errors
1322
+ NETWORK_ERROR: "NETWORK_ERROR",
1323
+ TIMEOUT_ERROR: "TIMEOUT_ERROR"
1324
+ };
1325
+ var ERROR_SEVERITY_MAP = {
1326
+ // Authentication - warning (user can fix)
1327
+ [ERROR_CODES.INVALID_CREDENTIALS]: "warning",
1328
+ [ERROR_CODES.UNAUTHORIZED]: "warning",
1329
+ [ERROR_CODES.INVALID_API_KEY]: "error",
1330
+ [ERROR_CODES.USER_NOT_FOUND]: "warning",
1331
+ [ERROR_CODES.USER_NOT_ACTIVE]: "warning",
1332
+ [ERROR_CODES.NO_PERMISSION]: "warning",
1333
+ // Data - info (might be expected)
1334
+ [ERROR_CODES.ITEM_NOT_FOUND]: "info",
1335
+ [ERROR_CODES.NOT_FOUND]: "info",
1336
+ [ERROR_CODES.IN_USE]: "warning",
1337
+ // Validation - warning (user input issue)
1338
+ [ERROR_CODES.FIELD_ERROR]: "warning",
1339
+ [ERROR_CODES.BAD_REQUEST]: "warning",
1340
+ [ERROR_CODES.INVALID_EMAIL]: "warning",
1341
+ [ERROR_CODES.INVALID_CODE]: "warning",
1342
+ // System - error (server issue)
1343
+ [ERROR_CODES.INTERNAL_SERVER_ERROR]: "error",
1344
+ [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "error",
1345
+ [ERROR_CODES.INVALID_CONFIGURATION]: "error",
1346
+ [ERROR_CODES.UNKNOWN_OPERATION]: "error",
1347
+ // Rate limiting - warning with higher duration
1348
+ [ERROR_CODES.TOO_MANY_REQUESTS]: "warning",
1349
+ // Network - error
1350
+ [ERROR_CODES.NETWORK_ERROR]: "error",
1351
+ [ERROR_CODES.TIMEOUT_ERROR]: "error"
1352
+ };
1353
+ function parseApiError(response) {
1354
+ const errors = [];
1355
+ try {
1356
+ const apiResponse = response;
1357
+ if (apiResponse.data && typeof apiResponse.data === "object") {
1358
+ const responseData = apiResponse.data;
1359
+ if (responseData.response) {
1360
+ const { status, fieldsWarning } = responseData.response;
1361
+ if (fieldsWarning && typeof fieldsWarning === "object") {
1362
+ Object.entries(fieldsWarning).forEach(([field, messages]) => {
1363
+ if (Array.isArray(messages) && messages.length > 0) {
1364
+ errors.push({
1365
+ code: ERROR_CODES.FIELD_ERROR,
1366
+ message: messages[0],
1367
+ severity: "warning",
1368
+ field
1369
+ });
1370
+ }
1371
+ });
1372
+ }
1373
+ if (status && typeof status === "string") {
1374
+ const errorCode = status;
1375
+ if (ERROR_SEVERITY_MAP[errorCode]) {
1376
+ errors.push({
1377
+ code: errorCode,
1378
+ message: getErrorMessage(errorCode),
1379
+ severity: ERROR_SEVERITY_MAP[errorCode]
1380
+ });
1461
1381
  }
1462
- ),
1463
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1464
- import_material4.TextField,
1465
- {
1466
- fullWidth: true,
1467
- id: "code",
1468
- name: "code",
1469
- type: "text",
1470
- value: code,
1471
- disabled: loading,
1472
- onChange: handleCodeChange,
1473
- error: !!helperTextCode,
1474
- helperText: helperTextCode,
1475
- placeholder: t("checkCode.codePlaceholder"),
1476
- inputProps: {
1477
- maxLength: 6,
1478
- style: { textAlign: "center", fontSize: "1.5rem", letterSpacing: "0.4rem" }
1479
- },
1480
- required: true
1382
+ }
1383
+ }
1384
+ }
1385
+ if (apiResponse.errors) {
1386
+ if (typeof apiResponse.errors === "string") {
1387
+ errors.push({
1388
+ code: ERROR_CODES.BAD_REQUEST,
1389
+ message: apiResponse.errors,
1390
+ severity: "warning"
1391
+ });
1392
+ } else if (typeof apiResponse.errors === "object") {
1393
+ const errorObj = apiResponse.errors;
1394
+ Object.entries(errorObj).forEach(([field, messages]) => {
1395
+ if (Array.isArray(messages) && messages.length > 0) {
1396
+ if (field === "_error") {
1397
+ messages.forEach((msg) => {
1398
+ const errorCode = typeof msg === "string" && isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
1399
+ errors.push({
1400
+ code: errorCode,
1401
+ message: typeof msg === "string" ? msg : getErrorMessage(errorCode),
1402
+ severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
1403
+ });
1404
+ });
1405
+ } else if (field === "_graphql") {
1406
+ messages.forEach((msg) => {
1407
+ if (typeof msg === "string") {
1408
+ const errorCode = isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
1409
+ errors.push({
1410
+ code: errorCode,
1411
+ message: getErrorMessage(errorCode),
1412
+ severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
1413
+ });
1414
+ }
1415
+ });
1416
+ } else {
1417
+ errors.push({
1418
+ code: ERROR_CODES.FIELD_ERROR,
1419
+ message: typeof messages[0] === "string" ? messages[0] : "Validation error",
1420
+ severity: "warning",
1421
+ field
1422
+ });
1423
+ }
1481
1424
  }
1482
- )
1483
- ] }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1485
- import_material4.Button,
1486
- {
1487
- disabled: loading || code.length !== 6,
1488
- type: "button",
1489
- onClick: handleSubmit,
1490
- fullWidth: true,
1491
- variant: "contained",
1492
- color: "primary",
1493
- sx: { mt: 2, mb: 2 },
1494
- children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.CircularProgress, { size: 20 }) : t("checkCode.verifyButton")
1425
+ });
1426
+ }
1427
+ }
1428
+ if (errors.length === 0 && apiResponse.success === false) {
1429
+ errors.push({
1430
+ code: ERROR_CODES.BAD_REQUEST,
1431
+ message: "Request failed",
1432
+ severity: "warning"
1433
+ });
1434
+ }
1435
+ } catch (error) {
1436
+ errors.push({
1437
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1438
+ message: "Failed to parse error response",
1439
+ severity: "error",
1440
+ details: { originalError: error }
1441
+ });
1442
+ }
1443
+ return errors.length > 0 ? errors : [
1444
+ {
1445
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1446
+ message: "Unknown error occurred",
1447
+ severity: "error"
1448
+ }
1449
+ ];
1450
+ }
1451
+ function parseTransactionError(response) {
1452
+ try {
1453
+ const transactionResponse = response;
1454
+ if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
1455
+ const errors = [];
1456
+ transactionResponse.data.forEach((item, index) => {
1457
+ if (item.response?.status === "TOO_MANY_REQUESTS") {
1458
+ errors.push({
1459
+ code: ERROR_CODES.TOO_MANY_REQUESTS,
1460
+ message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
1461
+ severity: "warning",
1462
+ details: { transactionIndex: index }
1463
+ });
1464
+ } else if (!item.response || item.response.status !== "OK") {
1465
+ errors.push({
1466
+ code: ERROR_CODES.BAD_REQUEST,
1467
+ message: "Transaction failed",
1468
+ severity: "warning",
1469
+ details: { transactionIndex: index, response: item.response }
1470
+ });
1495
1471
  }
1496
- ),
1497
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
1498
- ] }),
1499
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Alert, { sx: { mt: 2 }, severity: "error", children: error }, index)) })
1500
- ] });
1501
- };
1502
- var CheckCodeForm_default = CheckCodeForm;
1503
-
1504
- // src/components/CrudifyLogin/components/CrudifyInitializer.tsx
1505
- var import_material5 = require("@mui/material");
1506
- var import_jsx_runtime8 = require("react/jsx-runtime");
1507
- var CrudifyInitializer = ({ children, fallback }) => {
1508
- const { isLoading, error, isInitialized } = useCrudify();
1509
- const { t } = useTranslation();
1510
- if (isLoading) {
1511
- return fallback || /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1512
- import_material5.Box,
1472
+ });
1473
+ return errors;
1474
+ }
1475
+ return parseApiError(response);
1476
+ } catch (error) {
1477
+ return [
1513
1478
  {
1514
- sx: {
1515
- display: "flex",
1516
- flexDirection: "column",
1517
- alignItems: "center",
1518
- justifyContent: "center",
1519
- minHeight: "200px",
1520
- gap: 2
1521
- },
1522
- children: [
1523
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.CircularProgress, {}),
1524
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.Typography, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
1525
- ]
1479
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1480
+ message: "Failed to parse transaction error",
1481
+ severity: "error",
1482
+ details: { originalError: error }
1526
1483
  }
1527
- );
1528
- }
1529
- if (error) {
1530
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.Alert, { severity: "error", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material5.Typography, { variant: "body2", children: [
1531
- t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
1532
- ":",
1533
- " ",
1534
- error
1535
- ] }) });
1536
- }
1537
- if (!isInitialized) {
1538
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.Alert, { severity: "warning", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.Typography, { variant: "body2", children: t("login.notInitialized") !== "login.notInitialized" ? t("login.notInitialized") : "System not initialized" }) });
1539
- }
1540
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children });
1541
- };
1542
-
1543
- // src/providers/SessionProvider.tsx
1544
- var import_react10 = require("react");
1545
-
1546
- // src/hooks/useSession.ts
1547
- var import_react9 = require("react");
1548
-
1549
- // src/core/SessionManager.ts
1550
- var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
1551
-
1552
- // src/utils/tokenStorage.ts
1553
- var import_crypto_js = __toESM(require("crypto-js"));
1554
- var _TokenStorage = class _TokenStorage {
1555
- /**
1556
- * Configurar tipo de almacenamiento
1557
- */
1558
- static setStorageType(type) {
1559
- _TokenStorage.storageType = type;
1484
+ ];
1560
1485
  }
1561
- /**
1562
- * Verificar si el storage está disponible
1563
- */
1564
- static isStorageAvailable(type) {
1565
- try {
1566
- const storage = window[type];
1567
- const testKey = "__storage_test__";
1568
- storage.setItem(testKey, "test");
1569
- storage.removeItem(testKey);
1570
- return true;
1571
- } catch {
1572
- return false;
1486
+ }
1487
+ function isValidErrorCode(code) {
1488
+ return Object.values(ERROR_CODES).includes(code);
1489
+ }
1490
+ function getErrorMessage(code) {
1491
+ const messages = {
1492
+ [ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
1493
+ [ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
1494
+ [ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
1495
+ [ERROR_CODES.USER_NOT_FOUND]: "User not found",
1496
+ [ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
1497
+ [ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
1498
+ [ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
1499
+ [ERROR_CODES.NOT_FOUND]: "Resource not found",
1500
+ [ERROR_CODES.IN_USE]: "Resource is currently in use",
1501
+ [ERROR_CODES.FIELD_ERROR]: "Validation error",
1502
+ [ERROR_CODES.BAD_REQUEST]: "Invalid request",
1503
+ [ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
1504
+ [ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
1505
+ [ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
1506
+ [ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
1507
+ [ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
1508
+ [ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
1509
+ [ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
1510
+ [ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
1511
+ [ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
1512
+ };
1513
+ return messages[code] || "An unknown error occurred";
1514
+ }
1515
+ function parseJavaScriptError(error) {
1516
+ if (error instanceof Error) {
1517
+ if (error.name === "AbortError") {
1518
+ return {
1519
+ code: ERROR_CODES.TIMEOUT_ERROR,
1520
+ message: "Request was cancelled",
1521
+ severity: "info"
1522
+ };
1573
1523
  }
1574
- }
1575
- /**
1576
- * Obtener instancia de storage
1577
- */
1578
- static getStorage() {
1579
- if (_TokenStorage.storageType === "none") return null;
1580
- if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
1581
- console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
1582
- return null;
1524
+ if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
1525
+ return {
1526
+ code: ERROR_CODES.NETWORK_ERROR,
1527
+ message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
1528
+ severity: "error"
1529
+ };
1583
1530
  }
1584
- return window[_TokenStorage.storageType];
1531
+ return {
1532
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1533
+ message: error.message || "An unexpected error occurred",
1534
+ severity: "error",
1535
+ details: { originalError: error }
1536
+ };
1585
1537
  }
1586
- /**
1587
- * Encriptar datos sensibles
1588
- */
1589
- static encrypt(data) {
1590
- try {
1591
- return import_crypto_js.default.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
1592
- } catch (error) {
1593
- console.error("Crudify: Encryption failed", error);
1594
- return data;
1595
- }
1538
+ return {
1539
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1540
+ message: "An unknown error occurred",
1541
+ severity: "error",
1542
+ details: { originalError: error }
1543
+ };
1544
+ }
1545
+ function handleCrudifyError(error) {
1546
+ if (error instanceof Error) {
1547
+ return [parseJavaScriptError(error)];
1596
1548
  }
1597
- /**
1598
- * Desencriptar datos
1599
- */
1600
- static decrypt(encryptedData) {
1601
- try {
1602
- const bytes = import_crypto_js.default.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
1603
- const decrypted = bytes.toString(import_crypto_js.default.enc.Utf8);
1604
- return decrypted || encryptedData;
1605
- } catch (error) {
1606
- console.error("Crudify: Decryption failed", error);
1607
- return encryptedData;
1549
+ if (typeof error === "object" && error !== null) {
1550
+ const response = error;
1551
+ if (response.data && Array.isArray(response.data)) {
1552
+ return parseTransactionError(error);
1608
1553
  }
1554
+ return parseApiError(error);
1609
1555
  }
1610
- /**
1611
- * Guardar tokens de forma segura
1612
- */
1613
- static saveTokens(tokens) {
1614
- const storage = _TokenStorage.getStorage();
1615
- if (!storage) return;
1616
- try {
1617
- const tokenData = {
1618
- accessToken: tokens.accessToken,
1619
- refreshToken: tokens.refreshToken,
1620
- expiresAt: tokens.expiresAt,
1621
- refreshExpiresAt: tokens.refreshExpiresAt,
1622
- savedAt: Date.now()
1623
- };
1624
- const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
1625
- storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
1626
- console.debug("Crudify: Tokens saved successfully");
1627
- } catch (error) {
1628
- console.error("Crudify: Failed to save tokens", error);
1556
+ return [
1557
+ {
1558
+ code: ERROR_CODES.INTERNAL_SERVER_ERROR,
1559
+ message: "An unknown error occurred",
1560
+ severity: "error",
1561
+ details: { originalError: error }
1629
1562
  }
1630
- }
1631
- /**
1632
- * Obtener tokens guardados
1633
- */
1634
- static getTokens() {
1635
- const storage = _TokenStorage.getStorage();
1636
- if (!storage) return null;
1637
- try {
1638
- const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
1639
- if (!encrypted) return null;
1640
- const decrypted = _TokenStorage.decrypt(encrypted);
1641
- const tokenData = JSON.parse(decrypted);
1642
- if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
1643
- console.warn("Crudify: Incomplete token data found, clearing storage");
1644
- _TokenStorage.clearTokens();
1645
- return null;
1646
- }
1647
- if (Date.now() >= tokenData.refreshExpiresAt) {
1648
- console.info("Crudify: Refresh token expired, clearing storage");
1649
- _TokenStorage.clearTokens();
1650
- return null;
1563
+ ];
1564
+ }
1565
+
1566
+ // src/components/CrudifyLogin/Forms/LoginForm.tsx
1567
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1568
+ var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
1569
+ const { crudify: crudify6 } = useCrudify();
1570
+ const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
1571
+ const { login: sessionLogin } = useSessionContext();
1572
+ const { t } = useTranslation();
1573
+ const usernameInputRef = (0, import_react7.useRef)(null);
1574
+ const getRedirectUrl = () => {
1575
+ if (state.searchParams.redirect) {
1576
+ try {
1577
+ const decodedPath = decodeURIComponent(state.searchParams.redirect);
1578
+ if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
1579
+ return decodedPath;
1580
+ }
1581
+ } catch (error) {
1651
1582
  }
1652
- return {
1653
- accessToken: tokenData.accessToken,
1654
- refreshToken: tokenData.refreshToken,
1655
- expiresAt: tokenData.expiresAt,
1656
- refreshExpiresAt: tokenData.refreshExpiresAt
1657
- };
1658
- } catch (error) {
1659
- console.error("Crudify: Failed to retrieve tokens", error);
1660
- _TokenStorage.clearTokens();
1661
- return null;
1662
1583
  }
1663
- }
1664
- /**
1665
- * Limpiar tokens almacenados
1666
- */
1667
- static clearTokens() {
1668
- const storage = _TokenStorage.getStorage();
1669
- if (!storage) return;
1670
- try {
1671
- storage.removeItem(_TokenStorage.TOKEN_KEY);
1672
- console.debug("Crudify: Tokens cleared from storage");
1673
- } catch (error) {
1674
- console.error("Crudify: Failed to clear tokens", error);
1584
+ return redirectUrl || "/";
1585
+ };
1586
+ (0, import_react7.useEffect)(() => {
1587
+ const timer = setTimeout(() => {
1588
+ if (usernameInputRef.current) usernameInputRef.current.focus();
1589
+ }, 100);
1590
+ return () => clearTimeout(timer);
1591
+ }, []);
1592
+ const translateError = (parsedError) => {
1593
+ const possibleKeys = [
1594
+ `errors.auth.${parsedError.code}`,
1595
+ `errors.data.${parsedError.code}`,
1596
+ `errors.system.${parsedError.code}`,
1597
+ `errors.${parsedError.code}`,
1598
+ `login.${parsedError.code.toLowerCase()}`
1599
+ ];
1600
+ for (const key of possibleKeys) {
1601
+ const translated = t(key);
1602
+ if (translated !== key) {
1603
+ return translated;
1604
+ }
1675
1605
  }
1676
- }
1677
- /**
1678
- * Verificar si hay tokens válidos guardados
1679
- */
1680
- static hasValidTokens() {
1681
- const tokens = _TokenStorage.getTokens();
1682
- return tokens !== null;
1683
- }
1684
- /**
1685
- * Obtener información de expiración
1686
- */
1687
- static getExpirationInfo() {
1688
- const tokens = _TokenStorage.getTokens();
1689
- if (!tokens) return null;
1690
- const now = Date.now();
1691
- return {
1692
- accessExpired: now >= tokens.expiresAt,
1693
- refreshExpired: now >= tokens.refreshExpiresAt,
1694
- accessExpiresIn: Math.max(0, tokens.expiresAt - now),
1695
- refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
1696
- };
1697
- }
1698
- /**
1699
- * Actualizar solo el access token (después de refresh)
1700
- */
1701
- static updateAccessToken(newAccessToken, newExpiresAt) {
1702
- const existingTokens = _TokenStorage.getTokens();
1703
- if (!existingTokens) {
1704
- console.warn("Crudify: Cannot update access token, no existing tokens found");
1606
+ return parsedError.message || t("error.unknown");
1607
+ };
1608
+ const handleLogin = async () => {
1609
+ if (state.loading) return;
1610
+ if (!state.formData.username.trim()) {
1611
+ setFieldError("username", t("login.usernameRequired"));
1705
1612
  return;
1706
1613
  }
1707
- _TokenStorage.saveTokens({
1708
- ...existingTokens,
1709
- accessToken: newAccessToken,
1710
- expiresAt: newExpiresAt
1614
+ if (!state.formData.password.trim()) {
1615
+ setFieldError("password", t("login.passwordRequired"));
1616
+ return;
1617
+ }
1618
+ clearErrors();
1619
+ setLoading(true);
1620
+ try {
1621
+ const response = await sessionLogin(state.formData.username, state.formData.password);
1622
+ setLoading(false);
1623
+ if (response.success) {
1624
+ console.log("\u{1F510} LoginForm - Login successful via SessionProvider, calling onLoginSuccess");
1625
+ const finalRedirectUrl = getRedirectUrl();
1626
+ if (onLoginSuccess) {
1627
+ onLoginSuccess(response.data, finalRedirectUrl);
1628
+ }
1629
+ } else {
1630
+ handleLoginError(response);
1631
+ }
1632
+ } catch (error) {
1633
+ setLoading(false);
1634
+ const parsedErrors = handleCrudifyError(error);
1635
+ const translatedErrors = parsedErrors.map(translateError);
1636
+ setFieldError("global", translatedErrors);
1637
+ if (onError) {
1638
+ onError(translatedErrors.join(", "));
1639
+ }
1640
+ }
1641
+ };
1642
+ const handleLoginError = (response) => {
1643
+ const parsedErrors = handleCrudifyError(response);
1644
+ parsedErrors.forEach((error) => {
1645
+ if (error.field) {
1646
+ setFieldError(error.field, translateError(error));
1647
+ } else {
1648
+ const currentGlobalErrors = state.errors.global || [];
1649
+ setFieldError("global", [...currentGlobalErrors, translateError(error)]);
1650
+ }
1711
1651
  });
1712
- }
1652
+ };
1653
+ const handleSubmit = (e) => {
1654
+ e.preventDefault();
1655
+ handleLogin();
1656
+ };
1657
+ const handleKeyDown = (e) => {
1658
+ if (e.key === "Enter" && !state.loading) {
1659
+ e.preventDefault();
1660
+ handleLogin();
1661
+ }
1662
+ };
1663
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1664
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1665
+ import_material.Box,
1666
+ {
1667
+ component: "form",
1668
+ noValidate: true,
1669
+ onSubmit: handleSubmit,
1670
+ onKeyDown: handleKeyDown,
1671
+ sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
1672
+ children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
1674
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1675
+ import_material.Typography,
1676
+ {
1677
+ variant: "body2",
1678
+ component: "label",
1679
+ htmlFor: "email",
1680
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1681
+ children: t("login.usernameOrEmailLabel")
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1685
+ import_material.TextField,
1686
+ {
1687
+ fullWidth: true,
1688
+ id: "email",
1689
+ name: "email",
1690
+ type: "email",
1691
+ value: state.formData.username,
1692
+ disabled: state.loading,
1693
+ onChange: (e) => updateFormData({ username: e.target.value }),
1694
+ error: !!state.errors.username,
1695
+ helperText: state.errors.username,
1696
+ autoComplete: "email",
1697
+ placeholder: t("login.usernameOrEmailPlaceholder"),
1698
+ inputRef: usernameInputRef,
1699
+ required: true
1700
+ }
1701
+ )
1702
+ ] }),
1703
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1705
+ import_material.Typography,
1706
+ {
1707
+ variant: "body2",
1708
+ component: "label",
1709
+ htmlFor: "password",
1710
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1711
+ children: t("login.passwordLabel")
1712
+ }
1713
+ ),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1715
+ import_material.TextField,
1716
+ {
1717
+ fullWidth: true,
1718
+ id: "password",
1719
+ name: "password",
1720
+ type: "password",
1721
+ value: state.formData.password,
1722
+ disabled: state.loading,
1723
+ onChange: (e) => updateFormData({ password: e.target.value }),
1724
+ error: !!state.errors.password,
1725
+ helperText: state.errors.password,
1726
+ autoComplete: "current-password",
1727
+ placeholder: t("login.passwordPlaceholder"),
1728
+ required: true
1729
+ }
1730
+ )
1731
+ ] }),
1732
+ state.config.loginActions?.includes("forgotPassword") && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material.Box, { sx: { display: "flex", justifyContent: "flex-end", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1733
+ import_material.Link,
1734
+ {
1735
+ sx: { cursor: "pointer" },
1736
+ onClick: () => {
1737
+ onScreenChange?.("forgotPassword", state.searchParams);
1738
+ },
1739
+ variant: "body2",
1740
+ color: "secondary",
1741
+ children: t("login.forgotPasswordLink")
1742
+ }
1743
+ ) }),
1744
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material.Button, { disabled: state.loading, type: "submit", fullWidth: true, variant: "contained", color: "primary", sx: { mt: 1, mb: 2 }, children: state.loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material.CircularProgress, { size: 20 }) : t("login.loginButton") })
1745
+ ]
1746
+ }
1747
+ ),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material.Box, { children: state.errors.global && state.errors.global.length > 0 && state.errors.global.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: error }) }, index)) }),
1749
+ state.config.loginActions?.includes("createUser") && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material.Typography, { variant: "body2", align: "center", sx: { color: "text.secondary", mt: 3 }, children: [
1750
+ t("login.noAccountPrompt"),
1751
+ " ",
1752
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1753
+ import_material.Link,
1754
+ {
1755
+ sx: { cursor: "pointer" },
1756
+ onClick: () => {
1757
+ const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
1758
+ const signupUrl = `/public/users/create${searchString}`;
1759
+ onExternalNavigate?.(signupUrl);
1760
+ },
1761
+ fontWeight: "medium",
1762
+ color: "secondary",
1763
+ children: t("login.signUpLink")
1764
+ }
1765
+ )
1766
+ ] })
1767
+ ] });
1713
1768
  };
1714
- _TokenStorage.TOKEN_KEY = "crudify_tokens";
1715
- _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
1716
- _TokenStorage.storageType = "localStorage";
1717
- var TokenStorage = _TokenStorage;
1769
+ var LoginForm_default = LoginForm;
1718
1770
 
1719
- // src/core/SessionManager.ts
1720
- var SessionManager = class _SessionManager {
1721
- constructor() {
1722
- this.config = {};
1723
- this.initialized = false;
1724
- }
1725
- static getInstance() {
1726
- if (!_SessionManager.instance) {
1727
- _SessionManager.instance = new _SessionManager();
1771
+ // src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
1772
+ var import_react8 = require("react");
1773
+ var import_material2 = require("@mui/material");
1774
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1775
+ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
1776
+ const { crudify: crudify6 } = useCrudify();
1777
+ const [email, setEmail] = (0, import_react8.useState)("");
1778
+ const [loading, setLoading] = (0, import_react8.useState)(false);
1779
+ const [errors, setErrors] = (0, import_react8.useState)([]);
1780
+ const [helperTextEmail, setHelperTextEmail] = (0, import_react8.useState)(null);
1781
+ const [emailSent, setEmailSent] = (0, import_react8.useState)(false);
1782
+ const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react8.useState)(false);
1783
+ const { t } = useTranslation();
1784
+ const translateError = (parsedError) => {
1785
+ const possibleKeys = [
1786
+ `errors.auth.${parsedError.code}`,
1787
+ `errors.data.${parsedError.code}`,
1788
+ `errors.system.${parsedError.code}`,
1789
+ `errors.${parsedError.code}`,
1790
+ `forgotPassword.${parsedError.code.toLowerCase()}`
1791
+ ];
1792
+ for (const key of possibleKeys) {
1793
+ const translated = t(key);
1794
+ if (translated !== key) {
1795
+ return translated;
1796
+ }
1728
1797
  }
1729
- return _SessionManager.instance;
1730
- }
1731
- /**
1732
- * Inicializar el SessionManager
1733
- */
1734
- async initialize(config = {}) {
1735
- if (this.initialized) {
1736
- console.warn("SessionManager: Already initialized");
1798
+ return parsedError.message || t("error.unknown");
1799
+ };
1800
+ const validateEmail = (email2) => {
1801
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1802
+ return emailRegex.test(email2);
1803
+ };
1804
+ const handleSubmit = async () => {
1805
+ if (loading || !crudify6) return;
1806
+ setErrors([]);
1807
+ setHelperTextEmail(null);
1808
+ if (!email) {
1809
+ setHelperTextEmail(t("forgotPassword.emailRequired"));
1737
1810
  return;
1738
1811
  }
1739
- this.config = {
1740
- storageType: "localStorage",
1741
- autoRestore: true,
1742
- enableLogging: false,
1743
- ...config
1744
- };
1745
- TokenStorage.setStorageType(this.config.storageType || "localStorage");
1746
- if (this.config.enableLogging) {
1747
- }
1748
- if (this.config.autoRestore) {
1749
- await this.restoreSession();
1812
+ if (!validateEmail(email)) {
1813
+ setHelperTextEmail(t("forgotPassword.invalidEmail"));
1814
+ return;
1750
1815
  }
1751
- this.initialized = true;
1752
- this.log("SessionManager initialized successfully");
1753
- }
1754
- /**
1755
- * Login con persistencia automática
1756
- */
1757
- async login(email, password) {
1816
+ setLoading(true);
1758
1817
  try {
1759
- this.log("Attempting login...");
1760
- const response = await import_crudify_browser2.default.login(email, password);
1761
- if (!response.success) {
1762
- this.log("Login failed:", response.errors);
1763
- return {
1764
- success: false,
1765
- error: this.formatError(response.errors)
1766
- };
1818
+ const data = [{ operation: "requestPasswordReset", data: { email } }];
1819
+ const response = await crudify6.transaction(data);
1820
+ if (response.success) {
1821
+ if (response.data && response.data.existingCodeValid) {
1822
+ setCodeAlreadyExists(true);
1823
+ } else {
1824
+ setEmailSent(true);
1825
+ }
1826
+ } else {
1827
+ const parsedErrors = handleCrudifyError(response);
1828
+ const translatedErrors = parsedErrors.map(translateError);
1829
+ setErrors(translatedErrors);
1767
1830
  }
1768
- const tokens = {
1769
- accessToken: response.data.token,
1770
- refreshToken: response.data.refreshToken,
1771
- expiresAt: response.data.expiresAt,
1772
- refreshExpiresAt: response.data.refreshExpiresAt
1773
- };
1774
- TokenStorage.saveTokens(tokens);
1775
- this.log("Login successful, tokens saved");
1776
- this.config.onLoginSuccess?.(tokens);
1777
- return {
1778
- success: true,
1779
- tokens
1780
- };
1781
1831
  } catch (error) {
1782
- this.log("Login error:", error);
1783
- return {
1784
- success: false,
1785
- error: error instanceof Error ? error.message : "Unknown error"
1786
- };
1832
+ const parsedErrors = handleCrudifyError(error);
1833
+ const translatedErrors = parsedErrors.map(translateError);
1834
+ setErrors(translatedErrors);
1835
+ if (onError) {
1836
+ onError(translatedErrors.join(", "));
1837
+ }
1838
+ } finally {
1839
+ setLoading(false);
1787
1840
  }
1788
- }
1789
- /**
1790
- * Logout con limpieza de tokens
1791
- */
1792
- async logout() {
1793
- try {
1794
- this.log("Logging out...");
1795
- await import_crudify_browser2.default.logout();
1796
- TokenStorage.clearTokens();
1797
- this.log("Logout successful");
1798
- this.config.onLogout?.();
1799
- } catch (error) {
1800
- this.log("Logout error:", error);
1801
- TokenStorage.clearTokens();
1841
+ };
1842
+ const handleBack = () => {
1843
+ onScreenChange?.("login");
1844
+ };
1845
+ const handleGoToCheckCode = () => {
1846
+ if (emailSent || codeAlreadyExists) {
1847
+ onScreenChange?.("checkCode", { email });
1848
+ return;
1802
1849
  }
1803
- }
1804
- /**
1805
- * Restaurar sesión desde storage
1806
- */
1807
- async restoreSession() {
1808
- try {
1809
- this.log("Attempting to restore session...");
1810
- const savedTokens = TokenStorage.getTokens();
1811
- if (!savedTokens) {
1812
- this.log("No valid tokens found in storage");
1813
- return false;
1814
- }
1815
- import_crudify_browser2.default.setTokens({
1816
- accessToken: savedTokens.accessToken,
1817
- refreshToken: savedTokens.refreshToken,
1818
- expiresAt: savedTokens.expiresAt,
1819
- refreshExpiresAt: savedTokens.refreshExpiresAt
1820
- });
1821
- this.log("Session restored successfully");
1822
- this.config.onSessionRestored?.(savedTokens);
1823
- return true;
1824
- } catch (error) {
1825
- this.log("Session restore error:", error);
1826
- TokenStorage.clearTokens();
1827
- return false;
1850
+ if (!email) {
1851
+ setHelperTextEmail(t("forgotPassword.emailRequired"));
1852
+ return;
1828
1853
  }
1854
+ if (!validateEmail(email)) {
1855
+ setHelperTextEmail(t("forgotPassword.invalidEmail"));
1856
+ return;
1857
+ }
1858
+ onScreenChange?.("checkCode", { email });
1859
+ };
1860
+ if (emailSent || codeAlreadyExists) {
1861
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2, textAlign: "center" }, children: [
1862
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1863
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: codeAlreadyExists ? t("forgotPassword.codeAlreadyExistsMessage") : t("forgotPassword.emailSentMessage") }),
1864
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "body2", sx: { color: codeAlreadyExists ? "success.main" : "grey.600" }, children: codeAlreadyExists ? t("forgotPassword.checkEmailInstructions") : t("forgotPassword.checkEmailInstructions") })
1865
+ ] }),
1866
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Button, { type: "button", onClick: handleGoToCheckCode, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: t("forgotPassword.enterCodeLink") }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }) })
1868
+ ] }) });
1829
1869
  }
1830
- /**
1831
- * Verificar si el usuario está autenticado
1832
- */
1833
- isAuthenticated() {
1834
- return import_crudify_browser2.default.isLogin() || TokenStorage.hasValidTokens();
1835
- }
1836
- /**
1837
- * Obtener información de tokens actuales
1838
- */
1839
- getTokenInfo() {
1840
- const crudifyTokens = import_crudify_browser2.default.getTokenData();
1841
- const storageInfo = TokenStorage.getExpirationInfo();
1842
- return {
1843
- isLoggedIn: this.isAuthenticated(),
1844
- crudifyTokens,
1845
- storageInfo,
1846
- hasValidTokens: TokenStorage.hasValidTokens()
1847
- };
1848
- }
1849
- /**
1850
- * Refrescar tokens manualmente
1851
- */
1852
- async refreshTokens() {
1853
- try {
1854
- this.log("Manually refreshing tokens...");
1855
- const response = await import_crudify_browser2.default.refreshAccessToken();
1856
- if (!response.success) {
1857
- this.log("Token refresh failed:", response.errors);
1858
- TokenStorage.clearTokens();
1859
- this.config.onSessionExpired?.();
1860
- return false;
1870
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1871
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1872
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1873
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
1875
+ ] }),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
1877
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1878
+ import_material2.Typography,
1879
+ {
1880
+ variant: "body2",
1881
+ component: "label",
1882
+ htmlFor: "email",
1883
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1884
+ children: t("forgotPassword.emailLabel")
1885
+ }
1886
+ ),
1887
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1888
+ import_material2.TextField,
1889
+ {
1890
+ fullWidth: true,
1891
+ id: "email",
1892
+ name: "email",
1893
+ type: "email",
1894
+ value: email,
1895
+ disabled: loading,
1896
+ onChange: (e) => setEmail(e.target.value),
1897
+ error: !!helperTextEmail,
1898
+ helperText: helperTextEmail,
1899
+ autoComplete: "email",
1900
+ placeholder: t("forgotPassword.emailPlaceholder"),
1901
+ required: true
1902
+ }
1903
+ )
1904
+ ] }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Button, { disabled: loading, type: "button", onClick: handleSubmit, fullWidth: true, variant: "contained", color: "primary", sx: { mt: 2, mb: 2 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.CircularProgress, { size: 20 }) : t("forgotPassword.sendCodeButton") }),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
1907
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
1908
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
1909
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
1910
+ ] })
1911
+ ] }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Box, { children: errors.length > 0 && errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Alert, { variant: "filled", sx: { mt: 2 }, severity: "error", children: error }, index)) })
1913
+ ] });
1914
+ };
1915
+ var ForgotPasswordForm_default = ForgotPasswordForm;
1916
+
1917
+ // src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
1918
+ var import_react9 = require("react");
1919
+ var import_material3 = require("@mui/material");
1920
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1921
+ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
1922
+ const { crudify: crudify6 } = useCrudify();
1923
+ const [newPassword, setNewPassword] = (0, import_react9.useState)("");
1924
+ const [confirmPassword, setConfirmPassword] = (0, import_react9.useState)("");
1925
+ const [loading, setLoading] = (0, import_react9.useState)(false);
1926
+ const [errors, setErrors] = (0, import_react9.useState)([]);
1927
+ const [helperTextNewPassword, setHelperTextNewPassword] = (0, import_react9.useState)(null);
1928
+ const [helperTextConfirmPassword, setHelperTextConfirmPassword] = (0, import_react9.useState)(null);
1929
+ const [email, setEmail] = (0, import_react9.useState)("");
1930
+ const [code, setCode] = (0, import_react9.useState)("");
1931
+ const [fromCodeVerification, setFromCodeVerification] = (0, import_react9.useState)(false);
1932
+ const [validatingCode, setValidatingCode] = (0, import_react9.useState)(true);
1933
+ const [codeValidated, setCodeValidated] = (0, import_react9.useState)(false);
1934
+ const [pendingValidation, setPendingValidation] = (0, import_react9.useState)(null);
1935
+ const [isValidating, setIsValidating] = (0, import_react9.useState)(false);
1936
+ const { t } = useTranslation();
1937
+ const translateError = (parsedError) => {
1938
+ const possibleKeys = [
1939
+ `errors.auth.${parsedError.code}`,
1940
+ `errors.data.${parsedError.code}`,
1941
+ `errors.system.${parsedError.code}`,
1942
+ `errors.${parsedError.code}`,
1943
+ `resetPassword.${parsedError.code.toLowerCase()}`
1944
+ ];
1945
+ for (const key of possibleKeys) {
1946
+ const translated = t(key);
1947
+ if (translated !== key) {
1948
+ return translated;
1861
1949
  }
1862
- const newTokens = {
1863
- accessToken: response.data.token,
1864
- refreshToken: response.data.refreshToken,
1865
- expiresAt: response.data.expiresAt,
1866
- refreshExpiresAt: response.data.refreshExpiresAt
1867
- };
1868
- TokenStorage.saveTokens(newTokens);
1869
- this.log("Tokens refreshed and saved successfully");
1870
- return true;
1871
- } catch (error) {
1872
- this.log("Token refresh error:", error);
1873
- TokenStorage.clearTokens();
1874
- this.config.onSessionExpired?.();
1875
- return false;
1876
1950
  }
1877
- }
1878
- /**
1879
- * Configurar interceptor de respuesta para manejo automático de errores
1880
- */
1881
- setupResponseInterceptor() {
1882
- import_crudify_browser2.default.setResponseInterceptor(async (response) => {
1883
- if (response.errors) {
1884
- const hasAuthError = response.errors.some(
1885
- (error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
1886
- );
1887
- if (hasAuthError && TokenStorage.hasValidTokens()) {
1888
- this.log("Auth error detected, attempting token refresh...");
1889
- const refreshSuccess = await this.refreshTokens();
1890
- if (!refreshSuccess) {
1891
- this.log("Session expired, triggering callback");
1892
- this.config.onSessionExpired?.();
1951
+ return parsedError.message || t("error.unknown");
1952
+ };
1953
+ const getParam = (key) => {
1954
+ if (!searchParams) return null;
1955
+ if (searchParams instanceof URLSearchParams) {
1956
+ return searchParams.get(key);
1957
+ }
1958
+ return searchParams[key] || null;
1959
+ };
1960
+ (0, import_react9.useEffect)(() => {
1961
+ if (!searchParams) {
1962
+ return;
1963
+ }
1964
+ if (searchParams) {
1965
+ const fromCodeVerificationParam = getParam("fromCodeVerification");
1966
+ const emailParam = getParam("email");
1967
+ const codeParam = getParam("code");
1968
+ if (fromCodeVerificationParam === "true" && emailParam && codeParam) {
1969
+ setEmail(emailParam);
1970
+ setCode(codeParam);
1971
+ setFromCodeVerification(true);
1972
+ setCodeValidated(true);
1973
+ setValidatingCode(false);
1974
+ return;
1975
+ }
1976
+ const linkParam = getParam("link");
1977
+ if (linkParam) {
1978
+ try {
1979
+ const decodedLink = decodeURIComponent(linkParam);
1980
+ const [linkCode, linkEmail] = decodedLink.split("/");
1981
+ if (linkCode && linkEmail && linkCode.length === 6) {
1982
+ setCode(linkCode);
1983
+ setEmail(linkEmail);
1984
+ setFromCodeVerification(false);
1985
+ setPendingValidation({ email: linkEmail, code: linkCode });
1986
+ return;
1893
1987
  }
1988
+ } catch (error) {
1894
1989
  }
1895
1990
  }
1896
- return response;
1897
- });
1898
- this.log("Response interceptor configured");
1899
- }
1900
- /**
1901
- * Limpiar sesión completamente
1902
- */
1903
- clearSession() {
1904
- TokenStorage.clearTokens();
1905
- import_crudify_browser2.default.logout();
1906
- this.log("Session cleared completely");
1907
- }
1908
- // Métodos privados
1909
- log(message, ...args) {
1910
- if (this.config.enableLogging) {
1911
- console.log(`[SessionManager] ${message}`, ...args);
1912
- }
1913
- }
1914
- formatError(errors) {
1915
- if (!errors) return "Unknown error";
1916
- if (typeof errors === "string") return errors;
1917
- if (typeof errors === "object") {
1918
- const errorMessages = Object.values(errors).flat();
1919
- return errorMessages.join(", ");
1991
+ if (emailParam && codeParam) {
1992
+ setEmail(emailParam);
1993
+ setCode(codeParam);
1994
+ setFromCodeVerification(false);
1995
+ setPendingValidation({ email: emailParam, code: codeParam });
1996
+ return;
1997
+ }
1920
1998
  }
1921
- return "Authentication failed";
1922
- }
1923
- };
1924
-
1925
- // src/hooks/useSession.ts
1926
- function useSession(options = {}) {
1927
- const [state, setState] = (0, import_react9.useState)({
1928
- isAuthenticated: false,
1929
- isLoading: true,
1930
- isInitialized: false,
1931
- tokens: null,
1932
- error: null
1933
- });
1934
- const sessionManager = SessionManager.getInstance();
1935
- const initialize = (0, import_react9.useCallback)(async () => {
1936
- try {
1937
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
1938
- const config = {
1939
- autoRestore: options.autoRestore ?? true,
1940
- enableLogging: options.enableLogging ?? false,
1941
- onSessionExpired: () => {
1942
- setState((prev) => ({
1943
- ...prev,
1944
- isAuthenticated: false,
1945
- tokens: null,
1946
- error: "Session expired"
1947
- }));
1948
- options.onSessionExpired?.();
1949
- },
1950
- onSessionRestored: (tokens) => {
1951
- setState((prev) => ({
1952
- ...prev,
1953
- isAuthenticated: true,
1954
- tokens,
1955
- error: null
1956
- }));
1957
- options.onSessionRestored?.(tokens);
1958
- },
1959
- onLoginSuccess: (tokens) => {
1960
- setState((prev) => ({
1961
- ...prev,
1962
- isAuthenticated: true,
1963
- tokens,
1964
- error: null
1965
- }));
1966
- },
1967
- onLogout: () => {
1968
- setState((prev) => ({
1969
- ...prev,
1970
- isAuthenticated: false,
1971
- tokens: null,
1972
- error: null
1973
- }));
1999
+ setErrors([t("resetPassword.invalidCode")]);
2000
+ setValidatingCode(false);
2001
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2002
+ }, [searchParams, crudify6, t, onScreenChange]);
2003
+ (0, import_react9.useEffect)(() => {
2004
+ if (crudify6 && pendingValidation && !isValidating) {
2005
+ setIsValidating(true);
2006
+ const validateCode = async (emailToValidate, codeToValidate) => {
2007
+ try {
2008
+ const data = [
2009
+ {
2010
+ operation: "validatePasswordResetCode",
2011
+ data: { email: emailToValidate, codePassword: codeToValidate }
2012
+ }
2013
+ ];
2014
+ const response = await crudify6.transaction(data);
2015
+ if (response.data && Array.isArray(response.data)) {
2016
+ const validationResult = response.data[0];
2017
+ if (validationResult && validationResult.response && validationResult.response.status === "OK") {
2018
+ setCodeValidated(true);
2019
+ return;
2020
+ }
2021
+ }
2022
+ if (response.success) {
2023
+ setCodeValidated(true);
2024
+ } else {
2025
+ const parsedErrors = handleCrudifyError(response);
2026
+ const translatedErrors = parsedErrors.map(translateError);
2027
+ setErrors(translatedErrors);
2028
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2029
+ }
2030
+ } catch (error) {
2031
+ const parsedErrors = handleCrudifyError(error);
2032
+ const translatedErrors = parsedErrors.map(translateError);
2033
+ setErrors(translatedErrors);
2034
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2035
+ } finally {
2036
+ setValidatingCode(false);
2037
+ setPendingValidation(null);
2038
+ setIsValidating(false);
1974
2039
  }
1975
2040
  };
1976
- await sessionManager.initialize(config);
1977
- sessionManager.setupResponseInterceptor();
1978
- const isAuth = sessionManager.isAuthenticated();
1979
- const tokenInfo = sessionManager.getTokenInfo();
1980
- setState((prev) => ({
1981
- ...prev,
1982
- isAuthenticated: isAuth,
1983
- isInitialized: true,
1984
- isLoading: false,
1985
- tokens: tokenInfo.crudifyTokens.accessToken ? {
1986
- accessToken: tokenInfo.crudifyTokens.accessToken,
1987
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
1988
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
1989
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
1990
- } : null
1991
- }));
1992
- } catch (error) {
1993
- setState((prev) => ({
1994
- ...prev,
1995
- isLoading: false,
1996
- isInitialized: true,
1997
- error: error instanceof Error ? error.message : "Initialization failed"
1998
- }));
2041
+ validateCode(pendingValidation.email, pendingValidation.code);
1999
2042
  }
2000
- }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
2001
- const login = (0, import_react9.useCallback)(async (email, password) => {
2002
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
2003
- try {
2004
- const result = await sessionManager.login(email, password);
2005
- if (result.success && result.tokens) {
2006
- setState((prev) => ({
2007
- ...prev,
2008
- isAuthenticated: true,
2009
- tokens: result.tokens,
2010
- isLoading: false,
2011
- error: null
2012
- }));
2013
- } else {
2014
- setState((prev) => ({
2015
- ...prev,
2016
- isAuthenticated: false,
2017
- tokens: null,
2018
- isLoading: false,
2019
- error: result.error || "Login failed"
2020
- }));
2021
- }
2022
- return result;
2023
- } catch (error) {
2024
- const errorMsg = error instanceof Error ? error.message : "Login failed";
2025
- setState((prev) => ({
2026
- ...prev,
2027
- isAuthenticated: false,
2028
- tokens: null,
2029
- isLoading: false,
2030
- error: errorMsg
2031
- }));
2032
- return {
2033
- success: false,
2034
- error: errorMsg
2035
- };
2043
+ }, [crudify6, pendingValidation, t, onScreenChange]);
2044
+ const validatePassword = (password) => {
2045
+ if (password.length < 8) {
2046
+ return t("resetPassword.passwordTooShort");
2036
2047
  }
2037
- }, [sessionManager]);
2038
- const logout = (0, import_react9.useCallback)(async () => {
2039
- setState((prev) => ({ ...prev, isLoading: true }));
2040
- try {
2041
- await sessionManager.logout();
2042
- setState((prev) => ({
2043
- ...prev,
2044
- isAuthenticated: false,
2045
- tokens: null,
2046
- isLoading: false,
2047
- error: null
2048
- }));
2049
- } catch (error) {
2050
- setState((prev) => ({
2051
- ...prev,
2052
- isAuthenticated: false,
2053
- tokens: null,
2054
- isLoading: false,
2055
- error: error instanceof Error ? error.message : "Logout error"
2056
- }));
2048
+ return null;
2049
+ };
2050
+ const handleSubmit = async () => {
2051
+ if (loading || !crudify6) return;
2052
+ setErrors([]);
2053
+ setHelperTextNewPassword(null);
2054
+ setHelperTextConfirmPassword(null);
2055
+ let hasErrors = false;
2056
+ if (!newPassword) {
2057
+ setHelperTextNewPassword(t("resetPassword.newPasswordRequired"));
2058
+ hasErrors = true;
2059
+ } else {
2060
+ const passwordError = validatePassword(newPassword);
2061
+ if (passwordError) {
2062
+ setHelperTextNewPassword(passwordError);
2063
+ hasErrors = true;
2064
+ }
2057
2065
  }
2058
- }, [sessionManager]);
2059
- const refreshTokens = (0, import_react9.useCallback)(async () => {
2066
+ if (!confirmPassword) {
2067
+ setHelperTextConfirmPassword(t("resetPassword.confirmPasswordRequired"));
2068
+ hasErrors = true;
2069
+ } else if (newPassword !== confirmPassword) {
2070
+ setHelperTextConfirmPassword(t("resetPassword.passwordsDoNotMatch"));
2071
+ hasErrors = true;
2072
+ }
2073
+ if (hasErrors) return;
2074
+ setLoading(true);
2060
2075
  try {
2061
- const success = await sessionManager.refreshTokens();
2062
- if (success) {
2063
- const tokenInfo = sessionManager.getTokenInfo();
2064
- setState((prev) => ({
2065
- ...prev,
2066
- tokens: tokenInfo.crudifyTokens.accessToken ? {
2067
- accessToken: tokenInfo.crudifyTokens.accessToken,
2068
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
2069
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
2070
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
2071
- } : null,
2072
- error: null
2073
- }));
2076
+ const data = [
2077
+ {
2078
+ operation: "validateAndResetPassword",
2079
+ data: { email, codePassword: code, newPassword }
2080
+ }
2081
+ ];
2082
+ const response = await crudify6.transaction(data);
2083
+ if (response.success) {
2084
+ setErrors([]);
2085
+ setTimeout(() => {
2086
+ onResetSuccess?.();
2087
+ }, 1e3);
2074
2088
  } else {
2075
- setState((prev) => ({
2076
- ...prev,
2077
- isAuthenticated: false,
2078
- tokens: null,
2079
- error: "Token refresh failed"
2080
- }));
2089
+ const parsedErrors = handleCrudifyError(response);
2090
+ const translatedErrors = parsedErrors.map(translateError);
2091
+ setErrors(translatedErrors);
2081
2092
  }
2082
- return success;
2083
2093
  } catch (error) {
2084
- setState((prev) => ({
2085
- ...prev,
2086
- isAuthenticated: false,
2087
- tokens: null,
2088
- error: error instanceof Error ? error.message : "Token refresh failed"
2089
- }));
2090
- return false;
2094
+ const parsedErrors = handleCrudifyError(error);
2095
+ const translatedErrors = parsedErrors.map(translateError);
2096
+ setErrors(translatedErrors);
2097
+ if (onError) {
2098
+ onError(translatedErrors.join(", "));
2099
+ }
2091
2100
  }
2092
- }, [sessionManager]);
2093
- const clearError = (0, import_react9.useCallback)(() => {
2094
- setState((prev) => ({ ...prev, error: null }));
2095
- }, []);
2096
- const getTokenInfo = (0, import_react9.useCallback)(() => {
2097
- return sessionManager.getTokenInfo();
2098
- }, [sessionManager]);
2099
- (0, import_react9.useEffect)(() => {
2100
- initialize();
2101
- }, [initialize]);
2102
- return {
2103
- // Estado
2104
- ...state,
2105
- // Acciones
2106
- login,
2107
- logout,
2108
- refreshTokens,
2109
- clearError,
2110
- getTokenInfo,
2111
- // Utilidades
2112
- isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
2113
- // 5 minutos
2114
- expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
2115
- refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
2101
+ setLoading(false);
2116
2102
  };
2117
- }
2118
-
2119
- // src/utils/jwtUtils.ts
2120
- var decodeJwtSafely = (token) => {
2121
- try {
2122
- const parts = token.split(".");
2123
- if (parts.length !== 3) {
2124
- console.warn("Invalid JWT format: token must have 3 parts");
2125
- return null;
2126
- }
2127
- const payload = parts[1];
2128
- const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
2129
- const decodedPayload = JSON.parse(atob(paddedPayload));
2130
- return decodedPayload;
2131
- } catch (error) {
2132
- console.warn("Failed to decode JWT token:", error);
2133
- return null;
2134
- }
2135
- };
2136
- var getCurrentUserEmail = () => {
2137
- try {
2138
- let token = null;
2139
- token = sessionStorage.getItem("authToken");
2140
- console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
2141
- if (!token) {
2142
- token = sessionStorage.getItem("token");
2143
- console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
2144
- }
2145
- if (!token) {
2146
- token = localStorage.getItem("authToken") || localStorage.getItem("token");
2147
- console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
2148
- }
2149
- if (!token) {
2150
- console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
2151
- return null;
2152
- }
2153
- const payload = decodeJwtSafely(token);
2154
- if (!payload) {
2155
- console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
2156
- return null;
2103
+ const handleBack = () => {
2104
+ if (fromCodeVerification) {
2105
+ onScreenChange?.("checkCode", { email });
2106
+ } else {
2107
+ onScreenChange?.("forgotPassword");
2157
2108
  }
2158
- const email = payload.email || payload["cognito:username"] || null;
2159
- console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
2160
- return email;
2161
- } catch (error) {
2162
- console.warn("Failed to get current user email:", error);
2163
- return null;
2109
+ };
2110
+ if (validatingCode) {
2111
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "300px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.CircularProgress, {}) });
2164
2112
  }
2165
- };
2166
- var isTokenExpired = (token) => {
2167
- try {
2168
- const payload = decodeJwtSafely(token);
2169
- if (!payload || !payload.exp) return true;
2170
- const currentTime = Math.floor(Date.now() / 1e3);
2171
- return payload.exp < currentTime;
2172
- } catch {
2173
- return true;
2113
+ if (!codeValidated) {
2114
+ return /* @__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)) });
2174
2115
  }
2116
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2117
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2118
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
2119
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
2120
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
2121
+ ] }),
2122
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
2123
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2124
+ import_material3.Typography,
2125
+ {
2126
+ variant: "body2",
2127
+ component: "label",
2128
+ htmlFor: "newPassword",
2129
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2130
+ children: t("resetPassword.newPasswordLabel")
2131
+ }
2132
+ ),
2133
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2134
+ import_material3.TextField,
2135
+ {
2136
+ fullWidth: true,
2137
+ id: "newPassword",
2138
+ name: "newPassword",
2139
+ type: "password",
2140
+ value: newPassword,
2141
+ disabled: loading,
2142
+ onChange: (e) => setNewPassword(e.target.value),
2143
+ error: !!helperTextNewPassword,
2144
+ helperText: helperTextNewPassword,
2145
+ autoComplete: "new-password",
2146
+ placeholder: t("resetPassword.newPasswordPlaceholder"),
2147
+ required: true
2148
+ }
2149
+ )
2150
+ ] }),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
2152
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2153
+ import_material3.Typography,
2154
+ {
2155
+ variant: "body2",
2156
+ component: "label",
2157
+ htmlFor: "confirmPassword",
2158
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2159
+ children: t("resetPassword.confirmPasswordLabel")
2160
+ }
2161
+ ),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2163
+ import_material3.TextField,
2164
+ {
2165
+ fullWidth: true,
2166
+ id: "confirmPassword",
2167
+ name: "confirmPassword",
2168
+ type: "password",
2169
+ value: confirmPassword,
2170
+ disabled: loading,
2171
+ onChange: (e) => setConfirmPassword(e.target.value),
2172
+ error: !!helperTextConfirmPassword,
2173
+ helperText: helperTextConfirmPassword,
2174
+ autoComplete: "new-password",
2175
+ placeholder: t("resetPassword.confirmPasswordPlaceholder"),
2176
+ required: true
2177
+ }
2178
+ )
2179
+ ] }),
2180
+ /* @__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("resetPassword.resetPasswordButton") }),
2181
+ /* @__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") }) })
2182
+ ] }),
2183
+ /* @__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)) })
2184
+ ] });
2175
2185
  };
2186
+ var ResetPasswordForm_default = ResetPasswordForm;
2176
2187
 
2177
- // src/providers/SessionProvider.tsx
2178
- var import_jsx_runtime9 = require("react/jsx-runtime");
2179
- var SessionContext = (0, import_react10.createContext)(void 0);
2180
- function SessionProvider({ children, options = {}, config: propConfig }) {
2181
- const sessionHook = useSession(options);
2182
- const resolvedConfig = (0, import_react10.useMemo)(() => {
2183
- let publicApiKey;
2184
- let env;
2185
- let appName;
2186
- let loginActions;
2187
- let logo;
2188
- let colors;
2189
- let configSource = "unknown";
2190
- if (propConfig?.publicApiKey) {
2191
- publicApiKey = propConfig.publicApiKey;
2192
- configSource = "props";
2193
- }
2194
- if (propConfig?.env) {
2195
- env = propConfig.env;
2196
- }
2197
- if (propConfig?.appName) {
2198
- appName = propConfig.appName;
2199
- }
2200
- if (propConfig?.loginActions) {
2201
- loginActions = propConfig.loginActions;
2202
- }
2203
- if (propConfig?.logo) {
2204
- logo = propConfig.logo;
2205
- }
2206
- if (propConfig?.colors) {
2207
- colors = propConfig.colors;
2188
+ // src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
2189
+ var import_react10 = require("react");
2190
+ var import_material4 = require("@mui/material");
2191
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2192
+ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
2193
+ const { crudify: crudify6 } = useCrudify();
2194
+ const [code, setCode] = (0, import_react10.useState)("");
2195
+ const [loading, setLoading] = (0, import_react10.useState)(false);
2196
+ const [errors, setErrors] = (0, import_react10.useState)([]);
2197
+ const [helperTextCode, setHelperTextCode] = (0, import_react10.useState)(null);
2198
+ const [email, setEmail] = (0, import_react10.useState)("");
2199
+ const { t } = useTranslation();
2200
+ const getParam = (key) => {
2201
+ if (!searchParams) return null;
2202
+ if (searchParams instanceof URLSearchParams) {
2203
+ return searchParams.get(key);
2208
2204
  }
2209
- if (!publicApiKey) {
2210
- const cookieApiKey = getCookie("publicApiKey");
2211
- const cookieEnv = getCookie("environment");
2212
- const cookieAppName = getCookie("appName");
2213
- const cookieLoginActions = getCookie("loginActions");
2214
- if (cookieApiKey) {
2215
- publicApiKey = cookieApiKey;
2216
- configSource = "cookies";
2217
- }
2218
- if (cookieEnv && ["dev", "stg", "prod"].includes(cookieEnv)) {
2219
- env = cookieEnv;
2220
- }
2221
- if (cookieAppName) {
2222
- appName = cookieAppName;
2223
- }
2224
- if (cookieLoginActions) {
2225
- loginActions = cookieLoginActions.split(",").map((s) => s.trim()).filter(Boolean);
2205
+ return searchParams[key] || null;
2206
+ };
2207
+ const translateError = (parsedError) => {
2208
+ const possibleKeys = [
2209
+ `errors.auth.${parsedError.code}`,
2210
+ `errors.data.${parsedError.code}`,
2211
+ `errors.system.${parsedError.code}`,
2212
+ `errors.${parsedError.code}`,
2213
+ `checkCode.${parsedError.code.toLowerCase()}`
2214
+ ];
2215
+ for (const key of possibleKeys) {
2216
+ const translated = t(key);
2217
+ if (translated !== key) {
2218
+ return translated;
2226
2219
  }
2227
2220
  }
2228
- console.log("\u{1F50D} SessionProvider - Configuration Detection:");
2229
- console.log(" - Config source:", configSource);
2230
- console.log(" - PublicApiKey:", publicApiKey ? publicApiKey.substring(0, 15) + "..." : "undefined");
2231
- console.log(" - Environment:", env);
2232
- console.log(" - App name:", appName);
2233
- console.log(" - Login actions:", loginActions);
2234
- return {
2235
- publicApiKey,
2236
- env,
2237
- appName,
2238
- loginActions,
2239
- logo,
2240
- colors
2241
- };
2242
- }, [propConfig]);
2243
- const sessionData = (0, import_react10.useMemo)(() => {
2244
- if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
2245
- return null;
2221
+ return parsedError.message || t("error.unknown");
2222
+ };
2223
+ (0, import_react10.useEffect)(() => {
2224
+ const emailParam = getParam("email");
2225
+ if (emailParam) {
2226
+ setEmail(emailParam);
2227
+ } else {
2228
+ onScreenChange?.("forgotPassword");
2229
+ }
2230
+ }, [searchParams, onScreenChange]);
2231
+ const handleSubmit = async () => {
2232
+ if (loading || !crudify6) return;
2233
+ setErrors([]);
2234
+ setHelperTextCode(null);
2235
+ if (!code) {
2236
+ setHelperTextCode(t("checkCode.codeRequired"));
2237
+ return;
2238
+ }
2239
+ if (code.length !== 6) {
2240
+ setHelperTextCode(t("checkCode.codeRequired"));
2241
+ return;
2246
2242
  }
2243
+ setLoading(true);
2247
2244
  try {
2248
- const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
2249
- if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
2250
- const result = {
2251
- _id: decoded.sub,
2252
- email: decoded.email,
2253
- subscriberKey: decoded.subscriber
2254
- };
2255
- Object.keys(decoded).forEach((key) => {
2256
- if (!["sub", "email", "subscriber"].includes(key)) {
2257
- result[key] = decoded[key];
2258
- }
2259
- });
2260
- return result;
2245
+ const data = [
2246
+ {
2247
+ operation: "validatePasswordResetCode",
2248
+ data: { email, codePassword: code }
2249
+ }
2250
+ ];
2251
+ const response = await crudify6.transaction(data);
2252
+ if (response.success) {
2253
+ onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
2254
+ } else {
2255
+ const parsedErrors = handleCrudifyError(response);
2256
+ const translatedErrors = parsedErrors.map(translateError);
2257
+ setErrors(translatedErrors);
2258
+ setLoading(false);
2261
2259
  }
2262
2260
  } catch (error) {
2263
- console.error("Error decoding JWT token for sessionData:", error);
2261
+ const parsedErrors = handleCrudifyError(error);
2262
+ const translatedErrors = parsedErrors.map(translateError);
2263
+ setErrors(translatedErrors);
2264
+ setLoading(false);
2265
+ if (onError) {
2266
+ onError(translatedErrors.join(", "));
2267
+ }
2264
2268
  }
2265
- return null;
2266
- }, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
2267
- const contextValue = {
2268
- ...sessionHook,
2269
- sessionData,
2270
- config: resolvedConfig
2271
2269
  };
2272
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SessionContext.Provider, { value: contextValue, children });
2273
- }
2274
- function useSessionContext() {
2275
- const context = (0, import_react10.useContext)(SessionContext);
2276
- if (context === void 0) {
2277
- throw new Error("useSessionContext must be used within a SessionProvider");
2270
+ const handleBack = () => {
2271
+ onScreenChange?.("forgotPassword");
2272
+ };
2273
+ const handleCodeChange = (event) => {
2274
+ const value = event.target.value.replace(/\D/g, "").slice(0, 6);
2275
+ setCode(value);
2276
+ };
2277
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2278
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2279
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 2 }, children: [
2280
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
2281
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
2282
+ ] }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2285
+ import_material4.Typography,
2286
+ {
2287
+ variant: "body2",
2288
+ component: "label",
2289
+ htmlFor: "code",
2290
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2291
+ children: t("checkCode.codeLabel")
2292
+ }
2293
+ ),
2294
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2295
+ import_material4.TextField,
2296
+ {
2297
+ fullWidth: true,
2298
+ id: "code",
2299
+ name: "code",
2300
+ type: "text",
2301
+ value: code,
2302
+ disabled: loading,
2303
+ onChange: handleCodeChange,
2304
+ error: !!helperTextCode,
2305
+ helperText: helperTextCode,
2306
+ placeholder: t("checkCode.codePlaceholder"),
2307
+ inputProps: {
2308
+ maxLength: 6,
2309
+ style: { textAlign: "center", fontSize: "1.5rem", letterSpacing: "0.4rem" }
2310
+ },
2311
+ required: true
2312
+ }
2313
+ )
2314
+ ] }),
2315
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2316
+ import_material4.Button,
2317
+ {
2318
+ disabled: loading || code.length !== 6,
2319
+ type: "button",
2320
+ onClick: handleSubmit,
2321
+ fullWidth: true,
2322
+ variant: "contained",
2323
+ color: "primary",
2324
+ sx: { mt: 2, mb: 2 },
2325
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.CircularProgress, { size: 20 }) : t("checkCode.verifyButton")
2326
+ }
2327
+ ),
2328
+ /* @__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") }) })
2329
+ ] }),
2330
+ /* @__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, { sx: { mt: 2 }, severity: "error", children: error }, index)) })
2331
+ ] });
2332
+ };
2333
+ var CheckCodeForm_default = CheckCodeForm;
2334
+
2335
+ // src/components/CrudifyLogin/components/CrudifyInitializer.tsx
2336
+ var import_material5 = require("@mui/material");
2337
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2338
+ var CrudifyInitializer = ({ children, fallback }) => {
2339
+ const { isLoading, error, isInitialized } = useCrudify();
2340
+ const { t } = useTranslation();
2341
+ if (isLoading) {
2342
+ return fallback || /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2343
+ import_material5.Box,
2344
+ {
2345
+ sx: {
2346
+ display: "flex",
2347
+ flexDirection: "column",
2348
+ alignItems: "center",
2349
+ justifyContent: "center",
2350
+ minHeight: "200px",
2351
+ gap: 2
2352
+ },
2353
+ children: [
2354
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.CircularProgress, {}),
2355
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Typography, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
2356
+ ]
2357
+ }
2358
+ );
2278
2359
  }
2279
- return context;
2280
- }
2281
- function ProtectedRoute({ children, fallback = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: "Please log in to access this content" }), redirectTo }) {
2282
- const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
2283
- if (!isInitialized || isLoading) {
2284
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: "Loading..." });
2360
+ if (error) {
2361
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Alert, { severity: "error", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_material5.Typography, { variant: "body2", children: [
2362
+ t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
2363
+ ":",
2364
+ " ",
2365
+ error
2366
+ ] }) });
2285
2367
  }
2286
- if (!isAuthenticated) {
2287
- if (redirectTo) {
2288
- redirectTo();
2289
- return null;
2290
- }
2291
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: fallback });
2368
+ if (!isInitialized) {
2369
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Alert, { severity: "warning", sx: { mt: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Typography, { variant: "body2", children: t("login.notInitialized") !== "login.notInitialized" ? t("login.notInitialized") : "System not initialized" }) });
2292
2370
  }
2293
2371
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
2294
- }
2295
- function SessionDebugInfo() {
2296
- const session = useSessionContext();
2297
- if (!session.isInitialized) {
2298
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: "Session not initialized" });
2299
- }
2300
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2301
- "div",
2302
- {
2303
- style: {
2304
- padding: "10px",
2305
- margin: "10px",
2306
- border: "1px solid #ccc",
2307
- borderRadius: "4px",
2308
- fontSize: "12px",
2309
- fontFamily: "monospace"
2310
- },
2311
- children: [
2312
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { children: "Session Debug Info" }),
2313
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2314
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Authenticated:" }),
2315
- " ",
2316
- session.isAuthenticated ? "Yes" : "No"
2317
- ] }),
2318
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2319
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Loading:" }),
2320
- " ",
2321
- session.isLoading ? "Yes" : "No"
2322
- ] }),
2323
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2324
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Error:" }),
2325
- " ",
2326
- session.error || "None"
2327
- ] }),
2328
- session.tokens && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2329
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2330
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Access Token:" }),
2331
- " ",
2332
- session.tokens.accessToken.substring(0, 20),
2333
- "..."
2334
- ] }),
2335
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2336
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Refresh Token:" }),
2337
- " ",
2338
- session.tokens.refreshToken.substring(0, 20),
2339
- "..."
2340
- ] }),
2341
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2342
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Access Expires In:" }),
2343
- " ",
2344
- Math.round(session.expiresIn / 1e3 / 60),
2345
- " minutes"
2346
- ] }),
2347
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2348
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Refresh Expires In:" }),
2349
- " ",
2350
- Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
2351
- " hours"
2352
- ] }),
2353
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2354
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Expiring Soon:" }),
2355
- " ",
2356
- session.isExpiringSoon ? "Yes" : "No"
2357
- ] })
2358
- ] })
2359
- ]
2360
- }
2361
- );
2362
- }
2372
+ };
2363
2373
 
2364
2374
  // src/components/CrudifyLogin/index.tsx
2365
2375
  var import_jsx_runtime10 = require("react/jsx-runtime");