@nocios/crudify-ui 1.0.92 → 1.0.96

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 +2109 -2118
  2. package/dist/index.mjs +2176 -2185
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -447,7 +447,7 @@ var useLoginState = () => {
447
447
  };
448
448
 
449
449
  // src/components/CrudifyLogin/Forms/LoginForm.tsx
450
- var import_react5 = require("react");
450
+ var import_react6 = require("react");
451
451
  var import_material = require("@mui/material");
452
452
 
453
453
  // src/components/CrudifyLogin/utils/secureStorage.ts
@@ -829,985 +829,439 @@ function handleCrudifyError(error) {
829
829
  ];
830
830
  }
831
831
 
832
- // src/components/CrudifyLogin/Forms/LoginForm.tsx
833
- var import_jsx_runtime4 = require("react/jsx-runtime");
834
- var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
835
- const { crudify: crudify7 } = useCrudify();
836
- const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
837
- const { t } = useTranslation();
838
- const usernameInputRef = (0, import_react5.useRef)(null);
839
- const getRedirectUrl = () => {
840
- if (state.searchParams.redirect) {
841
- try {
842
- const decodedPath = decodeURIComponent(state.searchParams.redirect);
843
- if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
844
- return decodedPath;
845
- }
846
- } catch (error) {
847
- }
832
+ // src/providers/CrudifyDataProvider.tsx
833
+ var import_react5 = require("react");
834
+
835
+ // src/core/ConfigurationManager.ts
836
+ var _ConfigurationManager = class _ConfigurationManager {
837
+ constructor() {
838
+ this.resolvedConfig = null;
839
+ this.configError = null;
840
+ }
841
+ /**
842
+ * Singleton pattern to ensure consistent configuration across the app
843
+ */
844
+ static getInstance() {
845
+ if (!_ConfigurationManager.instance) {
846
+ _ConfigurationManager.instance = new _ConfigurationManager();
848
847
  }
849
- return redirectUrl || "/";
850
- };
851
- (0, import_react5.useEffect)(() => {
852
- const timer = setTimeout(() => {
853
- if (usernameInputRef.current) usernameInputRef.current.focus();
854
- }, 100);
855
- return () => clearTimeout(timer);
856
- }, []);
857
- const translateError = (parsedError) => {
858
- const possibleKeys = [
859
- `errors.auth.${parsedError.code}`,
860
- `errors.data.${parsedError.code}`,
861
- `errors.system.${parsedError.code}`,
862
- `errors.${parsedError.code}`,
863
- `login.${parsedError.code.toLowerCase()}`
864
- ];
865
- for (const key of possibleKeys) {
866
- const translated = t(key);
867
- if (translated !== key) {
868
- return translated;
848
+ return _ConfigurationManager.instance;
849
+ }
850
+ /**
851
+ * Reset the singleton instance (useful for testing)
852
+ */
853
+ static resetInstance() {
854
+ _ConfigurationManager.instance = null;
855
+ }
856
+ /**
857
+ * Resolve configuration from all sources with proper priority
858
+ */
859
+ resolveConfig(propsConfig = {}) {
860
+ if (this.resolvedConfig && this.isConfigStillValid(propsConfig)) {
861
+ return this.resolvedConfig;
862
+ }
863
+ try {
864
+ this.configError = null;
865
+ const envConfig = this.getEnvConfig();
866
+ const cookieConfig = this.getCookieConfig();
867
+ const configSource = {
868
+ env: "default",
869
+ publicApiKey: "default",
870
+ loginActions: "default",
871
+ appName: "default",
872
+ logo: "default",
873
+ colors: "default"
874
+ };
875
+ const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
876
+ const publicApiKey = this.resolveValue("publicApiKey", propsConfig.publicApiKey, envConfig.publicApiKey, cookieConfig.publicApiKey, void 0, configSource);
877
+ const loginActions = this.resolveValue("loginActions", propsConfig.loginActions, envConfig.loginActions, cookieConfig.loginActions, [], configSource);
878
+ const appName = this.resolveValue("appName", propsConfig.appName, envConfig.appName, cookieConfig.appName, "Crudify App", configSource);
879
+ const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
880
+ const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
881
+ if (!publicApiKey) {
882
+ throw new Error(
883
+ "publicApiKey is required. Provide it via:\n1. Props: <CrudifyDataProvider publicApiKey={...} />\n2. Environment: VITE_TEST_PUBLIC_API_KEY\n3. Cookie: publicApiKey"
884
+ );
869
885
  }
886
+ this.resolvedConfig = {
887
+ env,
888
+ publicApiKey,
889
+ loginActions,
890
+ appName,
891
+ logo,
892
+ colors,
893
+ configSource,
894
+ rawConfig: {
895
+ props: propsConfig,
896
+ env: envConfig,
897
+ cookies: cookieConfig
898
+ }
899
+ };
900
+ console.log("\u{1F527} ConfigurationManager - Configuration resolved:", {
901
+ config: {
902
+ env: this.resolvedConfig.env,
903
+ publicApiKey: `${this.resolvedConfig.publicApiKey.substring(0, 8)}...`,
904
+ appName: this.resolvedConfig.appName,
905
+ loginActionsCount: this.resolvedConfig.loginActions.length
906
+ },
907
+ sources: this.resolvedConfig.configSource
908
+ });
909
+ return this.resolvedConfig;
910
+ } catch (error) {
911
+ this.configError = error instanceof Error ? error.message : "Unknown configuration error";
912
+ console.error("\u{1F527} ConfigurationManager - Configuration error:", this.configError);
913
+ this.resolvedConfig = {
914
+ env: "prod",
915
+ publicApiKey: "",
916
+ loginActions: [],
917
+ appName: "Crudify App",
918
+ logo: "",
919
+ colors: {},
920
+ configSource: {
921
+ env: "default",
922
+ publicApiKey: "default",
923
+ loginActions: "default",
924
+ appName: "default",
925
+ logo: "default",
926
+ colors: "default"
927
+ },
928
+ rawConfig: {
929
+ props: propsConfig,
930
+ env: {},
931
+ cookies: {},
932
+ error: this.configError
933
+ }
934
+ };
935
+ return this.resolvedConfig;
870
936
  }
871
- return parsedError.message || t("error.unknown");
872
- };
873
- const handleLogin = async () => {
874
- if (state.loading) return;
875
- if (!state.formData.username.trim()) {
876
- setFieldError("username", t("login.usernameRequired"));
877
- return;
937
+ }
938
+ /**
939
+ * Check if current configuration is still valid for the given props
940
+ */
941
+ isConfigStillValid(propsConfig) {
942
+ if (!this.resolvedConfig) return false;
943
+ const currentProps = this.resolvedConfig.rawConfig.props;
944
+ return JSON.stringify(currentProps) === JSON.stringify(propsConfig);
945
+ }
946
+ /**
947
+ * Resolve a single config value with priority and source tracking
948
+ */
949
+ resolveValue(key, propsValue, envValue, cookieValue, defaultValue, configSource) {
950
+ if (propsValue !== void 0) {
951
+ configSource[key] = "props";
952
+ return propsValue;
878
953
  }
879
- if (!state.formData.password.trim()) {
880
- setFieldError("password", t("login.passwordRequired"));
881
- return;
954
+ if (envValue !== void 0) {
955
+ configSource[key] = "env";
956
+ return envValue;
882
957
  }
883
- clearErrors();
884
- setLoading(true);
958
+ if (cookieValue !== void 0) {
959
+ configSource[key] = "cookies";
960
+ return cookieValue;
961
+ }
962
+ configSource[key] = "default";
963
+ return defaultValue;
964
+ }
965
+ /**
966
+ * Get configuration from environment variables
967
+ */
968
+ getEnvConfig() {
969
+ const config = {};
885
970
  try {
886
- if (!crudify7) {
887
- throw new Error("Crudify not initialized");
971
+ } catch (error) {
972
+ console.warn("\u{1F527} ConfigurationManager - Environment variables not available:", error);
973
+ }
974
+ return config;
975
+ }
976
+ /**
977
+ * Get configuration from cookies (multi-tenant support)
978
+ */
979
+ getCookieConfig() {
980
+ const config = {};
981
+ try {
982
+ const env = getCookie("environment");
983
+ if (env && ["dev", "stg", "prod"].includes(env)) {
984
+ config.env = env;
888
985
  }
889
- const response = await crudify7.login(state.formData.username, state.formData.password);
890
- setLoading(false);
891
- if (response.success) {
892
- secureSessionStorage.setToken(response.data.token);
893
- const finalRedirectUrl = getRedirectUrl();
894
- setTimeout(() => {
895
- if (onLoginSuccess) {
896
- onLoginSuccess(response.data, finalRedirectUrl);
897
- }
898
- }, 50);
899
- } else {
900
- handleLoginError(response);
986
+ const publicApiKey = getCookie("publicApiKey");
987
+ if (publicApiKey) {
988
+ config.publicApiKey = publicApiKey;
901
989
  }
902
- } catch (error) {
903
- setLoading(false);
904
- const parsedErrors = handleCrudifyError(error);
905
- const translatedErrors = parsedErrors.map(translateError);
906
- setFieldError("global", translatedErrors);
907
- if (onError) {
908
- onError(translatedErrors.join(", "));
990
+ const appName = getCookie("appName");
991
+ if (appName) {
992
+ config.appName = appName;
909
993
  }
910
- }
911
- };
912
- const handleLoginError = (response) => {
913
- const parsedErrors = handleCrudifyError(response);
914
- parsedErrors.forEach((error) => {
915
- if (error.field) {
916
- setFieldError(error.field, translateError(error));
917
- } else {
918
- const currentGlobalErrors = state.errors.global || [];
919
- setFieldError("global", [...currentGlobalErrors, translateError(error)]);
994
+ const loginActions = getCookie("loginActions");
995
+ if (loginActions) {
996
+ config.loginActions = loginActions.split(",").map((action) => action.trim()).filter(Boolean);
920
997
  }
921
- });
922
- };
923
- const handleSubmit = (e) => {
924
- e.preventDefault();
925
- handleLogin();
926
- };
927
- const handleKeyDown = (e) => {
928
- if (e.key === "Enter" && !state.loading) {
929
- e.preventDefault();
930
- handleLogin();
931
- }
932
- };
933
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
934
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
935
- import_material.Box,
936
- {
937
- component: "form",
938
- noValidate: true,
939
- onSubmit: handleSubmit,
940
- onKeyDown: handleKeyDown,
941
- sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
942
- children: [
943
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
944
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
945
- import_material.Typography,
946
- {
947
- variant: "body2",
948
- component: "label",
949
- htmlFor: "email",
950
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
951
- children: t("login.usernameOrEmailLabel")
952
- }
953
- ),
954
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
955
- import_material.TextField,
956
- {
957
- fullWidth: true,
958
- id: "email",
959
- name: "email",
960
- type: "email",
961
- value: state.formData.username,
962
- disabled: state.loading,
963
- onChange: (e) => updateFormData({ username: e.target.value }),
964
- error: !!state.errors.username,
965
- helperText: state.errors.username,
966
- autoComplete: "email",
967
- placeholder: t("login.usernameOrEmailPlaceholder"),
968
- inputRef: usernameInputRef,
969
- required: true
970
- }
971
- )
972
- ] }),
973
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
974
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
975
- import_material.Typography,
976
- {
977
- variant: "body2",
978
- component: "label",
979
- htmlFor: "password",
980
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
981
- children: t("login.passwordLabel")
982
- }
983
- ),
984
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
985
- import_material.TextField,
986
- {
987
- fullWidth: true,
988
- id: "password",
989
- name: "password",
990
- type: "password",
991
- value: state.formData.password,
992
- disabled: state.loading,
993
- onChange: (e) => updateFormData({ password: e.target.value }),
994
- error: !!state.errors.password,
995
- helperText: state.errors.password,
996
- autoComplete: "current-password",
997
- placeholder: t("login.passwordPlaceholder"),
998
- required: true
999
- }
1000
- )
1001
- ] }),
1002
- 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)(
1003
- import_material.Link,
1004
- {
1005
- sx: { cursor: "pointer" },
1006
- onClick: () => {
1007
- onScreenChange?.("forgotPassword", state.searchParams);
1008
- },
1009
- variant: "body2",
1010
- color: "secondary",
1011
- children: t("login.forgotPasswordLink")
1012
- }
1013
- ) }),
1014
- /* @__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") })
1015
- ]
998
+ const logo = getCookie("logo");
999
+ if (logo) {
1000
+ config.logo = logo;
1016
1001
  }
1017
- ),
1018
- /* @__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)) }),
1019
- 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: [
1020
- t("login.noAccountPrompt"),
1021
- " ",
1022
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1023
- import_material.Link,
1024
- {
1025
- sx: { cursor: "pointer" },
1026
- onClick: () => {
1027
- const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
1028
- const signupUrl = `/public/users/create${searchString}`;
1029
- onExternalNavigate?.(signupUrl);
1030
- },
1031
- fontWeight: "medium",
1032
- color: "secondary",
1033
- children: t("login.signUpLink")
1002
+ const colors = getCookie("colors");
1003
+ if (colors) {
1004
+ try {
1005
+ config.colors = JSON.parse(colors);
1006
+ } catch (error) {
1007
+ console.warn("\u{1F527} ConfigurationManager - Failed to parse colors from cookie:", error);
1034
1008
  }
1035
- )
1036
- ] })
1037
- ] });
1009
+ }
1010
+ } catch (error) {
1011
+ console.warn("\u{1F527} ConfigurationManager - Error reading cookies:", error);
1012
+ }
1013
+ return config;
1014
+ }
1015
+ /**
1016
+ * Get the current resolved configuration
1017
+ */
1018
+ getConfig() {
1019
+ return this.resolvedConfig;
1020
+ }
1021
+ /**
1022
+ * Get any configuration errors
1023
+ */
1024
+ getConfigError() {
1025
+ return this.configError;
1026
+ }
1027
+ /**
1028
+ * Check if configuration is valid (no errors and has required fields)
1029
+ */
1030
+ isConfigured() {
1031
+ return this.resolvedConfig !== null && this.configError === null && !!this.resolvedConfig.publicApiKey;
1032
+ }
1033
+ /**
1034
+ * Clear the current configuration (useful for testing or reconfiguration)
1035
+ */
1036
+ clearConfig() {
1037
+ this.resolvedConfig = null;
1038
+ this.configError = null;
1039
+ }
1038
1040
  };
1039
- var LoginForm_default = LoginForm;
1041
+ _ConfigurationManager.instance = null;
1042
+ var ConfigurationManager = _ConfigurationManager;
1043
+ var configurationManager = ConfigurationManager.getInstance();
1040
1044
 
1041
- // src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
1042
- var import_react6 = require("react");
1043
- var import_material2 = require("@mui/material");
1044
- var import_jsx_runtime5 = require("react/jsx-runtime");
1045
- var ForgotPasswordForm = ({ onScreenChange, onError }) => {
1046
- const { crudify: crudify7 } = useCrudify();
1047
- const [email, setEmail] = (0, import_react6.useState)("");
1048
- const [loading, setLoading] = (0, import_react6.useState)(false);
1049
- const [errors, setErrors] = (0, import_react6.useState)([]);
1050
- const [helperTextEmail, setHelperTextEmail] = (0, import_react6.useState)(null);
1051
- const [emailSent, setEmailSent] = (0, import_react6.useState)(false);
1052
- const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react6.useState)(false);
1053
- const { t } = useTranslation();
1054
- const translateError = (parsedError) => {
1055
- const possibleKeys = [
1056
- `errors.auth.${parsedError.code}`,
1057
- `errors.data.${parsedError.code}`,
1058
- `errors.system.${parsedError.code}`,
1059
- `errors.${parsedError.code}`,
1060
- `forgotPassword.${parsedError.code.toLowerCase()}`
1061
- ];
1062
- for (const key of possibleKeys) {
1063
- const translated = t(key);
1064
- if (translated !== key) {
1065
- return translated;
1066
- }
1045
+ // src/core/CrudifyInitializer.ts
1046
+ var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
1047
+ var _CrudifyInitializer = class _CrudifyInitializer {
1048
+ constructor() {
1049
+ this.state = {
1050
+ isInitialized: false,
1051
+ isInitializing: false,
1052
+ initializationError: null,
1053
+ config: null,
1054
+ initializationPromise: null
1055
+ };
1056
+ console.log("\u{1F680} CrudifyInitializer - Instance created");
1057
+ }
1058
+ /**
1059
+ * Singleton pattern to ensure global initialization coordination
1060
+ */
1061
+ static getInstance() {
1062
+ if (!_CrudifyInitializer.instance) {
1063
+ _CrudifyInitializer.instance = new _CrudifyInitializer();
1067
1064
  }
1068
- return parsedError.message || t("error.unknown");
1069
- };
1070
- const validateEmail = (email2) => {
1071
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1072
- return emailRegex.test(email2);
1073
- };
1074
- const handleSubmit = async () => {
1075
- if (loading || !crudify7) return;
1076
- setErrors([]);
1077
- setHelperTextEmail(null);
1078
- if (!email) {
1079
- setHelperTextEmail(t("forgotPassword.emailRequired"));
1065
+ return _CrudifyInitializer.instance;
1066
+ }
1067
+ /**
1068
+ * Reset the singleton instance (useful for testing)
1069
+ */
1070
+ static resetInstance() {
1071
+ _CrudifyInitializer.instance = null;
1072
+ }
1073
+ /**
1074
+ * Initialize crudify with the given configuration
1075
+ * This method is idempotent and thread-safe
1076
+ */
1077
+ async initialize(config) {
1078
+ if (this.state.isInitialized && this.isConfigurationSame(config)) {
1079
+ console.log("\u{1F680} CrudifyInitializer - Already initialized with same config");
1080
1080
  return;
1081
1081
  }
1082
- if (!validateEmail(email)) {
1083
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
1082
+ if (this.state.isInitializing && this.state.initializationPromise) {
1083
+ console.log("\u{1F680} CrudifyInitializer - Waiting for ongoing initialization");
1084
+ await this.state.initializationPromise;
1084
1085
  return;
1085
1086
  }
1086
- setLoading(true);
1087
+ if (this.state.isInitialized && !this.isConfigurationSame(config)) {
1088
+ console.log("\u{1F680} CrudifyInitializer - Configuration changed, re-initializing");
1089
+ this.reset();
1090
+ }
1091
+ this.state.isInitializing = true;
1092
+ this.state.initializationError = null;
1093
+ this.state.initializationPromise = this.performInitialization(config);
1087
1094
  try {
1088
- const data = [{ operation: "requestPasswordReset", data: { email } }];
1089
- const response = await crudify7.transaction(data);
1090
- if (response.success) {
1091
- if (response.data && response.data.existingCodeValid) {
1092
- setCodeAlreadyExists(true);
1093
- } else {
1094
- setEmailSent(true);
1095
- }
1096
- } else {
1097
- const parsedErrors = handleCrudifyError(response);
1098
- const translatedErrors = parsedErrors.map(translateError);
1099
- setErrors(translatedErrors);
1100
- }
1095
+ await this.state.initializationPromise;
1096
+ this.state.isInitialized = true;
1097
+ this.state.config = { ...config };
1098
+ console.log("\u{1F680} CrudifyInitializer - Initialization completed successfully");
1101
1099
  } catch (error) {
1102
- const parsedErrors = handleCrudifyError(error);
1103
- const translatedErrors = parsedErrors.map(translateError);
1104
- setErrors(translatedErrors);
1105
- if (onError) {
1106
- onError(translatedErrors.join(", "));
1107
- }
1100
+ this.state.initializationError = error instanceof Error ? error.message : "Unknown initialization error";
1101
+ console.error("\u{1F680} CrudifyInitializer - Initialization failed:", this.state.initializationError);
1102
+ throw error;
1108
1103
  } finally {
1109
- setLoading(false);
1110
- }
1111
- };
1112
- const handleBack = () => {
1113
- onScreenChange?.("login");
1114
- };
1115
- const handleGoToCheckCode = () => {
1116
- if (emailSent || codeAlreadyExists) {
1117
- onScreenChange?.("checkCode", { email });
1118
- return;
1119
- }
1120
- if (!email) {
1121
- setHelperTextEmail(t("forgotPassword.emailRequired"));
1122
- return;
1123
- }
1124
- if (!validateEmail(email)) {
1125
- setHelperTextEmail(t("forgotPassword.invalidEmail"));
1126
- return;
1104
+ this.state.isInitializing = false;
1105
+ this.state.initializationPromise = null;
1127
1106
  }
1128
- onScreenChange?.("checkCode", { email });
1129
- };
1130
- if (emailSent || codeAlreadyExists) {
1131
- 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: [
1132
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1133
- /* @__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") }),
1134
- /* @__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") })
1135
- ] }),
1136
- /* @__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") }),
1137
- /* @__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") }) })
1138
- ] }) });
1139
1107
  }
1140
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1141
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1142
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
1143
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
1144
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
1145
- ] }),
1146
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1148
- import_material2.Typography,
1149
- {
1150
- variant: "body2",
1151
- component: "label",
1152
- htmlFor: "email",
1153
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1154
- children: t("forgotPassword.emailLabel")
1155
- }
1156
- ),
1157
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1158
- import_material2.TextField,
1159
- {
1160
- fullWidth: true,
1161
- id: "email",
1162
- name: "email",
1163
- type: "email",
1164
- value: email,
1165
- disabled: loading,
1166
- onChange: (e) => setEmail(e.target.value),
1167
- error: !!helperTextEmail,
1168
- helperText: helperTextEmail,
1169
- autoComplete: "email",
1170
- placeholder: t("forgotPassword.emailPlaceholder"),
1171
- required: true
1172
- }
1173
- )
1174
- ] }),
1175
- /* @__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") }),
1176
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
1177
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
1178
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
1179
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
1180
- ] })
1181
- ] }),
1182
- /* @__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)) })
1183
- ] });
1184
- };
1185
- var ForgotPasswordForm_default = ForgotPasswordForm;
1186
-
1187
- // src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
1188
- var import_react7 = require("react");
1189
- var import_material3 = require("@mui/material");
1190
- var import_jsx_runtime6 = require("react/jsx-runtime");
1191
- var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
1192
- const { crudify: crudify7 } = useCrudify();
1193
- const [newPassword, setNewPassword] = (0, import_react7.useState)("");
1194
- const [confirmPassword, setConfirmPassword] = (0, import_react7.useState)("");
1195
- const [loading, setLoading] = (0, import_react7.useState)(false);
1196
- const [errors, setErrors] = (0, import_react7.useState)([]);
1197
- const [helperTextNewPassword, setHelperTextNewPassword] = (0, import_react7.useState)(null);
1198
- const [helperTextConfirmPassword, setHelperTextConfirmPassword] = (0, import_react7.useState)(null);
1199
- const [email, setEmail] = (0, import_react7.useState)("");
1200
- const [code, setCode] = (0, import_react7.useState)("");
1201
- const [fromCodeVerification, setFromCodeVerification] = (0, import_react7.useState)(false);
1202
- const [validatingCode, setValidatingCode] = (0, import_react7.useState)(true);
1203
- const [codeValidated, setCodeValidated] = (0, import_react7.useState)(false);
1204
- const [pendingValidation, setPendingValidation] = (0, import_react7.useState)(null);
1205
- const [isValidating, setIsValidating] = (0, import_react7.useState)(false);
1206
- const { t } = useTranslation();
1207
- const translateError = (parsedError) => {
1208
- const possibleKeys = [
1209
- `errors.auth.${parsedError.code}`,
1210
- `errors.data.${parsedError.code}`,
1211
- `errors.system.${parsedError.code}`,
1212
- `errors.${parsedError.code}`,
1213
- `resetPassword.${parsedError.code.toLowerCase()}`
1214
- ];
1215
- for (const key of possibleKeys) {
1216
- const translated = t(key);
1217
- if (translated !== key) {
1218
- return translated;
1219
- }
1220
- }
1221
- return parsedError.message || t("error.unknown");
1222
- };
1223
- const getParam = (key) => {
1224
- if (!searchParams) return null;
1225
- if (searchParams instanceof URLSearchParams) {
1226
- return searchParams.get(key);
1227
- }
1228
- return searchParams[key] || null;
1229
- };
1230
- (0, import_react7.useEffect)(() => {
1231
- if (!searchParams) {
1232
- return;
1233
- }
1234
- if (searchParams) {
1235
- const fromCodeVerificationParam = getParam("fromCodeVerification");
1236
- const emailParam = getParam("email");
1237
- const codeParam = getParam("code");
1238
- if (fromCodeVerificationParam === "true" && emailParam && codeParam) {
1239
- setEmail(emailParam);
1240
- setCode(codeParam);
1241
- setFromCodeVerification(true);
1242
- setCodeValidated(true);
1243
- setValidatingCode(false);
1244
- return;
1245
- }
1246
- const linkParam = getParam("link");
1247
- if (linkParam) {
1248
- try {
1249
- const decodedLink = decodeURIComponent(linkParam);
1250
- const [linkCode, linkEmail] = decodedLink.split("/");
1251
- if (linkCode && linkEmail && linkCode.length === 6) {
1252
- setCode(linkCode);
1253
- setEmail(linkEmail);
1254
- setFromCodeVerification(false);
1255
- setPendingValidation({ email: linkEmail, code: linkCode });
1256
- return;
1257
- }
1258
- } catch (error) {
1259
- }
1260
- }
1261
- if (emailParam && codeParam) {
1262
- setEmail(emailParam);
1263
- setCode(codeParam);
1264
- setFromCodeVerification(false);
1265
- setPendingValidation({ email: emailParam, code: codeParam });
1266
- return;
1267
- }
1268
- }
1269
- setErrors([t("resetPassword.invalidCode")]);
1270
- setValidatingCode(false);
1271
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1272
- }, [searchParams, crudify7, t, onScreenChange]);
1273
- (0, import_react7.useEffect)(() => {
1274
- if (crudify7 && pendingValidation && !isValidating) {
1275
- setIsValidating(true);
1276
- const validateCode = async (emailToValidate, codeToValidate) => {
1277
- try {
1278
- const data = [
1279
- {
1280
- operation: "validatePasswordResetCode",
1281
- data: { email: emailToValidate, codePassword: codeToValidate }
1282
- }
1283
- ];
1284
- const response = await crudify7.transaction(data);
1285
- if (response.data && Array.isArray(response.data)) {
1286
- const validationResult = response.data[0];
1287
- if (validationResult && validationResult.response && validationResult.response.status === "OK") {
1288
- setCodeValidated(true);
1289
- return;
1290
- }
1291
- }
1292
- if (response.success) {
1293
- setCodeValidated(true);
1294
- } else {
1295
- const parsedErrors = handleCrudifyError(response);
1296
- const translatedErrors = parsedErrors.map(translateError);
1297
- setErrors(translatedErrors);
1298
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1299
- }
1300
- } catch (error) {
1301
- const parsedErrors = handleCrudifyError(error);
1302
- const translatedErrors = parsedErrors.map(translateError);
1303
- setErrors(translatedErrors);
1304
- setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1305
- } finally {
1306
- setValidatingCode(false);
1307
- setPendingValidation(null);
1308
- setIsValidating(false);
1309
- }
1310
- };
1311
- validateCode(pendingValidation.email, pendingValidation.code);
1312
- }
1313
- }, [crudify7, pendingValidation, t, onScreenChange]);
1314
- const validatePassword = (password) => {
1315
- if (password.length < 8) {
1316
- return t("resetPassword.passwordTooShort");
1317
- }
1318
- return null;
1319
- };
1320
- const handleSubmit = async () => {
1321
- if (loading || !crudify7) return;
1322
- setErrors([]);
1323
- setHelperTextNewPassword(null);
1324
- setHelperTextConfirmPassword(null);
1325
- let hasErrors = false;
1326
- if (!newPassword) {
1327
- setHelperTextNewPassword(t("resetPassword.newPasswordRequired"));
1328
- hasErrors = true;
1329
- } else {
1330
- const passwordError = validatePassword(newPassword);
1331
- if (passwordError) {
1332
- setHelperTextNewPassword(passwordError);
1333
- hasErrors = true;
1334
- }
1335
- }
1336
- if (!confirmPassword) {
1337
- setHelperTextConfirmPassword(t("resetPassword.confirmPasswordRequired"));
1338
- hasErrors = true;
1339
- } else if (newPassword !== confirmPassword) {
1340
- setHelperTextConfirmPassword(t("resetPassword.passwordsDoNotMatch"));
1341
- hasErrors = true;
1108
+ /**
1109
+ * Perform the actual initialization process
1110
+ */
1111
+ async performInitialization(config) {
1112
+ if (!config.publicApiKey) {
1113
+ throw new Error("publicApiKey is required for crudify initialization");
1342
1114
  }
1343
- if (hasErrors) return;
1344
- setLoading(true);
1115
+ console.log("\u{1F680} CrudifyInitializer - Starting initialization with config:", {
1116
+ env: config.env,
1117
+ publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
1118
+ appName: config.appName
1119
+ });
1345
1120
  try {
1346
- const data = [
1347
- {
1348
- operation: "validateAndResetPassword",
1349
- data: { email, codePassword: code, newPassword }
1350
- }
1351
- ];
1352
- const response = await crudify7.transaction(data);
1353
- if (response.success) {
1354
- setErrors([]);
1355
- setTimeout(() => {
1356
- onResetSuccess?.();
1357
- }, 1e3);
1358
- } else {
1359
- const parsedErrors = handleCrudifyError(response);
1360
- const translatedErrors = parsedErrors.map(translateError);
1361
- setErrors(translatedErrors);
1362
- }
1121
+ const environment = config.env || "prod";
1122
+ console.log("\u{1F680} CrudifyInitializer - Step 1: Configuring environment:", environment);
1123
+ await import_crudify_browser2.default.config(environment);
1124
+ console.log("\u{1F680} CrudifyInitializer - Step 2: Initializing with API key");
1125
+ await import_crudify_browser2.default.init(config.publicApiKey, "none");
1126
+ console.log("\u{1F680} CrudifyInitializer - Step 3: Verifying initialization");
1127
+ await this.verifyInitialization();
1128
+ console.log("\u{1F680} CrudifyInitializer - All initialization steps completed");
1363
1129
  } catch (error) {
1364
- const parsedErrors = handleCrudifyError(error);
1365
- const translatedErrors = parsedErrors.map(translateError);
1366
- setErrors(translatedErrors);
1367
- if (onError) {
1368
- onError(translatedErrors.join(", "));
1130
+ console.error("\u{1F680} CrudifyInitializer - Initialization failed at step:", error);
1131
+ throw new Error(
1132
+ `Crudify initialization failed: ${error instanceof Error ? error.message : "Unknown error"}. Please check your configuration (env: ${config.env || "prod"}, publicApiKey: ${config.publicApiKey ? "provided" : "missing"})`
1133
+ );
1134
+ }
1135
+ }
1136
+ /**
1137
+ * Verify that crudify is properly initialized by checking core methods
1138
+ */
1139
+ async verifyInitialization() {
1140
+ const requiredMethods = ["readItems", "readItem", "createItem", "updateItem", "deleteItem", "login", "transaction"];
1141
+ const missingMethods = [];
1142
+ for (const method of requiredMethods) {
1143
+ if (typeof import_crudify_browser2.default[method] !== "function") {
1144
+ missingMethods.push(method);
1369
1145
  }
1370
1146
  }
1371
- setLoading(false);
1372
- };
1373
- const handleBack = () => {
1374
- if (fromCodeVerification) {
1375
- onScreenChange?.("checkCode", { email });
1376
- } else {
1377
- onScreenChange?.("forgotPassword");
1147
+ if (missingMethods.length > 0) {
1148
+ throw new Error(
1149
+ `Crudify initialization incomplete. Missing methods: ${missingMethods.join(", ")}. This usually indicates a configuration or network issue.`
1150
+ );
1378
1151
  }
1379
- };
1380
- if (validatingCode) {
1381
- 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, {}) });
1152
+ console.log("\u{1F680} CrudifyInitializer - Verification successful (test call skipped for performance)");
1382
1153
  }
1383
- if (!codeValidated) {
1384
- 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)) });
1154
+ /**
1155
+ * Check if the given configuration is the same as the current one
1156
+ */
1157
+ isConfigurationSame(config) {
1158
+ if (!this.state.config) return false;
1159
+ return this.state.config.env === config.env && this.state.config.publicApiKey === config.publicApiKey;
1160
+ }
1161
+ /**
1162
+ * Reset the initialization state (useful for testing or configuration changes)
1163
+ */
1164
+ reset() {
1165
+ console.log("\u{1F680} CrudifyInitializer - Resetting initialization state");
1166
+ this.state = {
1167
+ isInitialized: false,
1168
+ isInitializing: false,
1169
+ initializationError: null,
1170
+ config: null,
1171
+ initializationPromise: null
1172
+ };
1173
+ }
1174
+ /**
1175
+ * Get the current initialization status
1176
+ */
1177
+ getStatus() {
1178
+ return {
1179
+ isInitialized: this.state.isInitialized,
1180
+ isInitializing: this.state.isInitializing,
1181
+ initializationError: this.state.initializationError,
1182
+ config: this.state.config
1183
+ };
1184
+ }
1185
+ /**
1186
+ * Check if crudify is ready to use
1187
+ */
1188
+ isReady() {
1189
+ return this.state.isInitialized && !this.state.initializationError;
1190
+ }
1191
+ /**
1192
+ * Get the current initialization error, if any
1193
+ */
1194
+ getError() {
1195
+ return this.state.initializationError;
1196
+ }
1197
+ /**
1198
+ * Force re-initialization (useful when configuration changes)
1199
+ */
1200
+ async reinitialize(config) {
1201
+ console.log("\u{1F680} CrudifyInitializer - Forcing re-initialization");
1202
+ this.reset();
1203
+ await this.initialize(config);
1204
+ }
1205
+ /**
1206
+ * Check if initialization is currently in progress
1207
+ */
1208
+ isInitializing() {
1209
+ return this.state.isInitializing;
1210
+ }
1211
+ /**
1212
+ * Wait for any ongoing initialization to complete
1213
+ */
1214
+ async waitForInitialization() {
1215
+ if (this.state.initializationPromise) {
1216
+ await this.state.initializationPromise;
1217
+ }
1385
1218
  }
1386
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1387
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1388
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
1389
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
1390
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
1391
- ] }),
1392
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
1393
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1394
- import_material3.Typography,
1395
- {
1396
- variant: "body2",
1397
- component: "label",
1398
- htmlFor: "newPassword",
1399
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1400
- children: t("resetPassword.newPasswordLabel")
1401
- }
1402
- ),
1403
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1404
- import_material3.TextField,
1405
- {
1406
- fullWidth: true,
1407
- id: "newPassword",
1408
- name: "newPassword",
1409
- type: "password",
1410
- value: newPassword,
1411
- disabled: loading,
1412
- onChange: (e) => setNewPassword(e.target.value),
1413
- error: !!helperTextNewPassword,
1414
- helperText: helperTextNewPassword,
1415
- autoComplete: "new-password",
1416
- placeholder: t("resetPassword.newPasswordPlaceholder"),
1417
- required: true
1418
- }
1419
- )
1420
- ] }),
1421
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
1422
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1423
- import_material3.Typography,
1424
- {
1425
- variant: "body2",
1426
- component: "label",
1427
- htmlFor: "confirmPassword",
1428
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1429
- children: t("resetPassword.confirmPasswordLabel")
1430
- }
1431
- ),
1432
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1433
- import_material3.TextField,
1434
- {
1435
- fullWidth: true,
1436
- id: "confirmPassword",
1437
- name: "confirmPassword",
1438
- type: "password",
1439
- value: confirmPassword,
1440
- disabled: loading,
1441
- onChange: (e) => setConfirmPassword(e.target.value),
1442
- error: !!helperTextConfirmPassword,
1443
- helperText: helperTextConfirmPassword,
1444
- autoComplete: "new-password",
1445
- placeholder: t("resetPassword.confirmPasswordPlaceholder"),
1446
- required: true
1447
- }
1448
- )
1449
- ] }),
1450
- /* @__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") }),
1451
- /* @__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") }) })
1452
- ] }),
1453
- /* @__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)) })
1454
- ] });
1455
1219
  };
1456
- var ResetPasswordForm_default = ResetPasswordForm;
1220
+ _CrudifyInitializer.instance = null;
1221
+ var CrudifyInitializer = _CrudifyInitializer;
1222
+ var crudifyInitializer = CrudifyInitializer.getInstance();
1457
1223
 
1458
- // src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
1459
- var import_react8 = require("react");
1460
- var import_material4 = require("@mui/material");
1461
- var import_jsx_runtime7 = require("react/jsx-runtime");
1462
- var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
1463
- const { crudify: crudify7 } = useCrudify();
1464
- const [code, setCode] = (0, import_react8.useState)("");
1465
- const [loading, setLoading] = (0, import_react8.useState)(false);
1466
- const [errors, setErrors] = (0, import_react8.useState)([]);
1467
- const [helperTextCode, setHelperTextCode] = (0, import_react8.useState)(null);
1468
- const [email, setEmail] = (0, import_react8.useState)("");
1469
- const { t } = useTranslation();
1470
- const getParam = (key) => {
1471
- if (!searchParams) return null;
1472
- if (searchParams instanceof URLSearchParams) {
1473
- return searchParams.get(key);
1474
- }
1475
- return searchParams[key] || null;
1476
- };
1477
- const translateError = (parsedError) => {
1478
- const possibleKeys = [
1479
- `errors.auth.${parsedError.code}`,
1480
- `errors.data.${parsedError.code}`,
1481
- `errors.system.${parsedError.code}`,
1482
- `errors.${parsedError.code}`,
1483
- `checkCode.${parsedError.code.toLowerCase()}`
1484
- ];
1485
- for (const key of possibleKeys) {
1486
- const translated = t(key);
1487
- if (translated !== key) {
1488
- return translated;
1489
- }
1224
+ // src/core/TokenManager.ts
1225
+ var import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
1226
+
1227
+ // src/utils/jwtUtils.ts
1228
+ var decodeJwtSafely = (token) => {
1229
+ try {
1230
+ const parts = token.split(".");
1231
+ if (parts.length !== 3) {
1232
+ console.warn("Invalid JWT format: token must have 3 parts");
1233
+ return null;
1490
1234
  }
1491
- return parsedError.message || t("error.unknown");
1492
- };
1493
- (0, import_react8.useEffect)(() => {
1494
- const emailParam = getParam("email");
1495
- if (emailParam) {
1496
- setEmail(emailParam);
1497
- } else {
1498
- onScreenChange?.("forgotPassword");
1235
+ const payload = parts[1];
1236
+ const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
1237
+ const decodedPayload = JSON.parse(atob(paddedPayload));
1238
+ return decodedPayload;
1239
+ } catch (error) {
1240
+ console.warn("Failed to decode JWT token:", error);
1241
+ return null;
1242
+ }
1243
+ };
1244
+ var getCurrentUserEmail = () => {
1245
+ try {
1246
+ let token = null;
1247
+ token = sessionStorage.getItem("authToken");
1248
+ console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
1249
+ if (!token) {
1250
+ token = sessionStorage.getItem("token");
1251
+ console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
1499
1252
  }
1500
- }, [searchParams, onScreenChange]);
1501
- const handleSubmit = async () => {
1502
- if (loading || !crudify7) return;
1503
- setErrors([]);
1504
- setHelperTextCode(null);
1505
- if (!code) {
1506
- setHelperTextCode(t("checkCode.codeRequired"));
1507
- return;
1253
+ if (!token) {
1254
+ token = localStorage.getItem("authToken") || localStorage.getItem("token");
1255
+ console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
1508
1256
  }
1509
- if (code.length !== 6) {
1510
- setHelperTextCode(t("checkCode.codeRequired"));
1511
- return;
1257
+ if (!token) {
1258
+ console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
1259
+ return null;
1512
1260
  }
1513
- setLoading(true);
1514
- try {
1515
- const data = [
1516
- {
1517
- operation: "validatePasswordResetCode",
1518
- data: { email, codePassword: code }
1519
- }
1520
- ];
1521
- const response = await crudify7.transaction(data);
1522
- if (response.success) {
1523
- onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
1524
- } else {
1525
- const parsedErrors = handleCrudifyError(response);
1526
- const translatedErrors = parsedErrors.map(translateError);
1527
- setErrors(translatedErrors);
1528
- setLoading(false);
1529
- }
1530
- } catch (error) {
1531
- const parsedErrors = handleCrudifyError(error);
1532
- const translatedErrors = parsedErrors.map(translateError);
1533
- setErrors(translatedErrors);
1534
- setLoading(false);
1535
- if (onError) {
1536
- onError(translatedErrors.join(", "));
1537
- }
1538
- }
1539
- };
1540
- const handleBack = () => {
1541
- onScreenChange?.("forgotPassword");
1542
- };
1543
- const handleCodeChange = (event) => {
1544
- const value = event.target.value.replace(/\D/g, "").slice(0, 6);
1545
- setCode(value);
1546
- };
1547
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1548
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
1549
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { sx: { mb: 2 }, children: [
1550
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
1551
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
1552
- ] }),
1553
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
1554
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1555
- import_material4.Typography,
1556
- {
1557
- variant: "body2",
1558
- component: "label",
1559
- htmlFor: "code",
1560
- sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
1561
- children: t("checkCode.codeLabel")
1562
- }
1563
- ),
1564
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1565
- import_material4.TextField,
1566
- {
1567
- fullWidth: true,
1568
- id: "code",
1569
- name: "code",
1570
- type: "text",
1571
- value: code,
1572
- disabled: loading,
1573
- onChange: handleCodeChange,
1574
- error: !!helperTextCode,
1575
- helperText: helperTextCode,
1576
- placeholder: t("checkCode.codePlaceholder"),
1577
- inputProps: {
1578
- maxLength: 6,
1579
- style: { textAlign: "center", fontSize: "1.5rem", letterSpacing: "0.4rem" }
1580
- },
1581
- required: true
1582
- }
1583
- )
1584
- ] }),
1585
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1586
- import_material4.Button,
1587
- {
1588
- disabled: loading || code.length !== 6,
1589
- type: "button",
1590
- onClick: handleSubmit,
1591
- fullWidth: true,
1592
- variant: "contained",
1593
- color: "primary",
1594
- sx: { mt: 2, mb: 2 },
1595
- children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material4.CircularProgress, { size: 20 }) : t("checkCode.verifyButton")
1596
- }
1597
- ),
1598
- /* @__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") }) })
1599
- ] }),
1600
- /* @__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)) })
1601
- ] });
1602
- };
1603
- var CheckCodeForm_default = CheckCodeForm;
1604
-
1605
- // src/components/CrudifyLogin/components/CrudifyInitializer.tsx
1606
- var import_material5 = require("@mui/material");
1607
- var import_jsx_runtime8 = require("react/jsx-runtime");
1608
- var CrudifyInitializer = ({ children, fallback }) => {
1609
- const { isLoading, error, isInitialized } = useCrudify();
1610
- const { t } = useTranslation();
1611
- if (isLoading) {
1612
- return fallback || /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1613
- import_material5.Box,
1614
- {
1615
- sx: {
1616
- display: "flex",
1617
- flexDirection: "column",
1618
- alignItems: "center",
1619
- justifyContent: "center",
1620
- minHeight: "200px",
1621
- gap: 2
1622
- },
1623
- children: [
1624
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.CircularProgress, {}),
1625
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material5.Typography, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
1626
- ]
1627
- }
1628
- );
1629
- }
1630
- if (error) {
1631
- 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: [
1632
- t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
1633
- ":",
1634
- " ",
1635
- error
1636
- ] }) });
1637
- }
1638
- if (!isInitialized) {
1639
- 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" }) });
1640
- }
1641
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children });
1642
- };
1643
-
1644
- // src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
1645
- var import_react9 = require("react");
1646
- var useCrudifyLogin = (config, _options = {}) => {
1647
- const finalConfig = (0, import_react9.useMemo)(() => {
1648
- const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
1649
- const rawEnv = config.env || getCookie("environment") || "prod";
1650
- const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
1651
- const appName = config.appName || getCookie("appName") || "Crudia";
1652
- const loginActions = config.loginActions || (() => {
1653
- try {
1654
- const cookieValue = getCookie("loginActions");
1655
- return cookieValue ? cookieValue.split(",").map((action) => action.trim()).filter(Boolean) : [];
1656
- } catch {
1657
- return [];
1658
- }
1659
- })();
1660
- return {
1661
- publicApiKey,
1662
- env,
1663
- appName,
1664
- loginActions
1665
- };
1666
- }, [config]);
1667
- return { config: finalConfig };
1668
- };
1669
-
1670
- // src/components/CrudifyLogin/index.tsx
1671
- var import_jsx_runtime9 = require("react/jsx-runtime");
1672
- var CrudifyLoginInternal = ({
1673
- onScreenChange,
1674
- onExternalNavigate,
1675
- onLoginSuccess,
1676
- onError,
1677
- redirectUrl = "/"
1678
- }) => {
1679
- const { t } = useTranslation();
1680
- const { state, setScreen } = useLoginState();
1681
- const handleScreenChange = (screen2, params) => {
1682
- let finalParams = params;
1683
- if (screen2 === "login") {
1684
- finalParams = {};
1685
- } else if (screen2 === "forgotPassword" && !params) {
1686
- finalParams = {};
1687
- }
1688
- setScreen(screen2, finalParams);
1689
- onScreenChange?.(screen2, finalParams);
1690
- };
1691
- const renderCurrentForm = () => {
1692
- const commonProps = {
1693
- onScreenChange: handleScreenChange,
1694
- onExternalNavigate,
1695
- onError,
1696
- redirectUrl
1697
- };
1698
- switch (state.currentScreen) {
1699
- case "forgotPassword":
1700
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ForgotPasswordForm_default, { ...commonProps });
1701
- case "checkCode":
1702
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckCodeForm_default, { ...commonProps, searchParams: state.searchParams });
1703
- case "resetPassword":
1704
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1705
- ResetPasswordForm_default,
1706
- {
1707
- ...commonProps,
1708
- searchParams: state.searchParams,
1709
- onResetSuccess: () => {
1710
- handleScreenChange("login");
1711
- }
1712
- }
1713
- );
1714
- default:
1715
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LoginForm_default, { ...commonProps, onLoginSuccess });
1716
- }
1717
- };
1718
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(CrudifyInitializer, { children: [
1719
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material6.Box, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1720
- "img",
1721
- {
1722
- src: state.config.logo || "/nocios-default.png",
1723
- alt: t("login.logoAlt"),
1724
- style: {
1725
- width: "100%",
1726
- maxWidth: "150px",
1727
- height: "auto"
1728
- },
1729
- onError: (e) => {
1730
- const target = e.target;
1731
- target.src = "/nocios-default.png";
1732
- }
1733
- }
1734
- ) }),
1735
- state.config.appName && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1736
- import_material6.Typography,
1737
- {
1738
- variant: "h6",
1739
- component: "h1",
1740
- sx: {
1741
- textAlign: "center",
1742
- mb: 2,
1743
- color: state.config.colors?.primaryColor || "#1066BA"
1744
- },
1745
- children: state.config.appName
1746
- }
1747
- ),
1748
- renderCurrentForm()
1749
- ] });
1750
- };
1751
- var CrudifyLogin = ({
1752
- translations,
1753
- translationsUrl,
1754
- language = "en",
1755
- config = {},
1756
- initialScreen = "login",
1757
- autoReadFromCookies = true,
1758
- ...props
1759
- }) => {
1760
- const { config: finalConfig } = useCrudifyLogin(config);
1761
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(I18nProvider, { translations, translationsUrl, language, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CrudifyProvider, { config: finalConfig, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LoginStateProvider, { config, initialScreen, autoReadFromCookies, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CrudifyLoginInternal, { config, ...props }) }) }) });
1762
- };
1763
- var CrudifyLogin_default = CrudifyLogin;
1764
-
1765
- // src/components/UserProfile/UserProfileDisplay.tsx
1766
- var import_material7 = require("@mui/material");
1767
- var import_icons_material = require("@mui/icons-material");
1768
-
1769
- // src/hooks/useUserProfile.ts
1770
- var import_react10 = require("react");
1771
- var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
1772
-
1773
- // src/utils/jwtUtils.ts
1774
- var decodeJwtSafely = (token) => {
1775
- try {
1776
- const parts = token.split(".");
1777
- if (parts.length !== 3) {
1778
- console.warn("Invalid JWT format: token must have 3 parts");
1779
- return null;
1780
- }
1781
- const payload = parts[1];
1782
- const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
1783
- const decodedPayload = JSON.parse(atob(paddedPayload));
1784
- return decodedPayload;
1785
- } catch (error) {
1786
- console.warn("Failed to decode JWT token:", error);
1787
- return null;
1788
- }
1789
- };
1790
- var getCurrentUserEmail = () => {
1791
- try {
1792
- let token = null;
1793
- token = sessionStorage.getItem("authToken");
1794
- console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
1795
- if (!token) {
1796
- token = sessionStorage.getItem("token");
1797
- console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
1798
- }
1799
- if (!token) {
1800
- token = localStorage.getItem("authToken") || localStorage.getItem("token");
1801
- console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
1802
- }
1803
- if (!token) {
1804
- console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
1805
- return null;
1806
- }
1807
- const payload = decodeJwtSafely(token);
1808
- if (!payload) {
1809
- console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
1810
- return null;
1261
+ const payload = decodeJwtSafely(token);
1262
+ if (!payload) {
1263
+ console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
1264
+ return null;
1811
1265
  }
1812
1266
  const email = payload.email || payload["cognito:username"] || null;
1813
1267
  console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
@@ -1828,1316 +1282,1853 @@ var isTokenExpired = (token) => {
1828
1282
  }
1829
1283
  };
1830
1284
 
1831
- // src/hooks/useUserProfile.ts
1832
- var useUserProfile = (options = {}) => {
1833
- const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
1834
- const [userProfile, setUserProfile] = (0, import_react10.useState)(null);
1835
- const [loading, setLoading] = (0, import_react10.useState)(false);
1836
- const [error, setError] = (0, import_react10.useState)(null);
1837
- const [extendedData, setExtendedData] = (0, import_react10.useState)({});
1838
- const abortControllerRef = (0, import_react10.useRef)(null);
1839
- const mountedRef = (0, import_react10.useRef)(true);
1840
- const requestIdRef = (0, import_react10.useRef)(0);
1841
- const retryCountRef = (0, import_react10.useRef)(0);
1842
- const clearProfile = (0, import_react10.useCallback)(() => {
1843
- setUserProfile(null);
1844
- setError(null);
1845
- setLoading(false);
1846
- setExtendedData({});
1847
- }, []);
1848
- const refreshProfile = (0, import_react10.useCallback)(async () => {
1849
- const userEmail = getCurrentUserEmail();
1850
- if (!userEmail) {
1851
- if (mountedRef.current) {
1852
- setError("No user email available");
1853
- setLoading(false);
1854
- }
1855
- return;
1856
- }
1857
- if (abortControllerRef.current) {
1858
- abortControllerRef.current.abort();
1285
+ // src/core/TokenManager.ts
1286
+ var _TokenManager = class _TokenManager {
1287
+ constructor() {
1288
+ this.TOKEN_KEY = "authToken";
1289
+ // Compatible with crudia-ui
1290
+ this.tokenCache = null;
1291
+ this.parsedTokenCache = null;
1292
+ this.expirationCheckInterval = null;
1293
+ this.storageEventListener = null;
1294
+ this.initializeTokenManager();
1295
+ }
1296
+ /**
1297
+ * Singleton pattern to ensure consistent token management
1298
+ */
1299
+ static getInstance() {
1300
+ if (!_TokenManager.instance) {
1301
+ _TokenManager.instance = new _TokenManager();
1859
1302
  }
1860
- const abortController = new AbortController();
1861
- abortControllerRef.current = abortController;
1862
- const currentRequestId = ++requestIdRef.current;
1863
- try {
1864
- if (mountedRef.current) {
1865
- setLoading(true);
1866
- setError(null);
1867
- }
1868
- const response = await import_crudify_browser2.default.readItems("users", {
1869
- where: { email: userEmail },
1870
- limit: 1
1871
- });
1872
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
1873
- if (response.success && response.data && response.data.length > 0) {
1874
- const userData = response.data[0];
1875
- setUserProfile(userData);
1876
- const additionalData = {
1877
- fullProfile: userData,
1878
- totalFields: Object.keys(userData).length,
1879
- displayData: {
1880
- id: userData.id,
1881
- email: userData.email,
1882
- username: userData.username,
1883
- firstName: userData.firstName,
1884
- lastName: userData.lastName,
1885
- fullName: userData.fullName || `${userData.firstName || ""} ${userData.lastName || ""}`.trim(),
1886
- role: userData.role,
1887
- permissions: userData.permissions || [],
1888
- isActive: userData.isActive,
1889
- lastLogin: userData.lastLogin,
1890
- createdAt: userData.createdAt,
1891
- updatedAt: userData.updatedAt,
1892
- // Include any custom fields
1893
- ...Object.keys(userData).filter((key) => !["id", "email", "username", "firstName", "lastName", "fullName", "role", "permissions", "isActive", "lastLogin", "createdAt", "updatedAt"].includes(key)).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
1894
- }
1895
- };
1896
- setExtendedData(additionalData);
1897
- setError(null);
1898
- retryCountRef.current = 0;
1899
- } else {
1900
- setError("User profile not found");
1901
- setUserProfile(null);
1902
- setExtendedData({});
1903
- }
1904
- }
1905
- } catch (err) {
1906
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
1907
- const error2 = err;
1908
- if (error2.name === "AbortError") {
1909
- return;
1910
- }
1911
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
1912
- if (shouldRetry) {
1913
- retryCountRef.current++;
1914
- setTimeout(() => {
1915
- if (mountedRef.current) {
1916
- refreshProfile();
1917
- }
1918
- }, 1e3 * retryCountRef.current);
1919
- } else {
1920
- setError("Failed to load user profile");
1921
- setUserProfile(null);
1922
- setExtendedData({});
1923
- }
1924
- }
1925
- } finally {
1926
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
1927
- setLoading(false);
1928
- }
1929
- if (abortControllerRef.current === abortController) {
1930
- abortControllerRef.current = null;
1931
- }
1932
- }
1933
- }, [retryOnError, maxRetries]);
1934
- (0, import_react10.useEffect)(() => {
1935
- if (autoFetch) {
1936
- refreshProfile();
1937
- }
1938
- }, [autoFetch, refreshProfile]);
1939
- (0, import_react10.useEffect)(() => {
1940
- mountedRef.current = true;
1941
- return () => {
1942
- mountedRef.current = false;
1943
- if (abortControllerRef.current) {
1944
- abortControllerRef.current.abort();
1945
- abortControllerRef.current = null;
1946
- }
1947
- };
1948
- }, []);
1949
- return {
1950
- userProfile,
1951
- loading,
1952
- error,
1953
- extendedData,
1954
- refreshProfile,
1955
- clearProfile
1956
- };
1957
- };
1958
-
1959
- // src/components/UserProfile/UserProfileDisplay.tsx
1960
- var import_react11 = require("react");
1961
- var import_jsx_runtime10 = require("react/jsx-runtime");
1962
- var UserProfileDisplay = ({
1963
- showExtendedData = true,
1964
- showProfileCard = true,
1965
- autoRefresh = true
1966
- }) => {
1967
- const { userProfile, loading, error, extendedData, refreshProfile } = useUserProfile({
1968
- autoFetch: autoRefresh,
1969
- retryOnError: true,
1970
- maxRetries: 3
1971
- });
1972
- const [showAllFields, setShowAllFields] = (0, import_react11.useState)(false);
1973
- if (loading) {
1974
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", justifyContent: "center", alignItems: "center", p: 3, children: [
1975
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.CircularProgress, {}),
1976
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "body2", sx: { ml: 2 }, children: "Cargando perfil de usuario..." })
1977
- ] });
1978
- }
1979
- if (error) {
1980
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1981
- import_material7.Alert,
1982
- {
1983
- severity: "error",
1984
- action: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.IconButton, { color: "inherit", size: "small", onClick: refreshProfile, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "caption", children: "Reintentar" }) }),
1985
- children: [
1986
- "Error al cargar el perfil: ",
1987
- error
1988
- ]
1989
- }
1990
- );
1991
- }
1992
- if (!userProfile) {
1993
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Alert, { severity: "warning", children: "No se encontr\xF3 informaci\xF3n del usuario" });
1994
- }
1995
- const displayData = extendedData?.displayData || {};
1996
- const totalFields = extendedData?.totalFields || 0;
1997
- const formatDate = (dateString) => {
1998
- if (!dateString) return "No disponible";
1999
- try {
2000
- return new Date(dateString).toLocaleString("es-ES", {
2001
- year: "numeric",
2002
- month: "short",
2003
- day: "numeric",
2004
- hour: "2-digit",
2005
- minute: "2-digit"
2006
- });
2007
- } catch {
2008
- return dateString;
2009
- }
2010
- };
2011
- const renderFieldValue = (key, value) => {
2012
- if (value === null || value === void 0) return "No disponible";
2013
- if (typeof value === "boolean") return value ? "S\xED" : "No";
2014
- if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "Ninguno";
2015
- if (typeof value === "object") return JSON.stringify(value, null, 2);
2016
- return String(value);
2017
- };
2018
- const basicFields = [
2019
- { key: "id", label: "ID", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Badge, {}) },
2020
- { key: "email", label: "Email", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Email, {}) },
2021
- { key: "username", label: "Usuario", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Person, {}) },
2022
- { key: "fullName", label: "Nombre completo", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.AccountCircle, {}) },
2023
- { key: "role", label: "Rol", icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Security, {}) }
2024
- ];
2025
- const extendedFields = [
2026
- { key: "firstName", label: "Nombre" },
2027
- { key: "lastName", label: "Apellido" },
2028
- { key: "isActive", label: "Activo" },
2029
- { key: "lastLogin", label: "\xDAltimo login" },
2030
- { key: "createdAt", label: "Creado" },
2031
- { key: "updatedAt", label: "Actualizado" }
2032
- ];
2033
- const knownFields = [...basicFields.map((f) => f.key), ...extendedFields.map((f) => f.key), "permissions"];
2034
- const customFields = Object.keys(displayData).filter((key) => !knownFields.includes(key)).map((key) => ({ key, label: key }));
2035
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { children: [
2036
- showProfileCard && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Card, { sx: { mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.CardContent, { children: [
2037
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", alignItems: "center", mb: 2, children: [
2038
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2039
- import_material7.Avatar,
2040
- {
2041
- src: displayData.avatar,
2042
- sx: { width: 56, height: 56, mr: 2 },
2043
- children: displayData.fullName?.[0] || displayData.username?.[0] || displayData.email?.[0]
2044
- }
2045
- ),
2046
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { children: [
2047
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "h6", children: displayData.fullName || displayData.username || displayData.email }),
2048
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "body2", color: "text.secondary", children: displayData.role || "Usuario" }),
2049
- displayData.isActive !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2050
- import_material7.Chip,
2051
- {
2052
- label: displayData.isActive ? "Activo" : "Inactivo",
2053
- color: displayData.isActive ? "success" : "error",
2054
- size: "small",
2055
- sx: { mt: 0.5 }
2056
- }
2057
- )
2058
- ] })
2059
- ] }),
2060
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Box, { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: 2, children: basicFields.map(
2061
- ({ key, label, icon }) => displayData[key] ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", alignItems: "center", children: [
2062
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Box, { sx: { mr: 1, color: "text.secondary" }, children: icon }),
2063
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { children: [
2064
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "caption", color: "text.secondary", children: label }),
2065
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "body2", children: renderFieldValue(key, displayData[key]) })
2066
- ] })
2067
- ] }, key) : null
2068
- ) }),
2069
- displayData.permissions && Array.isArray(displayData.permissions) && displayData.permissions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { mt: 2, children: [
2070
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "caption", color: "text.secondary", display: "block", children: "Permisos" }),
2071
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", flexWrap: "wrap", gap: 0.5, mt: 0.5, children: [
2072
- displayData.permissions.slice(0, 5).map((permission, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Chip, { label: permission, size: "small", variant: "outlined" }, index)),
2073
- displayData.permissions.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Chip, { label: `+${displayData.permissions.length - 5} m\xE1s`, size: "small" })
2074
- ] })
2075
- ] })
2076
- ] }) }),
2077
- showExtendedData && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Card, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.CardContent, { children: [
2078
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2, children: [
2079
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Typography, { variant: "h6", display: "flex", alignItems: "center", children: [
2080
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Info, { sx: { mr: 1 } }),
2081
- "Informaci\xF3n Detallada"
2082
- ] }),
2083
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Chip, { label: `${totalFields} campos totales`, size: "small" })
2084
- ] }),
2085
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.List, { dense: true, children: [
2086
- extendedFields.map(({ key, label }) => displayData[key] !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.ListItem, { divider: true, children: [
2087
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.Schedule, { fontSize: "small" }) }),
2088
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2089
- import_material7.ListItemText,
2090
- {
2091
- primary: label,
2092
- secondary: key.includes("At") || key.includes("Login") ? formatDate(displayData[key]) : renderFieldValue(key, displayData[key])
2093
- }
2094
- )
2095
- ] }, key)),
2096
- customFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2097
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Divider, { sx: { my: 1 } }),
2098
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.ListItem, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2099
- import_material7.ListItemText,
2100
- {
2101
- primary: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Typography, { variant: "subtitle2", children: [
2103
- "Campos Personalizados (",
2104
- customFields.length,
2105
- ")"
2106
- ] }),
2107
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.IconButton, { size: "small", onClick: () => setShowAllFields(!showAllFields), children: showAllFields ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.ExpandLess, {}) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_icons_material.ExpandMore, {}) })
2108
- ] })
2109
- }
2110
- ) }),
2111
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Collapse, { in: showAllFields, children: customFields.map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.ListItem, { sx: { pl: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2112
- import_material7.ListItemText,
2113
- {
2114
- primary: label,
2115
- secondary: renderFieldValue(key, displayData[key])
2116
- }
2117
- ) }, key)) })
2118
- ] })
2119
- ] }),
2120
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Box, { mt: 2, display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2121
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_material7.Typography, { variant: "caption", color: "text.secondary", children: [
2122
- "\xDAltima actualizaci\xF3n: ",
2123
- formatDate(displayData.updatedAt)
2124
- ] }),
2125
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.IconButton, { size: "small", onClick: refreshProfile, disabled: loading, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material7.Typography, { variant: "caption", children: "Actualizar" }) })
2126
- ] })
2127
- ] }) })
2128
- ] });
2129
- };
2130
- var UserProfileDisplay_default = UserProfileDisplay;
2131
-
2132
- // src/providers/CrudifyDataProvider.tsx
2133
- var import_react12 = require("react");
2134
-
2135
- // src/core/ConfigurationManager.ts
2136
- var _ConfigurationManager = class _ConfigurationManager {
2137
- constructor() {
2138
- this.resolvedConfig = null;
2139
- this.configError = null;
1303
+ return _TokenManager.instance;
2140
1304
  }
2141
1305
  /**
2142
- * Singleton pattern to ensure consistent configuration across the app
1306
+ * Reset the singleton instance (useful for testing)
2143
1307
  */
2144
- static getInstance() {
2145
- if (!_ConfigurationManager.instance) {
2146
- _ConfigurationManager.instance = new _ConfigurationManager();
1308
+ static resetInstance() {
1309
+ if (_TokenManager.instance) {
1310
+ _TokenManager.instance.cleanup();
2147
1311
  }
2148
- return _ConfigurationManager.instance;
1312
+ _TokenManager.instance = null;
2149
1313
  }
2150
1314
  /**
2151
- * Reset the singleton instance (useful for testing)
1315
+ * Initialize the token manager with storage synchronization
2152
1316
  */
2153
- static resetInstance() {
2154
- _ConfigurationManager.instance = null;
1317
+ initializeTokenManager() {
1318
+ console.log("\u{1F510} TokenManager - Initializing token management");
1319
+ this.migrateFromLocalStorage();
1320
+ this.loadTokenFromStorage();
1321
+ this.setupExpirationCheck();
1322
+ this.setupStorageListener();
1323
+ console.log("\u{1F510} TokenManager - Initialization complete");
2155
1324
  }
2156
1325
  /**
2157
- * Resolve configuration from all sources with proper priority
1326
+ * Migrate tokens from localStorage to sessionStorage for better security
1327
+ * This ensures compatibility with older implementations
2158
1328
  */
2159
- resolveConfig(propsConfig = {}) {
2160
- if (this.resolvedConfig && this.isConfigStillValid(propsConfig)) {
2161
- return this.resolvedConfig;
2162
- }
1329
+ migrateFromLocalStorage() {
2163
1330
  try {
2164
- this.configError = null;
2165
- const envConfig = this.getEnvConfig();
2166
- const cookieConfig = this.getCookieConfig();
2167
- const configSource = {
2168
- env: "default",
2169
- publicApiKey: "default",
2170
- loginActions: "default",
2171
- appName: "default",
2172
- logo: "default",
2173
- colors: "default"
2174
- };
2175
- const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
2176
- const publicApiKey = this.resolveValue("publicApiKey", propsConfig.publicApiKey, envConfig.publicApiKey, cookieConfig.publicApiKey, void 0, configSource);
2177
- const loginActions = this.resolveValue("loginActions", propsConfig.loginActions, envConfig.loginActions, cookieConfig.loginActions, [], configSource);
2178
- const appName = this.resolveValue("appName", propsConfig.appName, envConfig.appName, cookieConfig.appName, "Crudify App", configSource);
2179
- const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
2180
- const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
2181
- if (!publicApiKey) {
2182
- throw new Error(
2183
- "publicApiKey is required. Provide it via:\n1. Props: <CrudifyDataProvider publicApiKey={...} />\n2. Environment: VITE_TEST_PUBLIC_API_KEY\n3. Cookie: publicApiKey"
2184
- );
2185
- }
2186
- this.resolvedConfig = {
2187
- env,
2188
- publicApiKey,
2189
- loginActions,
2190
- appName,
2191
- logo,
2192
- colors,
2193
- configSource,
2194
- rawConfig: {
2195
- props: propsConfig,
2196
- env: envConfig,
2197
- cookies: cookieConfig
1331
+ const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
1332
+ for (const key of legacyKeys) {
1333
+ const token = localStorage.getItem(key);
1334
+ if (token && !secureSessionStorage.getToken()) {
1335
+ console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
1336
+ secureSessionStorage.setToken(token);
1337
+ localStorage.removeItem(key);
1338
+ break;
2198
1339
  }
2199
- };
2200
- console.log("\u{1F527} ConfigurationManager - Configuration resolved:", {
2201
- config: {
2202
- env: this.resolvedConfig.env,
2203
- publicApiKey: `${this.resolvedConfig.publicApiKey.substring(0, 8)}...`,
2204
- appName: this.resolvedConfig.appName,
2205
- loginActionsCount: this.resolvedConfig.loginActions.length
2206
- },
2207
- sources: this.resolvedConfig.configSource
2208
- });
2209
- return this.resolvedConfig;
1340
+ }
2210
1341
  } catch (error) {
2211
- this.configError = error instanceof Error ? error.message : "Unknown configuration error";
2212
- console.error("\u{1F527} ConfigurationManager - Configuration error:", this.configError);
2213
- this.resolvedConfig = {
2214
- env: "prod",
2215
- publicApiKey: "",
2216
- loginActions: [],
2217
- appName: "Crudify App",
2218
- logo: "",
2219
- colors: {},
2220
- configSource: {
2221
- env: "default",
2222
- publicApiKey: "default",
2223
- loginActions: "default",
2224
- appName: "default",
2225
- logo: "default",
2226
- colors: "default"
2227
- },
2228
- rawConfig: {
2229
- props: propsConfig,
2230
- env: {},
2231
- cookies: {},
2232
- error: this.configError
2233
- }
2234
- };
2235
- return this.resolvedConfig;
1342
+ console.warn("\u{1F510} TokenManager - Token migration failed:", error);
2236
1343
  }
2237
1344
  }
2238
1345
  /**
2239
- * Check if current configuration is still valid for the given props
1346
+ * Load token from storage and synchronize with crudify
2240
1347
  */
2241
- isConfigStillValid(propsConfig) {
2242
- if (!this.resolvedConfig) return false;
2243
- const currentProps = this.resolvedConfig.rawConfig.props;
2244
- return JSON.stringify(currentProps) === JSON.stringify(propsConfig);
1348
+ loadTokenFromStorage() {
1349
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
1350
+ try {
1351
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure session storage");
1352
+ const storedToken = secureSessionStorage.getToken();
1353
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
1354
+ if (storedToken && this.isTokenValid(storedToken)) {
1355
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
1356
+ this.tokenCache = storedToken;
1357
+ this.parsedTokenCache = this.parseToken(storedToken);
1358
+ this.syncTokenWithCrudify(storedToken);
1359
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Token loaded from storage and synchronized");
1360
+ } else if (storedToken) {
1361
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists but is invalid/expired, clearing");
1362
+ this.clearToken();
1363
+ } else {
1364
+ console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: No stored token found");
1365
+ }
1366
+ } catch (error) {
1367
+ console.warn("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Error loading token from storage:", error);
1368
+ this.clearToken();
1369
+ }
2245
1370
  }
2246
1371
  /**
2247
- * Resolve a single config value with priority and source tracking
1372
+ * Set up automatic token expiration checking
2248
1373
  */
2249
- resolveValue(key, propsValue, envValue, cookieValue, defaultValue, configSource) {
2250
- if (propsValue !== void 0) {
2251
- configSource[key] = "props";
2252
- return propsValue;
2253
- }
2254
- if (envValue !== void 0) {
2255
- configSource[key] = "env";
2256
- return envValue;
2257
- }
2258
- if (cookieValue !== void 0) {
2259
- configSource[key] = "cookies";
2260
- return cookieValue;
2261
- }
2262
- configSource[key] = "default";
2263
- return defaultValue;
1374
+ setupExpirationCheck() {
1375
+ this.expirationCheckInterval = window.setInterval(() => {
1376
+ if (this.tokenCache && !this.isTokenValid(this.tokenCache)) {
1377
+ console.log("\u{1F510} TokenManager - Token expired, clearing automatically");
1378
+ this.clearToken();
1379
+ }
1380
+ }, 3e4);
2264
1381
  }
2265
1382
  /**
2266
- * Get configuration from environment variables
1383
+ * Set up storage event listener for cross-tab synchronization
2267
1384
  */
2268
- getEnvConfig() {
2269
- const config = {};
2270
- try {
2271
- } catch (error) {
2272
- console.warn("\u{1F527} ConfigurationManager - Environment variables not available:", error);
2273
- }
2274
- return config;
1385
+ setupStorageListener() {
1386
+ this.storageEventListener = (event) => {
1387
+ if (event.key === this.TOKEN_KEY) {
1388
+ console.log("\u{1F510} TokenManager - Token change detected from another tab");
1389
+ this.loadTokenFromStorage();
1390
+ }
1391
+ };
1392
+ window.addEventListener("storage", this.storageEventListener);
2275
1393
  }
2276
1394
  /**
2277
- * Get configuration from cookies (multi-tenant support)
1395
+ * Set a new JWT token with automatic synchronization
2278
1396
  */
2279
- getCookieConfig() {
2280
- const config = {};
1397
+ setToken(token) {
1398
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Entry point - setting token:", token ? "provided" : "null");
2281
1399
  try {
2282
- const env = getCookie("environment");
2283
- if (env && ["dev", "stg", "prod"].includes(env)) {
2284
- config.env = env;
2285
- }
2286
- const publicApiKey = getCookie("publicApiKey");
2287
- if (publicApiKey) {
2288
- config.publicApiKey = publicApiKey;
2289
- }
2290
- const appName = getCookie("appName");
2291
- if (appName) {
2292
- config.appName = appName;
2293
- }
2294
- const loginActions = getCookie("loginActions");
2295
- if (loginActions) {
2296
- config.loginActions = loginActions.split(",").map((action) => action.trim()).filter(Boolean);
2297
- }
2298
- const logo = getCookie("logo");
2299
- if (logo) {
2300
- config.logo = logo;
1400
+ if (!token) {
1401
+ console.log("\u{1F510} TokenManager - SET_TOKEN: No token provided, clearing token");
1402
+ this.clearToken();
1403
+ return;
2301
1404
  }
2302
- const colors = getCookie("colors");
2303
- if (colors) {
2304
- try {
2305
- config.colors = JSON.parse(colors);
2306
- } catch (error) {
2307
- console.warn("\u{1F527} ConfigurationManager - Failed to parse colors from cookie:", error);
2308
- }
1405
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Validating token before setting");
1406
+ if (!this.isTokenValid(token)) {
1407
+ console.warn("\u{1F510} TokenManager - SET_TOKEN: Attempted to set invalid or expired token");
1408
+ this.clearToken();
1409
+ return;
2309
1410
  }
1411
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Token is valid, updating cache");
1412
+ this.tokenCache = token;
1413
+ this.parsedTokenCache = this.parseToken(token);
1414
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
1415
+ secureSessionStorage.setToken(token);
1416
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
1417
+ this.syncTokenWithCrudify(token);
1418
+ console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
2310
1419
  } catch (error) {
2311
- console.warn("\u{1F527} ConfigurationManager - Error reading cookies:", error);
1420
+ console.error("\u{1F510} TokenManager - SET_TOKEN: Error setting token:", error);
1421
+ this.clearToken();
2312
1422
  }
2313
- return config;
2314
- }
2315
- /**
2316
- * Get the current resolved configuration
2317
- */
2318
- getConfig() {
2319
- return this.resolvedConfig;
2320
1423
  }
2321
1424
  /**
2322
- * Get any configuration errors
1425
+ * Get the current JWT token
2323
1426
  */
2324
- getConfigError() {
2325
- return this.configError;
1427
+ getToken() {
1428
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Entry point - checking cache");
1429
+ if (this.tokenCache) {
1430
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Cache exists, validating token");
1431
+ if (this.isTokenValid(this.tokenCache)) {
1432
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Cache valid, returning cached token");
1433
+ return this.tokenCache;
1434
+ } else {
1435
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Cache invalid, clearing cache");
1436
+ this.tokenCache = null;
1437
+ }
1438
+ } else {
1439
+ console.log("\u{1F510} TokenManager - GET_TOKEN: No cache, loading from storage");
1440
+ }
1441
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Loading from storage");
1442
+ this.loadTokenFromStorage();
1443
+ console.log("\u{1F510} TokenManager - GET_TOKEN: Returning final token:", !!this.tokenCache);
1444
+ return this.tokenCache;
2326
1445
  }
2327
1446
  /**
2328
- * Check if configuration is valid (no errors and has required fields)
1447
+ * Parse the current JWT token
2329
1448
  */
2330
- isConfigured() {
2331
- return this.resolvedConfig !== null && this.configError === null && !!this.resolvedConfig.publicApiKey;
1449
+ parseToken(token) {
1450
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Entry point - parsing token");
1451
+ const targetToken = token !== void 0 ? token : this.tokenCache;
1452
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Target token exists:", !!targetToken);
1453
+ if (!targetToken) {
1454
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: No target token, returning null");
1455
+ return null;
1456
+ }
1457
+ if (this.tokenCache === targetToken && this.parsedTokenCache) {
1458
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Returning cached parsed token");
1459
+ return this.parsedTokenCache;
1460
+ }
1461
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Cache miss, parsing token with decodeJwtSafely");
1462
+ const parsed = decodeJwtSafely(targetToken);
1463
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Token parsed successfully:", !!parsed);
1464
+ if (targetToken === this.tokenCache) {
1465
+ console.log("\u{1F510} TokenManager - PARSE_TOKEN: Updating parsed token cache");
1466
+ this.parsedTokenCache = parsed;
1467
+ }
1468
+ return parsed;
2332
1469
  }
2333
1470
  /**
2334
- * Clear the current configuration (useful for testing or reconfiguration)
1471
+ * Check if a token is valid (properly formatted and not expired)
2335
1472
  */
2336
- clearConfig() {
2337
- this.resolvedConfig = null;
2338
- this.configError = null;
2339
- }
2340
- };
2341
- _ConfigurationManager.instance = null;
2342
- var ConfigurationManager = _ConfigurationManager;
2343
- var configurationManager = ConfigurationManager.getInstance();
2344
-
2345
- // src/core/CrudifyInitializer.ts
2346
- var import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
2347
- var _CrudifyInitializer = class _CrudifyInitializer {
2348
- constructor() {
2349
- this.state = {
2350
- isInitialized: false,
2351
- isInitializing: false,
2352
- initializationError: null,
2353
- config: null,
2354
- initializationPromise: null
2355
- };
2356
- console.log("\u{1F680} CrudifyInitializer - Instance created");
2357
- }
2358
- /**
2359
- * Singleton pattern to ensure global initialization coordination
2360
- */
2361
- static getInstance() {
2362
- if (!_CrudifyInitializer.instance) {
2363
- _CrudifyInitializer.instance = new _CrudifyInitializer();
2364
- }
2365
- return _CrudifyInitializer.instance;
2366
- }
2367
- /**
2368
- * Reset the singleton instance (useful for testing)
2369
- */
2370
- static resetInstance() {
2371
- _CrudifyInitializer.instance = null;
2372
- }
2373
- /**
2374
- * Initialize crudify with the given configuration
2375
- * This method is idempotent and thread-safe
2376
- */
2377
- async initialize(config) {
2378
- if (this.state.isInitialized && this.isConfigurationSame(config)) {
2379
- console.log("\u{1F680} CrudifyInitializer - Already initialized with same config");
2380
- return;
2381
- }
2382
- if (this.state.isInitializing && this.state.initializationPromise) {
2383
- console.log("\u{1F680} CrudifyInitializer - Waiting for ongoing initialization");
2384
- await this.state.initializationPromise;
2385
- return;
2386
- }
2387
- if (this.state.isInitialized && !this.isConfigurationSame(config)) {
2388
- console.log("\u{1F680} CrudifyInitializer - Configuration changed, re-initializing");
2389
- this.reset();
1473
+ isTokenValid(token) {
1474
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Entry point - checking token validity");
1475
+ const targetToken = token !== void 0 ? token : this.tokenCache;
1476
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Target token exists:", !!targetToken);
1477
+ if (!targetToken) {
1478
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: No token, returning false");
1479
+ return false;
2390
1480
  }
2391
- this.state.isInitializing = true;
2392
- this.state.initializationError = null;
2393
- this.state.initializationPromise = this.performInitialization(config);
2394
1481
  try {
2395
- await this.state.initializationPromise;
2396
- this.state.isInitialized = true;
2397
- this.state.config = { ...config };
2398
- console.log("\u{1F680} CrudifyInitializer - Initialization completed successfully");
1482
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Checking if token is expired");
1483
+ if (isTokenExpired(targetToken)) {
1484
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token is expired, returning false");
1485
+ return false;
1486
+ }
1487
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token not expired, checking if can be parsed");
1488
+ const parsed = decodeJwtSafely(targetToken);
1489
+ const isValid = parsed !== null;
1490
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token parsing result:", isValid);
1491
+ return isValid;
2399
1492
  } catch (error) {
2400
- this.state.initializationError = error instanceof Error ? error.message : "Unknown initialization error";
2401
- console.error("\u{1F680} CrudifyInitializer - Initialization failed:", this.state.initializationError);
2402
- throw error;
2403
- } finally {
2404
- this.state.isInitializing = false;
2405
- this.state.initializationPromise = null;
1493
+ console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Error validating token:", error);
1494
+ return false;
2406
1495
  }
2407
1496
  }
2408
1497
  /**
2409
- * Perform the actual initialization process
1498
+ * Get token expiration time as Date object
2410
1499
  */
2411
- async performInitialization(config) {
2412
- if (!config.publicApiKey) {
2413
- throw new Error("publicApiKey is required for crudify initialization");
2414
- }
2415
- console.log("\u{1F680} CrudifyInitializer - Starting initialization with config:", {
2416
- env: config.env,
2417
- publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
2418
- appName: config.appName
2419
- });
2420
- try {
2421
- const environment = config.env || "prod";
2422
- console.log("\u{1F680} CrudifyInitializer - Step 1: Configuring environment:", environment);
2423
- await import_crudify_browser3.default.config(environment);
2424
- console.log("\u{1F680} CrudifyInitializer - Step 2: Initializing with API key");
2425
- await import_crudify_browser3.default.init(config.publicApiKey, "none");
2426
- console.log("\u{1F680} CrudifyInitializer - Step 3: Verifying initialization");
2427
- await this.verifyInitialization();
2428
- console.log("\u{1F680} CrudifyInitializer - All initialization steps completed");
2429
- } catch (error) {
2430
- console.error("\u{1F680} CrudifyInitializer - Initialization failed at step:", error);
2431
- throw new Error(
2432
- `Crudify initialization failed: ${error instanceof Error ? error.message : "Unknown error"}. Please check your configuration (env: ${config.env || "prod"}, publicApiKey: ${config.publicApiKey ? "provided" : "missing"})`
2433
- );
2434
- }
1500
+ getTokenExpiration() {
1501
+ const token = this.getToken();
1502
+ if (!token) return null;
1503
+ const parsed = this.parseToken(token);
1504
+ if (!parsed?.exp) return null;
1505
+ return new Date(parsed.exp * 1e3);
2435
1506
  }
2436
1507
  /**
2437
- * Verify that crudify is properly initialized by checking core methods
1508
+ * Clear the current token from all storages and crudify
2438
1509
  */
2439
- async verifyInitialization() {
2440
- const requiredMethods = ["readItems", "readItem", "createItem", "updateItem", "deleteItem", "login", "transaction"];
2441
- const missingMethods = [];
2442
- for (const method of requiredMethods) {
2443
- if (typeof import_crudify_browser3.default[method] !== "function") {
2444
- missingMethods.push(method);
2445
- }
2446
- }
2447
- if (missingMethods.length > 0) {
2448
- throw new Error(
2449
- `Crudify initialization incomplete. Missing methods: ${missingMethods.join(", ")}. This usually indicates a configuration or network issue.`
2450
- );
2451
- }
1510
+ clearToken() {
1511
+ console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Entry point - clearing all tokens");
2452
1512
  try {
2453
- await import_crudify_browser3.default.readItems("__test_connection__", { limit: 1 });
1513
+ console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing cache");
1514
+ this.tokenCache = null;
1515
+ this.parsedTokenCache = null;
1516
+ console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from secure storage");
1517
+ secureSessionStorage.removeItem(this.TOKEN_KEY);
1518
+ console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from crudify");
1519
+ import_crudify_browser3.default.setToken("");
1520
+ console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Token cleared from all storages successfully");
2454
1521
  } catch (error) {
2455
- const errorMessage = error instanceof Error ? error.message : String(error);
2456
- if (!errorMessage.includes("Not initialized") && !errorMessage.includes("not initialized")) {
2457
- console.log("\u{1F680} CrudifyInitializer - Verification successful (API responded with expected error)");
2458
- return;
2459
- }
2460
- throw new Error(
2461
- `Crudify initialization verification failed: ${errorMessage}. The library appears to be initialized but is not responding correctly.`
2462
- );
1522
+ console.warn("\u{1F510} TokenManager - CLEAR_TOKEN: Error clearing token:", error);
2463
1523
  }
2464
1524
  }
2465
1525
  /**
2466
- * Check if the given configuration is the same as the current one
1526
+ * Synchronize token with crudify library
2467
1527
  */
2468
- isConfigurationSame(config) {
2469
- if (!this.state.config) return false;
2470
- return this.state.config.env === config.env && this.state.config.publicApiKey === config.publicApiKey;
1528
+ syncTokenWithCrudify(token) {
1529
+ try {
1530
+ import_crudify_browser3.default.setToken(token);
1531
+ console.log("\u{1F510} TokenManager - Token synchronized with crudify");
1532
+ } catch (error) {
1533
+ console.warn("\u{1F510} TokenManager - Failed to sync token with crudify:", error);
1534
+ }
2471
1535
  }
2472
1536
  /**
2473
- * Reset the initialization state (useful for testing or configuration changes)
1537
+ * Refresh token (placeholder for future implementation)
2474
1538
  */
2475
- reset() {
2476
- console.log("\u{1F680} CrudifyInitializer - Resetting initialization state");
2477
- this.state = {
2478
- isInitialized: false,
2479
- isInitializing: false,
2480
- initializationError: null,
2481
- config: null,
2482
- initializationPromise: null
2483
- };
1539
+ async refreshToken() {
1540
+ throw new Error("Token refresh not yet implemented");
2484
1541
  }
2485
1542
  /**
2486
- * Get the current initialization status
1543
+ * Get user information from the current token
2487
1544
  */
2488
- getStatus() {
1545
+ getUserInfo() {
1546
+ const parsed = this.parseToken();
1547
+ if (!parsed) {
1548
+ return {
1549
+ email: null,
1550
+ userId: null,
1551
+ userIdentifier: null,
1552
+ username: null
1553
+ };
1554
+ }
2489
1555
  return {
2490
- isInitialized: this.state.isInitialized,
2491
- isInitializing: this.state.isInitializing,
2492
- initializationError: this.state.initializationError,
2493
- config: this.state.config
1556
+ email: parsed.email || null,
1557
+ userId: parsed.sub || null,
1558
+ userIdentifier: parsed["cognito:username"] || parsed.email || parsed.sub || null,
1559
+ username: parsed["cognito:username"] || null
2494
1560
  };
2495
1561
  }
2496
1562
  /**
2497
- * Check if crudify is ready to use
2498
- */
2499
- isReady() {
2500
- return this.state.isInitialized && !this.state.initializationError;
2501
- }
2502
- /**
2503
- * Get the current initialization error, if any
1563
+ * Check if user is currently authenticated
2504
1564
  */
2505
- getError() {
2506
- return this.state.initializationError;
1565
+ isAuthenticated() {
1566
+ return this.isTokenValid();
2507
1567
  }
2508
1568
  /**
2509
- * Force re-initialization (useful when configuration changes)
1569
+ * Get time until token expires in minutes
2510
1570
  */
2511
- async reinitialize(config) {
2512
- console.log("\u{1F680} CrudifyInitializer - Forcing re-initialization");
2513
- this.reset();
2514
- await this.initialize(config);
1571
+ getTimeUntilExpiration() {
1572
+ const expiration = this.getTokenExpiration();
1573
+ if (!expiration) return null;
1574
+ const now = /* @__PURE__ */ new Date();
1575
+ const minutesUntilExpiry = Math.floor((expiration.getTime() - now.getTime()) / (60 * 1e3));
1576
+ return Math.max(0, minutesUntilExpiry);
2515
1577
  }
2516
1578
  /**
2517
- * Check if initialization is currently in progress
1579
+ * Cleanup resources (call when the component unmounts)
2518
1580
  */
2519
- isInitializing() {
2520
- return this.state.isInitializing;
1581
+ cleanup() {
1582
+ if (this.expirationCheckInterval) {
1583
+ window.clearInterval(this.expirationCheckInterval);
1584
+ this.expirationCheckInterval = null;
1585
+ }
1586
+ if (this.storageEventListener) {
1587
+ window.removeEventListener("storage", this.storageEventListener);
1588
+ this.storageEventListener = null;
1589
+ }
1590
+ console.log("\u{1F510} TokenManager - Cleanup completed");
2521
1591
  }
2522
1592
  /**
2523
- * Wait for any ongoing initialization to complete
1593
+ * Get debug information about the current token state
2524
1594
  */
2525
- async waitForInitialization() {
2526
- if (this.state.initializationPromise) {
2527
- await this.state.initializationPromise;
2528
- }
1595
+ getDebugInfo() {
1596
+ const token = this.getToken();
1597
+ const parsed = this.parseToken();
1598
+ const expiration = this.getTokenExpiration();
1599
+ return {
1600
+ hasToken: !!token,
1601
+ tokenLength: token?.length || 0,
1602
+ isValid: this.isTokenValid(),
1603
+ isAuthenticated: this.isAuthenticated(),
1604
+ expiration: expiration?.toISOString() || null,
1605
+ minutesUntilExpiry: this.getTimeUntilExpiration(),
1606
+ userInfo: this.getUserInfo(),
1607
+ parsedTokenKeys: parsed ? Object.keys(parsed) : []
1608
+ };
2529
1609
  }
2530
1610
  };
2531
- _CrudifyInitializer.instance = null;
2532
- var CrudifyInitializer2 = _CrudifyInitializer;
2533
- var crudifyInitializer = CrudifyInitializer2.getInstance();
1611
+ _TokenManager.instance = null;
1612
+ var TokenManager = _TokenManager;
1613
+ var tokenManager = TokenManager.getInstance();
2534
1614
 
2535
- // src/core/TokenManager.ts
2536
- var import_crudify_browser4 = __toESM(require("@nocios/crudify-browser"));
2537
- var _TokenManager = class _TokenManager {
2538
- constructor() {
2539
- this.TOKEN_KEY = "authToken";
2540
- // Compatible with crudia-ui
2541
- this.tokenCache = null;
2542
- this.parsedTokenCache = null;
2543
- this.expirationCheckInterval = null;
2544
- this.storageEventListener = null;
2545
- this.initializeTokenManager();
1615
+ // src/providers/CrudifyDataProvider.tsx
1616
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1617
+ var CrudifyDataContext = (0, import_react5.createContext)(null);
1618
+ var CrudifyDataProvider = ({
1619
+ children,
1620
+ env,
1621
+ publicApiKey,
1622
+ loginActions,
1623
+ appName,
1624
+ logo,
1625
+ colors
1626
+ }) => {
1627
+ const [config, setConfig] = (0, import_react5.useState)(null);
1628
+ const [isConfigured, setIsConfigured] = (0, import_react5.useState)(false);
1629
+ const [configError, setConfigError] = (0, import_react5.useState)(null);
1630
+ const [isInitialized, setIsInitialized] = (0, import_react5.useState)(false);
1631
+ const [isInitializing, setIsInitializing] = (0, import_react5.useState)(false);
1632
+ const [initializationError, setInitializationError] = (0, import_react5.useState)(null);
1633
+ const [isAuthenticated, setIsAuthenticated] = (0, import_react5.useState)(false);
1634
+ const [token, setTokenState] = (0, import_react5.useState)(null);
1635
+ const [user, setUser] = (0, import_react5.useState)(null);
1636
+ const [tokenExpiration, setTokenExpiration] = (0, import_react5.useState)(null);
1637
+ const initializeConfiguration = (0, import_react5.useCallback)(() => {
1638
+ try {
1639
+ console.log("\u{1F30D} CrudifyDataProvider - Initializing configuration");
1640
+ const propsConfig = {
1641
+ env,
1642
+ publicApiKey,
1643
+ loginActions,
1644
+ appName,
1645
+ logo,
1646
+ colors
1647
+ };
1648
+ const resolvedConfig = configurationManager.resolveConfig(propsConfig);
1649
+ const error = configurationManager.getConfigError();
1650
+ setConfig(resolvedConfig);
1651
+ setConfigError(error);
1652
+ setIsConfigured(configurationManager.isConfigured());
1653
+ console.log("\u{1F30D} CrudifyDataProvider - Configuration initialized:", {
1654
+ isConfigured: configurationManager.isConfigured(),
1655
+ error,
1656
+ sources: resolvedConfig.configSource
1657
+ });
1658
+ return resolvedConfig;
1659
+ } catch (error) {
1660
+ const errorMessage = error instanceof Error ? error.message : "Configuration initialization failed";
1661
+ console.error("\u{1F30D} CrudifyDataProvider - Configuration error:", errorMessage);
1662
+ setConfigError(errorMessage);
1663
+ setIsConfigured(false);
1664
+ return null;
1665
+ }
1666
+ }, [env, publicApiKey, loginActions, appName, logo, colors]);
1667
+ const initializeCrudify = (0, import_react5.useCallback)(async (resolvedConfig) => {
1668
+ if (!resolvedConfig || !resolvedConfig.publicApiKey) {
1669
+ setInitializationError("Cannot initialize crudify without valid configuration");
1670
+ return;
1671
+ }
1672
+ try {
1673
+ setIsInitializing(true);
1674
+ setInitializationError(null);
1675
+ console.log("\u{1F680} CrudifyDataProvider - Starting crudify initialization");
1676
+ await crudifyInitializer.initialize({
1677
+ env: resolvedConfig.env,
1678
+ publicApiKey: resolvedConfig.publicApiKey,
1679
+ loginActions: resolvedConfig.loginActions,
1680
+ appName: resolvedConfig.appName,
1681
+ logo: resolvedConfig.logo,
1682
+ colors: resolvedConfig.colors
1683
+ });
1684
+ setIsInitialized(true);
1685
+ console.log("\u{1F680} CrudifyDataProvider - Crudify initialization completed");
1686
+ } catch (error) {
1687
+ const errorMessage = error instanceof Error ? error.message : "Crudify initialization failed";
1688
+ console.error("\u{1F680} CrudifyDataProvider - Initialization error:", errorMessage);
1689
+ setInitializationError(errorMessage);
1690
+ setIsInitialized(false);
1691
+ } finally {
1692
+ setIsInitializing(false);
1693
+ }
1694
+ }, []);
1695
+ const updateAuthenticationState = (0, import_react5.useCallback)(() => {
1696
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Starting authentication state update");
1697
+ try {
1698
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting token from TokenManager");
1699
+ const currentToken = tokenManager.getToken();
1700
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token retrieved:", !!currentToken);
1701
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Parsing token");
1702
+ const parsedUser = tokenManager.parseToken();
1703
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token parsed:", !!parsedUser);
1704
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting expiration");
1705
+ const expiration = tokenManager.getTokenExpiration();
1706
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Expiration retrieved:", !!expiration);
1707
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Checking authentication");
1708
+ const authenticated = tokenManager.isAuthenticated();
1709
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication checked:", authenticated);
1710
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Updating state variables");
1711
+ setTokenState(currentToken);
1712
+ setUser(parsedUser);
1713
+ setTokenExpiration(expiration);
1714
+ setIsAuthenticated(authenticated);
1715
+ console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication state updated successfully:", {
1716
+ hasToken: !!currentToken,
1717
+ isAuthenticated: authenticated,
1718
+ userEmail: parsedUser?.email || null,
1719
+ expiration: expiration?.toISOString() || null
1720
+ });
1721
+ } catch (error) {
1722
+ console.error("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Error updating authentication state:", error);
1723
+ }
1724
+ }, []);
1725
+ const setToken = (0, import_react5.useCallback)((newToken) => {
1726
+ console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting new token:", newToken ? "provided" : "null");
1727
+ tokenManager.setToken(newToken);
1728
+ console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Updating state using newToken directly");
1729
+ if (newToken) {
1730
+ const parsedUser = tokenManager.parseToken(newToken);
1731
+ const expiration = tokenManager.getTokenExpiration();
1732
+ const authenticated = tokenManager.isTokenValid(newToken);
1733
+ setTokenState(newToken);
1734
+ setUser(parsedUser);
1735
+ setTokenExpiration(expiration);
1736
+ setIsAuthenticated(authenticated);
1737
+ console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Token set, state updated", {
1738
+ hasToken: true,
1739
+ isAuthenticated: authenticated,
1740
+ userEmail: parsedUser?.email || null
1741
+ });
1742
+ } else {
1743
+ setTokenState(null);
1744
+ setUser(null);
1745
+ setTokenExpiration(null);
1746
+ setIsAuthenticated(false);
1747
+ console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Token cleared, state reset");
1748
+ }
1749
+ }, []);
1750
+ const logout = (0, import_react5.useCallback)(() => {
1751
+ console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Logging out user");
1752
+ tokenManager.clearToken();
1753
+ console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Updating state directly");
1754
+ setTokenState(null);
1755
+ setUser(null);
1756
+ setTokenExpiration(null);
1757
+ setIsAuthenticated(false);
1758
+ console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: User logged out, state cleared");
1759
+ }, []);
1760
+ const refreshConfig = (0, import_react5.useCallback)(() => {
1761
+ console.log("\u{1F30D} CrudifyDataProvider - Refreshing configuration");
1762
+ configurationManager.clearConfig();
1763
+ const newConfig = initializeConfiguration();
1764
+ if (newConfig && newConfig.publicApiKey) {
1765
+ initializeCrudify(newConfig);
1766
+ }
1767
+ }, [initializeConfiguration, initializeCrudify]);
1768
+ const reinitialize = (0, import_react5.useCallback)(async () => {
1769
+ if (!config || !config.publicApiKey) {
1770
+ console.warn("\u{1F680} CrudifyDataProvider - Cannot reinitialize without valid configuration");
1771
+ return;
1772
+ }
1773
+ console.log("\u{1F680} CrudifyDataProvider - Force reinitializing crudify");
1774
+ crudifyInitializer.reset();
1775
+ await initializeCrudify(config);
1776
+ }, [config, initializeCrudify]);
1777
+ const getDebugInfo = (0, import_react5.useCallback)(() => {
1778
+ return {
1779
+ provider: {
1780
+ isConfigured,
1781
+ configError,
1782
+ isInitialized,
1783
+ isInitializing,
1784
+ initializationError,
1785
+ isAuthenticated
1786
+ },
1787
+ configuration: {
1788
+ config: config ? {
1789
+ env: config.env,
1790
+ publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
1791
+ appName: config.appName,
1792
+ loginActionsCount: config.loginActions.length,
1793
+ hasLogo: !!config.logo,
1794
+ colorsCount: Object.keys(config.colors).length
1795
+ } : null,
1796
+ sources: config?.configSource || null,
1797
+ rawConfig: config?.rawConfig || null
1798
+ },
1799
+ authentication: {
1800
+ hasToken: !!token,
1801
+ tokenLength: token?.length || 0,
1802
+ userEmail: user?.email || null,
1803
+ userId: user?.sub || null,
1804
+ expiration: tokenExpiration?.toISOString() || null,
1805
+ minutesUntilExpiry: tokenManager.getTimeUntilExpiration()
1806
+ },
1807
+ tokenManager: tokenManager.getDebugInfo(),
1808
+ crudifyInitializer: crudifyInitializer.getStatus()
1809
+ };
1810
+ }, [isConfigured, configError, isInitialized, isInitializing, initializationError, isAuthenticated, config, token, user, tokenExpiration]);
1811
+ (0, import_react5.useEffect)(() => {
1812
+ console.log("\u{1F30D} CrudifyDataProvider - Provider mounting, starting initialization");
1813
+ const resolvedConfig = initializeConfiguration();
1814
+ updateAuthenticationState();
1815
+ if (resolvedConfig && resolvedConfig.publicApiKey) {
1816
+ initializeCrudify(resolvedConfig);
1817
+ }
1818
+ return () => {
1819
+ console.log("\u{1F30D} CrudifyDataProvider - Provider unmounting, cleaning up");
1820
+ tokenManager.cleanup();
1821
+ };
1822
+ }, []);
1823
+ (0, import_react5.useEffect)(() => {
1824
+ console.log("\u{1F510} CrudifyDataProvider - INITIAL_AUTH_EFFECT: Loading initial authentication state");
1825
+ updateAuthenticationState();
1826
+ }, []);
1827
+ const contextValue = {
1828
+ // Configuration
1829
+ config,
1830
+ isConfigured,
1831
+ configError,
1832
+ configSource: config ? JSON.stringify(config.configSource) : "none",
1833
+ // Initialization
1834
+ isInitialized,
1835
+ isInitializing,
1836
+ initializationError,
1837
+ // Authentication
1838
+ isAuthenticated,
1839
+ token,
1840
+ user,
1841
+ tokenExpiration,
1842
+ // Actions
1843
+ setToken,
1844
+ logout,
1845
+ refreshConfig,
1846
+ reinitialize,
1847
+ // Debug
1848
+ getDebugInfo
1849
+ };
1850
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CrudifyDataContext.Provider, { value: contextValue, children });
1851
+ };
1852
+ var useCrudifyDataContext = () => {
1853
+ const context = (0, import_react5.useContext)(CrudifyDataContext);
1854
+ if (!context) {
1855
+ throw new Error(
1856
+ "useCrudifyDataContext must be used within a CrudifyDataProvider. Make sure to wrap your app with <CrudifyDataProvider>."
1857
+ );
2546
1858
  }
2547
- /**
2548
- * Singleton pattern to ensure consistent token management
2549
- */
2550
- static getInstance() {
2551
- if (!_TokenManager.instance) {
2552
- _TokenManager.instance = new _TokenManager();
1859
+ return context;
1860
+ };
1861
+
1862
+ // src/hooks/useCrudifyAuth.ts
1863
+ var useCrudifyAuth = () => {
1864
+ const {
1865
+ isAuthenticated,
1866
+ isInitializing,
1867
+ initializationError,
1868
+ token,
1869
+ user,
1870
+ tokenExpiration,
1871
+ setToken,
1872
+ logout
1873
+ } = useCrudifyDataContext();
1874
+ return {
1875
+ // Estado básico
1876
+ isAuthenticated,
1877
+ loading: isInitializing,
1878
+ error: initializationError,
1879
+ // Datos del token
1880
+ token,
1881
+ user,
1882
+ tokenExpiration,
1883
+ // Acciones
1884
+ setToken,
1885
+ logout,
1886
+ refreshToken: void 0
1887
+ // Will be implemented in future versions
1888
+ };
1889
+ };
1890
+
1891
+ // src/components/CrudifyLogin/Forms/LoginForm.tsx
1892
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1893
+ var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
1894
+ const { crudify: crudify7 } = useCrudify();
1895
+ const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
1896
+ const { setToken } = useCrudifyAuth();
1897
+ const { t } = useTranslation();
1898
+ const usernameInputRef = (0, import_react6.useRef)(null);
1899
+ const getRedirectUrl = () => {
1900
+ if (state.searchParams.redirect) {
1901
+ try {
1902
+ const decodedPath = decodeURIComponent(state.searchParams.redirect);
1903
+ if (decodedPath.startsWith("/") && !decodedPath.startsWith("//")) {
1904
+ return decodedPath;
1905
+ }
1906
+ } catch (error) {
1907
+ }
2553
1908
  }
2554
- return _TokenManager.instance;
2555
- }
2556
- /**
2557
- * Reset the singleton instance (useful for testing)
2558
- */
2559
- static resetInstance() {
2560
- if (_TokenManager.instance) {
2561
- _TokenManager.instance.cleanup();
1909
+ return redirectUrl || "/";
1910
+ };
1911
+ (0, import_react6.useEffect)(() => {
1912
+ const timer = setTimeout(() => {
1913
+ if (usernameInputRef.current) usernameInputRef.current.focus();
1914
+ }, 100);
1915
+ return () => clearTimeout(timer);
1916
+ }, []);
1917
+ const translateError = (parsedError) => {
1918
+ const possibleKeys = [
1919
+ `errors.auth.${parsedError.code}`,
1920
+ `errors.data.${parsedError.code}`,
1921
+ `errors.system.${parsedError.code}`,
1922
+ `errors.${parsedError.code}`,
1923
+ `login.${parsedError.code.toLowerCase()}`
1924
+ ];
1925
+ for (const key of possibleKeys) {
1926
+ const translated = t(key);
1927
+ if (translated !== key) {
1928
+ return translated;
1929
+ }
2562
1930
  }
2563
- _TokenManager.instance = null;
2564
- }
2565
- /**
2566
- * Initialize the token manager with storage synchronization
2567
- */
2568
- initializeTokenManager() {
2569
- console.log("\u{1F510} TokenManager - Initializing token management");
2570
- this.migrateFromLocalStorage();
2571
- this.loadTokenFromStorage();
2572
- this.setupExpirationCheck();
2573
- this.setupStorageListener();
2574
- console.log("\u{1F510} TokenManager - Initialization complete");
2575
- }
2576
- /**
2577
- * Migrate tokens from localStorage to sessionStorage for better security
2578
- * This ensures compatibility with older implementations
2579
- */
2580
- migrateFromLocalStorage() {
1931
+ return parsedError.message || t("error.unknown");
1932
+ };
1933
+ const handleLogin = async () => {
1934
+ if (state.loading) return;
1935
+ if (!state.formData.username.trim()) {
1936
+ setFieldError("username", t("login.usernameRequired"));
1937
+ return;
1938
+ }
1939
+ if (!state.formData.password.trim()) {
1940
+ setFieldError("password", t("login.passwordRequired"));
1941
+ return;
1942
+ }
1943
+ clearErrors();
1944
+ setLoading(true);
2581
1945
  try {
2582
- const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
2583
- for (const key of legacyKeys) {
2584
- const token = localStorage.getItem(key);
2585
- if (token && !secureSessionStorage.getToken()) {
2586
- console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
2587
- secureSessionStorage.setToken(token);
2588
- localStorage.removeItem(key);
2589
- break;
2590
- }
1946
+ if (!crudify7) {
1947
+ throw new Error("Crudify not initialized");
1948
+ }
1949
+ const response = await crudify7.login(state.formData.username, state.formData.password);
1950
+ setLoading(false);
1951
+ if (response.success) {
1952
+ secureSessionStorage.setToken(response.data.token);
1953
+ setToken(response.data.token);
1954
+ const finalRedirectUrl = getRedirectUrl();
1955
+ setTimeout(() => {
1956
+ if (onLoginSuccess) {
1957
+ onLoginSuccess(response.data, finalRedirectUrl);
1958
+ }
1959
+ }, 100);
1960
+ } else {
1961
+ handleLoginError(response);
2591
1962
  }
2592
1963
  } catch (error) {
2593
- console.warn("\u{1F510} TokenManager - Token migration failed:", error);
1964
+ setLoading(false);
1965
+ const parsedErrors = handleCrudifyError(error);
1966
+ const translatedErrors = parsedErrors.map(translateError);
1967
+ setFieldError("global", translatedErrors);
1968
+ if (onError) {
1969
+ onError(translatedErrors.join(", "));
1970
+ }
1971
+ }
1972
+ };
1973
+ const handleLoginError = (response) => {
1974
+ const parsedErrors = handleCrudifyError(response);
1975
+ parsedErrors.forEach((error) => {
1976
+ if (error.field) {
1977
+ setFieldError(error.field, translateError(error));
1978
+ } else {
1979
+ const currentGlobalErrors = state.errors.global || [];
1980
+ setFieldError("global", [...currentGlobalErrors, translateError(error)]);
1981
+ }
1982
+ });
1983
+ };
1984
+ const handleSubmit = (e) => {
1985
+ e.preventDefault();
1986
+ handleLogin();
1987
+ };
1988
+ const handleKeyDown = (e) => {
1989
+ if (e.key === "Enter" && !state.loading) {
1990
+ e.preventDefault();
1991
+ handleLogin();
1992
+ }
1993
+ };
1994
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1996
+ import_material.Box,
1997
+ {
1998
+ component: "form",
1999
+ noValidate: true,
2000
+ onSubmit: handleSubmit,
2001
+ onKeyDown: handleKeyDown,
2002
+ sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 },
2003
+ children: [
2004
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
2005
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2006
+ import_material.Typography,
2007
+ {
2008
+ variant: "body2",
2009
+ component: "label",
2010
+ htmlFor: "email",
2011
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2012
+ children: t("login.usernameOrEmailLabel")
2013
+ }
2014
+ ),
2015
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2016
+ import_material.TextField,
2017
+ {
2018
+ fullWidth: true,
2019
+ id: "email",
2020
+ name: "email",
2021
+ type: "email",
2022
+ value: state.formData.username,
2023
+ disabled: state.loading,
2024
+ onChange: (e) => updateFormData({ username: e.target.value }),
2025
+ error: !!state.errors.username,
2026
+ helperText: state.errors.username,
2027
+ autoComplete: "email",
2028
+ placeholder: t("login.usernameOrEmailPlaceholder"),
2029
+ inputRef: usernameInputRef,
2030
+ required: true
2031
+ }
2032
+ )
2033
+ ] }),
2034
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_material.Box, { sx: { mb: 1 }, children: [
2035
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2036
+ import_material.Typography,
2037
+ {
2038
+ variant: "body2",
2039
+ component: "label",
2040
+ htmlFor: "password",
2041
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2042
+ children: t("login.passwordLabel")
2043
+ }
2044
+ ),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2046
+ import_material.TextField,
2047
+ {
2048
+ fullWidth: true,
2049
+ id: "password",
2050
+ name: "password",
2051
+ type: "password",
2052
+ value: state.formData.password,
2053
+ disabled: state.loading,
2054
+ onChange: (e) => updateFormData({ password: e.target.value }),
2055
+ error: !!state.errors.password,
2056
+ helperText: state.errors.password,
2057
+ autoComplete: "current-password",
2058
+ placeholder: t("login.passwordPlaceholder"),
2059
+ required: true
2060
+ }
2061
+ )
2062
+ ] }),
2063
+ 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)(
2064
+ import_material.Link,
2065
+ {
2066
+ sx: { cursor: "pointer" },
2067
+ onClick: () => {
2068
+ onScreenChange?.("forgotPassword", state.searchParams);
2069
+ },
2070
+ variant: "body2",
2071
+ color: "secondary",
2072
+ children: t("login.forgotPasswordLink")
2073
+ }
2074
+ ) }),
2075
+ /* @__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") })
2076
+ ]
2077
+ }
2078
+ ),
2079
+ /* @__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)) }),
2080
+ 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: [
2081
+ t("login.noAccountPrompt"),
2082
+ " ",
2083
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2084
+ import_material.Link,
2085
+ {
2086
+ sx: { cursor: "pointer" },
2087
+ onClick: () => {
2088
+ const searchString = Object.keys(state.searchParams).length > 0 ? `?${new URLSearchParams(state.searchParams).toString()}` : "";
2089
+ const signupUrl = `/public/users/create${searchString}`;
2090
+ onExternalNavigate?.(signupUrl);
2091
+ },
2092
+ fontWeight: "medium",
2093
+ color: "secondary",
2094
+ children: t("login.signUpLink")
2095
+ }
2096
+ )
2097
+ ] })
2098
+ ] });
2099
+ };
2100
+ var LoginForm_default = LoginForm;
2101
+
2102
+ // src/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx
2103
+ var import_react7 = require("react");
2104
+ var import_material2 = require("@mui/material");
2105
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2106
+ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
2107
+ const { crudify: crudify7 } = useCrudify();
2108
+ const [email, setEmail] = (0, import_react7.useState)("");
2109
+ const [loading, setLoading] = (0, import_react7.useState)(false);
2110
+ const [errors, setErrors] = (0, import_react7.useState)([]);
2111
+ const [helperTextEmail, setHelperTextEmail] = (0, import_react7.useState)(null);
2112
+ const [emailSent, setEmailSent] = (0, import_react7.useState)(false);
2113
+ const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react7.useState)(false);
2114
+ const { t } = useTranslation();
2115
+ const translateError = (parsedError) => {
2116
+ const possibleKeys = [
2117
+ `errors.auth.${parsedError.code}`,
2118
+ `errors.data.${parsedError.code}`,
2119
+ `errors.system.${parsedError.code}`,
2120
+ `errors.${parsedError.code}`,
2121
+ `forgotPassword.${parsedError.code.toLowerCase()}`
2122
+ ];
2123
+ for (const key of possibleKeys) {
2124
+ const translated = t(key);
2125
+ if (translated !== key) {
2126
+ return translated;
2127
+ }
2128
+ }
2129
+ return parsedError.message || t("error.unknown");
2130
+ };
2131
+ const validateEmail = (email2) => {
2132
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2133
+ return emailRegex.test(email2);
2134
+ };
2135
+ const handleSubmit = async () => {
2136
+ if (loading || !crudify7) return;
2137
+ setErrors([]);
2138
+ setHelperTextEmail(null);
2139
+ if (!email) {
2140
+ setHelperTextEmail(t("forgotPassword.emailRequired"));
2141
+ return;
2142
+ }
2143
+ if (!validateEmail(email)) {
2144
+ setHelperTextEmail(t("forgotPassword.invalidEmail"));
2145
+ return;
2594
2146
  }
2595
- }
2596
- /**
2597
- * Load token from storage and synchronize with crudify
2598
- */
2599
- loadTokenFromStorage() {
2600
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
2147
+ setLoading(true);
2601
2148
  try {
2602
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure session storage");
2603
- const storedToken = secureSessionStorage.getToken();
2604
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
2605
- if (storedToken && this.isTokenValid(storedToken)) {
2606
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
2607
- this.tokenCache = storedToken;
2608
- this.parsedTokenCache = this.parseToken(storedToken);
2609
- this.syncTokenWithCrudify(storedToken);
2610
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Token loaded from storage and synchronized");
2611
- } else if (storedToken) {
2612
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists but is invalid/expired, clearing");
2613
- this.clearToken();
2149
+ const data = [{ operation: "requestPasswordReset", data: { email } }];
2150
+ const response = await crudify7.transaction(data);
2151
+ if (response.success) {
2152
+ if (response.data && response.data.existingCodeValid) {
2153
+ setCodeAlreadyExists(true);
2154
+ } else {
2155
+ setEmailSent(true);
2156
+ }
2614
2157
  } else {
2615
- console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: No stored token found");
2158
+ const parsedErrors = handleCrudifyError(response);
2159
+ const translatedErrors = parsedErrors.map(translateError);
2160
+ setErrors(translatedErrors);
2616
2161
  }
2617
2162
  } catch (error) {
2618
- console.warn("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Error loading token from storage:", error);
2619
- this.clearToken();
2163
+ const parsedErrors = handleCrudifyError(error);
2164
+ const translatedErrors = parsedErrors.map(translateError);
2165
+ setErrors(translatedErrors);
2166
+ if (onError) {
2167
+ onError(translatedErrors.join(", "));
2168
+ }
2169
+ } finally {
2170
+ setLoading(false);
2171
+ }
2172
+ };
2173
+ const handleBack = () => {
2174
+ onScreenChange?.("login");
2175
+ };
2176
+ const handleGoToCheckCode = () => {
2177
+ if (emailSent || codeAlreadyExists) {
2178
+ onScreenChange?.("checkCode", { email });
2179
+ return;
2180
+ }
2181
+ if (!email) {
2182
+ setHelperTextEmail(t("forgotPassword.emailRequired"));
2183
+ return;
2620
2184
  }
2185
+ if (!validateEmail(email)) {
2186
+ setHelperTextEmail(t("forgotPassword.invalidEmail"));
2187
+ return;
2188
+ }
2189
+ onScreenChange?.("checkCode", { email });
2190
+ };
2191
+ if (emailSent || codeAlreadyExists) {
2192
+ 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: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
2194
+ /* @__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") }),
2195
+ /* @__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") })
2196
+ ] }),
2197
+ /* @__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") }),
2198
+ /* @__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") }) })
2199
+ ] }) });
2621
2200
  }
2622
- /**
2623
- * Set up automatic token expiration checking
2624
- */
2625
- setupExpirationCheck() {
2626
- this.expirationCheckInterval = window.setInterval(() => {
2627
- if (this.tokenCache && !this.isTokenValid(this.tokenCache)) {
2628
- console.log("\u{1F510} TokenManager - Token expired, clearing automatically");
2629
- this.clearToken();
2201
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2202
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2203
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 2 }, children: [
2204
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("forgotPassword.title") }),
2205
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("forgotPassword.instructions") })
2206
+ ] }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { mb: 1 }, children: [
2208
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2209
+ import_material2.Typography,
2210
+ {
2211
+ variant: "body2",
2212
+ component: "label",
2213
+ htmlFor: "email",
2214
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2215
+ children: t("forgotPassword.emailLabel")
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2219
+ import_material2.TextField,
2220
+ {
2221
+ fullWidth: true,
2222
+ id: "email",
2223
+ name: "email",
2224
+ type: "email",
2225
+ value: email,
2226
+ disabled: loading,
2227
+ onChange: (e) => setEmail(e.target.value),
2228
+ error: !!helperTextEmail,
2229
+ helperText: helperTextEmail,
2230
+ autoComplete: "email",
2231
+ placeholder: t("forgotPassword.emailPlaceholder"),
2232
+ required: true
2233
+ }
2234
+ )
2235
+ ] }),
2236
+ /* @__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") }),
2237
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_material2.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", gap: 2 }, children: [
2238
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleBack, variant: "body2", color: "secondary", children: t("common.back") }),
2239
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Typography, { variant: "body2", sx: { color: "grey.400" }, children: "\u2022" }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_material2.Link, { sx: { cursor: "pointer" }, onClick: handleGoToCheckCode, variant: "body2", color: "secondary", children: t("login.alreadyHaveCodeLink") })
2241
+ ] })
2242
+ ] }),
2243
+ /* @__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)) })
2244
+ ] });
2245
+ };
2246
+ var ForgotPasswordForm_default = ForgotPasswordForm;
2247
+
2248
+ // src/components/CrudifyLogin/Forms/ResetPasswordForm.tsx
2249
+ var import_react8 = require("react");
2250
+ var import_material3 = require("@mui/material");
2251
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2252
+ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
2253
+ const { crudify: crudify7 } = useCrudify();
2254
+ const [newPassword, setNewPassword] = (0, import_react8.useState)("");
2255
+ const [confirmPassword, setConfirmPassword] = (0, import_react8.useState)("");
2256
+ const [loading, setLoading] = (0, import_react8.useState)(false);
2257
+ const [errors, setErrors] = (0, import_react8.useState)([]);
2258
+ const [helperTextNewPassword, setHelperTextNewPassword] = (0, import_react8.useState)(null);
2259
+ const [helperTextConfirmPassword, setHelperTextConfirmPassword] = (0, import_react8.useState)(null);
2260
+ const [email, setEmail] = (0, import_react8.useState)("");
2261
+ const [code, setCode] = (0, import_react8.useState)("");
2262
+ const [fromCodeVerification, setFromCodeVerification] = (0, import_react8.useState)(false);
2263
+ const [validatingCode, setValidatingCode] = (0, import_react8.useState)(true);
2264
+ const [codeValidated, setCodeValidated] = (0, import_react8.useState)(false);
2265
+ const [pendingValidation, setPendingValidation] = (0, import_react8.useState)(null);
2266
+ const [isValidating, setIsValidating] = (0, import_react8.useState)(false);
2267
+ const { t } = useTranslation();
2268
+ const translateError = (parsedError) => {
2269
+ const possibleKeys = [
2270
+ `errors.auth.${parsedError.code}`,
2271
+ `errors.data.${parsedError.code}`,
2272
+ `errors.system.${parsedError.code}`,
2273
+ `errors.${parsedError.code}`,
2274
+ `resetPassword.${parsedError.code.toLowerCase()}`
2275
+ ];
2276
+ for (const key of possibleKeys) {
2277
+ const translated = t(key);
2278
+ if (translated !== key) {
2279
+ return translated;
2630
2280
  }
2631
- }, 3e4);
2632
- }
2633
- /**
2634
- * Set up storage event listener for cross-tab synchronization
2635
- */
2636
- setupStorageListener() {
2637
- this.storageEventListener = (event) => {
2638
- if (event.key === this.TOKEN_KEY) {
2639
- console.log("\u{1F510} TokenManager - Token change detected from another tab");
2640
- this.loadTokenFromStorage();
2281
+ }
2282
+ return parsedError.message || t("error.unknown");
2283
+ };
2284
+ const getParam = (key) => {
2285
+ if (!searchParams) return null;
2286
+ if (searchParams instanceof URLSearchParams) {
2287
+ return searchParams.get(key);
2288
+ }
2289
+ return searchParams[key] || null;
2290
+ };
2291
+ (0, import_react8.useEffect)(() => {
2292
+ if (!searchParams) {
2293
+ return;
2294
+ }
2295
+ if (searchParams) {
2296
+ const fromCodeVerificationParam = getParam("fromCodeVerification");
2297
+ const emailParam = getParam("email");
2298
+ const codeParam = getParam("code");
2299
+ if (fromCodeVerificationParam === "true" && emailParam && codeParam) {
2300
+ setEmail(emailParam);
2301
+ setCode(codeParam);
2302
+ setFromCodeVerification(true);
2303
+ setCodeValidated(true);
2304
+ setValidatingCode(false);
2305
+ return;
2306
+ }
2307
+ const linkParam = getParam("link");
2308
+ if (linkParam) {
2309
+ try {
2310
+ const decodedLink = decodeURIComponent(linkParam);
2311
+ const [linkCode, linkEmail] = decodedLink.split("/");
2312
+ if (linkCode && linkEmail && linkCode.length === 6) {
2313
+ setCode(linkCode);
2314
+ setEmail(linkEmail);
2315
+ setFromCodeVerification(false);
2316
+ setPendingValidation({ email: linkEmail, code: linkCode });
2317
+ return;
2318
+ }
2319
+ } catch (error) {
2320
+ }
2321
+ }
2322
+ if (emailParam && codeParam) {
2323
+ setEmail(emailParam);
2324
+ setCode(codeParam);
2325
+ setFromCodeVerification(false);
2326
+ setPendingValidation({ email: emailParam, code: codeParam });
2327
+ return;
2328
+ }
2329
+ }
2330
+ setErrors([t("resetPassword.invalidCode")]);
2331
+ setValidatingCode(false);
2332
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2333
+ }, [searchParams, crudify7, t, onScreenChange]);
2334
+ (0, import_react8.useEffect)(() => {
2335
+ if (crudify7 && pendingValidation && !isValidating) {
2336
+ setIsValidating(true);
2337
+ const validateCode = async (emailToValidate, codeToValidate) => {
2338
+ try {
2339
+ const data = [
2340
+ {
2341
+ operation: "validatePasswordResetCode",
2342
+ data: { email: emailToValidate, codePassword: codeToValidate }
2343
+ }
2344
+ ];
2345
+ const response = await crudify7.transaction(data);
2346
+ if (response.data && Array.isArray(response.data)) {
2347
+ const validationResult = response.data[0];
2348
+ if (validationResult && validationResult.response && validationResult.response.status === "OK") {
2349
+ setCodeValidated(true);
2350
+ return;
2351
+ }
2352
+ }
2353
+ if (response.success) {
2354
+ setCodeValidated(true);
2355
+ } else {
2356
+ const parsedErrors = handleCrudifyError(response);
2357
+ const translatedErrors = parsedErrors.map(translateError);
2358
+ setErrors(translatedErrors);
2359
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2360
+ }
2361
+ } catch (error) {
2362
+ const parsedErrors = handleCrudifyError(error);
2363
+ const translatedErrors = parsedErrors.map(translateError);
2364
+ setErrors(translatedErrors);
2365
+ setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
2366
+ } finally {
2367
+ setValidatingCode(false);
2368
+ setPendingValidation(null);
2369
+ setIsValidating(false);
2370
+ }
2371
+ };
2372
+ validateCode(pendingValidation.email, pendingValidation.code);
2373
+ }
2374
+ }, [crudify7, pendingValidation, t, onScreenChange]);
2375
+ const validatePassword = (password) => {
2376
+ if (password.length < 8) {
2377
+ return t("resetPassword.passwordTooShort");
2378
+ }
2379
+ return null;
2380
+ };
2381
+ const handleSubmit = async () => {
2382
+ if (loading || !crudify7) return;
2383
+ setErrors([]);
2384
+ setHelperTextNewPassword(null);
2385
+ setHelperTextConfirmPassword(null);
2386
+ let hasErrors = false;
2387
+ if (!newPassword) {
2388
+ setHelperTextNewPassword(t("resetPassword.newPasswordRequired"));
2389
+ hasErrors = true;
2390
+ } else {
2391
+ const passwordError = validatePassword(newPassword);
2392
+ if (passwordError) {
2393
+ setHelperTextNewPassword(passwordError);
2394
+ hasErrors = true;
2641
2395
  }
2642
- };
2643
- window.addEventListener("storage", this.storageEventListener);
2644
- }
2645
- /**
2646
- * Set a new JWT token with automatic synchronization
2647
- */
2648
- setToken(token) {
2649
- console.log("\u{1F510} TokenManager - SET_TOKEN: Entry point - setting token:", token ? "provided" : "null");
2396
+ }
2397
+ if (!confirmPassword) {
2398
+ setHelperTextConfirmPassword(t("resetPassword.confirmPasswordRequired"));
2399
+ hasErrors = true;
2400
+ } else if (newPassword !== confirmPassword) {
2401
+ setHelperTextConfirmPassword(t("resetPassword.passwordsDoNotMatch"));
2402
+ hasErrors = true;
2403
+ }
2404
+ if (hasErrors) return;
2405
+ setLoading(true);
2650
2406
  try {
2651
- if (!token) {
2652
- console.log("\u{1F510} TokenManager - SET_TOKEN: No token provided, clearing token");
2653
- this.clearToken();
2654
- return;
2655
- }
2656
- console.log("\u{1F510} TokenManager - SET_TOKEN: Validating token before setting");
2657
- if (!this.isTokenValid(token)) {
2658
- console.warn("\u{1F510} TokenManager - SET_TOKEN: Attempted to set invalid or expired token");
2659
- this.clearToken();
2660
- return;
2407
+ const data = [
2408
+ {
2409
+ operation: "validateAndResetPassword",
2410
+ data: { email, codePassword: code, newPassword }
2411
+ }
2412
+ ];
2413
+ const response = await crudify7.transaction(data);
2414
+ if (response.success) {
2415
+ setErrors([]);
2416
+ setTimeout(() => {
2417
+ onResetSuccess?.();
2418
+ }, 1e3);
2419
+ } else {
2420
+ const parsedErrors = handleCrudifyError(response);
2421
+ const translatedErrors = parsedErrors.map(translateError);
2422
+ setErrors(translatedErrors);
2661
2423
  }
2662
- console.log("\u{1F510} TokenManager - SET_TOKEN: Token is valid, updating cache");
2663
- this.tokenCache = token;
2664
- this.parsedTokenCache = this.parseToken(token);
2665
- console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
2666
- secureSessionStorage.setToken(token);
2667
- console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
2668
- this.syncTokenWithCrudify(token);
2669
- console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
2670
2424
  } catch (error) {
2671
- console.error("\u{1F510} TokenManager - SET_TOKEN: Error setting token:", error);
2672
- this.clearToken();
2673
- }
2674
- }
2675
- /**
2676
- * Get the current JWT token
2677
- */
2678
- getToken() {
2679
- console.log("\u{1F510} TokenManager - GET_TOKEN: Entry point - checking cache");
2680
- if (this.tokenCache) {
2681
- console.log("\u{1F510} TokenManager - GET_TOKEN: Cache exists, validating token");
2682
- if (this.isTokenValid(this.tokenCache)) {
2683
- console.log("\u{1F510} TokenManager - GET_TOKEN: Cache valid, returning cached token");
2684
- return this.tokenCache;
2685
- } else {
2686
- console.log("\u{1F510} TokenManager - GET_TOKEN: Cache invalid, clearing cache");
2687
- this.tokenCache = null;
2425
+ const parsedErrors = handleCrudifyError(error);
2426
+ const translatedErrors = parsedErrors.map(translateError);
2427
+ setErrors(translatedErrors);
2428
+ if (onError) {
2429
+ onError(translatedErrors.join(", "));
2688
2430
  }
2431
+ }
2432
+ setLoading(false);
2433
+ };
2434
+ const handleBack = () => {
2435
+ if (fromCodeVerification) {
2436
+ onScreenChange?.("checkCode", { email });
2689
2437
  } else {
2690
- console.log("\u{1F510} TokenManager - GET_TOKEN: No cache, loading from storage");
2438
+ onScreenChange?.("forgotPassword");
2691
2439
  }
2692
- console.log("\u{1F510} TokenManager - GET_TOKEN: Loading from storage");
2693
- this.loadTokenFromStorage();
2694
- console.log("\u{1F510} TokenManager - GET_TOKEN: Returning final token:", !!this.tokenCache);
2695
- return this.tokenCache;
2440
+ };
2441
+ if (validatingCode) {
2442
+ 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, {}) });
2696
2443
  }
2697
- /**
2698
- * Parse the current JWT token
2699
- */
2700
- parseToken(token) {
2701
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Entry point - parsing token");
2702
- const targetToken = token !== void 0 ? token : this.tokenCache;
2703
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Target token exists:", !!targetToken);
2704
- if (!targetToken) {
2705
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: No target token, returning null");
2706
- return null;
2707
- }
2708
- if (this.tokenCache === targetToken && this.parsedTokenCache) {
2709
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Returning cached parsed token");
2710
- return this.parsedTokenCache;
2711
- }
2712
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Cache miss, parsing token with decodeJwtSafely");
2713
- const parsed = decodeJwtSafely(targetToken);
2714
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Token parsed successfully:", !!parsed);
2715
- if (targetToken === this.tokenCache) {
2716
- console.log("\u{1F510} TokenManager - PARSE_TOKEN: Updating parsed token cache");
2717
- this.parsedTokenCache = parsed;
2718
- }
2719
- return parsed;
2444
+ if (!codeValidated) {
2445
+ 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)) });
2720
2446
  }
2721
- /**
2722
- * Check if a token is valid (properly formatted and not expired)
2723
- */
2724
- isTokenValid(token) {
2725
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Entry point - checking token validity");
2726
- const targetToken = token !== void 0 ? token : this.tokenCache;
2727
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Target token exists:", !!targetToken);
2728
- if (!targetToken) {
2729
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: No token, returning false");
2730
- return false;
2447
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2448
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2449
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 2 }, children: [
2450
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("resetPassword.title") }),
2451
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_material3.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("resetPassword.instructions") })
2452
+ ] }),
2453
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
2454
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2455
+ import_material3.Typography,
2456
+ {
2457
+ variant: "body2",
2458
+ component: "label",
2459
+ htmlFor: "newPassword",
2460
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2461
+ children: t("resetPassword.newPasswordLabel")
2462
+ }
2463
+ ),
2464
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2465
+ import_material3.TextField,
2466
+ {
2467
+ fullWidth: true,
2468
+ id: "newPassword",
2469
+ name: "newPassword",
2470
+ type: "password",
2471
+ value: newPassword,
2472
+ disabled: loading,
2473
+ onChange: (e) => setNewPassword(e.target.value),
2474
+ error: !!helperTextNewPassword,
2475
+ helperText: helperTextNewPassword,
2476
+ autoComplete: "new-password",
2477
+ placeholder: t("resetPassword.newPasswordPlaceholder"),
2478
+ required: true
2479
+ }
2480
+ )
2481
+ ] }),
2482
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_material3.Box, { sx: { mb: 1 }, children: [
2483
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2484
+ import_material3.Typography,
2485
+ {
2486
+ variant: "body2",
2487
+ component: "label",
2488
+ htmlFor: "confirmPassword",
2489
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2490
+ children: t("resetPassword.confirmPasswordLabel")
2491
+ }
2492
+ ),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2494
+ import_material3.TextField,
2495
+ {
2496
+ fullWidth: true,
2497
+ id: "confirmPassword",
2498
+ name: "confirmPassword",
2499
+ type: "password",
2500
+ value: confirmPassword,
2501
+ disabled: loading,
2502
+ onChange: (e) => setConfirmPassword(e.target.value),
2503
+ error: !!helperTextConfirmPassword,
2504
+ helperText: helperTextConfirmPassword,
2505
+ autoComplete: "new-password",
2506
+ placeholder: t("resetPassword.confirmPasswordPlaceholder"),
2507
+ required: true
2508
+ }
2509
+ )
2510
+ ] }),
2511
+ /* @__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") }),
2512
+ /* @__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") }) })
2513
+ ] }),
2514
+ /* @__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)) })
2515
+ ] });
2516
+ };
2517
+ var ResetPasswordForm_default = ResetPasswordForm;
2518
+
2519
+ // src/components/CrudifyLogin/Forms/CheckCodeForm.tsx
2520
+ var import_react9 = require("react");
2521
+ var import_material4 = require("@mui/material");
2522
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2523
+ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
2524
+ const { crudify: crudify7 } = useCrudify();
2525
+ const [code, setCode] = (0, import_react9.useState)("");
2526
+ const [loading, setLoading] = (0, import_react9.useState)(false);
2527
+ const [errors, setErrors] = (0, import_react9.useState)([]);
2528
+ const [helperTextCode, setHelperTextCode] = (0, import_react9.useState)(null);
2529
+ const [email, setEmail] = (0, import_react9.useState)("");
2530
+ const { t } = useTranslation();
2531
+ const getParam = (key) => {
2532
+ if (!searchParams) return null;
2533
+ if (searchParams instanceof URLSearchParams) {
2534
+ return searchParams.get(key);
2731
2535
  }
2732
- try {
2733
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Checking if token is expired");
2734
- if (isTokenExpired(targetToken)) {
2735
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token is expired, returning false");
2736
- return false;
2536
+ return searchParams[key] || null;
2537
+ };
2538
+ const translateError = (parsedError) => {
2539
+ const possibleKeys = [
2540
+ `errors.auth.${parsedError.code}`,
2541
+ `errors.data.${parsedError.code}`,
2542
+ `errors.system.${parsedError.code}`,
2543
+ `errors.${parsedError.code}`,
2544
+ `checkCode.${parsedError.code.toLowerCase()}`
2545
+ ];
2546
+ for (const key of possibleKeys) {
2547
+ const translated = t(key);
2548
+ if (translated !== key) {
2549
+ return translated;
2737
2550
  }
2738
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token not expired, checking if can be parsed");
2739
- const parsed = decodeJwtSafely(targetToken);
2740
- const isValid = parsed !== null;
2741
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token parsing result:", isValid);
2742
- return isValid;
2743
- } catch (error) {
2744
- console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Error validating token:", error);
2745
- return false;
2746
2551
  }
2747
- }
2748
- /**
2749
- * Get token expiration time as Date object
2750
- */
2751
- getTokenExpiration() {
2752
- const token = this.getToken();
2753
- if (!token) return null;
2754
- const parsed = this.parseToken(token);
2755
- if (!parsed?.exp) return null;
2756
- return new Date(parsed.exp * 1e3);
2757
- }
2758
- /**
2759
- * Clear the current token from all storages and crudify
2760
- */
2761
- clearToken() {
2762
- console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Entry point - clearing all tokens");
2763
- try {
2764
- console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing cache");
2765
- this.tokenCache = null;
2766
- this.parsedTokenCache = null;
2767
- console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from secure storage");
2768
- secureSessionStorage.removeItem(this.TOKEN_KEY);
2769
- console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from crudify");
2770
- import_crudify_browser4.default.setToken("");
2771
- console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Token cleared from all storages successfully");
2772
- } catch (error) {
2773
- console.warn("\u{1F510} TokenManager - CLEAR_TOKEN: Error clearing token:", error);
2552
+ return parsedError.message || t("error.unknown");
2553
+ };
2554
+ (0, import_react9.useEffect)(() => {
2555
+ const emailParam = getParam("email");
2556
+ if (emailParam) {
2557
+ setEmail(emailParam);
2558
+ } else {
2559
+ onScreenChange?.("forgotPassword");
2774
2560
  }
2775
- }
2776
- /**
2777
- * Synchronize token with crudify library
2778
- */
2779
- syncTokenWithCrudify(token) {
2561
+ }, [searchParams, onScreenChange]);
2562
+ const handleSubmit = async () => {
2563
+ if (loading || !crudify7) return;
2564
+ setErrors([]);
2565
+ setHelperTextCode(null);
2566
+ if (!code) {
2567
+ setHelperTextCode(t("checkCode.codeRequired"));
2568
+ return;
2569
+ }
2570
+ if (code.length !== 6) {
2571
+ setHelperTextCode(t("checkCode.codeRequired"));
2572
+ return;
2573
+ }
2574
+ setLoading(true);
2780
2575
  try {
2781
- import_crudify_browser4.default.setToken(token);
2782
- console.log("\u{1F510} TokenManager - Token synchronized with crudify");
2576
+ const data = [
2577
+ {
2578
+ operation: "validatePasswordResetCode",
2579
+ data: { email, codePassword: code }
2580
+ }
2581
+ ];
2582
+ const response = await crudify7.transaction(data);
2583
+ if (response.success) {
2584
+ onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
2585
+ } else {
2586
+ const parsedErrors = handleCrudifyError(response);
2587
+ const translatedErrors = parsedErrors.map(translateError);
2588
+ setErrors(translatedErrors);
2589
+ setLoading(false);
2590
+ }
2783
2591
  } catch (error) {
2784
- console.warn("\u{1F510} TokenManager - Failed to sync token with crudify:", error);
2592
+ const parsedErrors = handleCrudifyError(error);
2593
+ const translatedErrors = parsedErrors.map(translateError);
2594
+ setErrors(translatedErrors);
2595
+ setLoading(false);
2596
+ if (onError) {
2597
+ onError(translatedErrors.join(", "));
2598
+ }
2785
2599
  }
2600
+ };
2601
+ const handleBack = () => {
2602
+ onScreenChange?.("forgotPassword");
2603
+ };
2604
+ const handleCodeChange = (event) => {
2605
+ const value = event.target.value.replace(/\D/g, "").slice(0, 6);
2606
+ setCode(value);
2607
+ };
2608
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2609
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { component: "form", noValidate: true, sx: { width: "100%", display: "flex", flexDirection: "column", gap: 2 }, children: [
2610
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 2 }, children: [
2611
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "h5", component: "h1", sx: { mb: 1, fontWeight: 600 }, children: t("checkCode.title") }),
2612
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.Typography, { variant: "body2", sx: { color: "grey.600" }, children: t("checkCode.instructions") })
2613
+ ] }),
2614
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_material4.Box, { sx: { mb: 1 }, children: [
2615
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2616
+ import_material4.Typography,
2617
+ {
2618
+ variant: "body2",
2619
+ component: "label",
2620
+ htmlFor: "code",
2621
+ sx: { display: "block", fontWeight: 500, color: "grey.700", mb: 0.5 },
2622
+ children: t("checkCode.codeLabel")
2623
+ }
2624
+ ),
2625
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2626
+ import_material4.TextField,
2627
+ {
2628
+ fullWidth: true,
2629
+ id: "code",
2630
+ name: "code",
2631
+ type: "text",
2632
+ value: code,
2633
+ disabled: loading,
2634
+ onChange: handleCodeChange,
2635
+ error: !!helperTextCode,
2636
+ helperText: helperTextCode,
2637
+ placeholder: t("checkCode.codePlaceholder"),
2638
+ inputProps: {
2639
+ maxLength: 6,
2640
+ style: { textAlign: "center", fontSize: "1.5rem", letterSpacing: "0.4rem" }
2641
+ },
2642
+ required: true
2643
+ }
2644
+ )
2645
+ ] }),
2646
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2647
+ import_material4.Button,
2648
+ {
2649
+ disabled: loading || code.length !== 6,
2650
+ type: "button",
2651
+ onClick: handleSubmit,
2652
+ fullWidth: true,
2653
+ variant: "contained",
2654
+ color: "primary",
2655
+ sx: { mt: 2, mb: 2 },
2656
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_material4.CircularProgress, { size: 20 }) : t("checkCode.verifyButton")
2657
+ }
2658
+ ),
2659
+ /* @__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") }) })
2660
+ ] }),
2661
+ /* @__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)) })
2662
+ ] });
2663
+ };
2664
+ var CheckCodeForm_default = CheckCodeForm;
2665
+
2666
+ // src/components/CrudifyLogin/components/CrudifyInitializer.tsx
2667
+ var import_material5 = require("@mui/material");
2668
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2669
+ var CrudifyInitializer2 = ({ children, fallback }) => {
2670
+ const { isLoading, error, isInitialized } = useCrudify();
2671
+ const { t } = useTranslation();
2672
+ if (isLoading) {
2673
+ return fallback || /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2674
+ import_material5.Box,
2675
+ {
2676
+ sx: {
2677
+ display: "flex",
2678
+ flexDirection: "column",
2679
+ alignItems: "center",
2680
+ justifyContent: "center",
2681
+ minHeight: "200px",
2682
+ gap: 2
2683
+ },
2684
+ children: [
2685
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.CircularProgress, {}),
2686
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_material5.Typography, { variant: "body2", color: "text.secondary", children: t("login.initializing") !== "login.initializing" ? t("login.initializing") : "Initializing..." })
2687
+ ]
2688
+ }
2689
+ );
2786
2690
  }
2787
- /**
2788
- * Refresh token (placeholder for future implementation)
2789
- */
2790
- async refreshToken() {
2791
- throw new Error("Token refresh not yet implemented");
2691
+ if (error) {
2692
+ 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: [
2693
+ t("login.initializationError") !== "login.initializationError" ? t("login.initializationError") : "Initialization error",
2694
+ ":",
2695
+ " ",
2696
+ error
2697
+ ] }) });
2792
2698
  }
2793
- /**
2794
- * Get user information from the current token
2795
- */
2796
- getUserInfo() {
2797
- const parsed = this.parseToken();
2798
- if (!parsed) {
2799
- return {
2800
- email: null,
2801
- userId: null,
2802
- userIdentifier: null,
2803
- username: null
2804
- };
2805
- }
2699
+ if (!isInitialized) {
2700
+ 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" }) });
2701
+ }
2702
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
2703
+ };
2704
+
2705
+ // src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
2706
+ var import_react10 = require("react");
2707
+ var useCrudifyLogin = (config, _options = {}) => {
2708
+ const finalConfig = (0, import_react10.useMemo)(() => {
2709
+ const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
2710
+ const rawEnv = config.env || getCookie("environment") || "prod";
2711
+ const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
2712
+ const appName = config.appName || getCookie("appName") || "Crudia";
2713
+ const loginActions = config.loginActions || (() => {
2714
+ try {
2715
+ const cookieValue = getCookie("loginActions");
2716
+ return cookieValue ? cookieValue.split(",").map((action) => action.trim()).filter(Boolean) : [];
2717
+ } catch {
2718
+ return [];
2719
+ }
2720
+ })();
2806
2721
  return {
2807
- email: parsed.email || null,
2808
- userId: parsed.sub || null,
2809
- userIdentifier: parsed["cognito:username"] || parsed.email || parsed.sub || null,
2810
- username: parsed["cognito:username"] || null
2722
+ publicApiKey,
2723
+ env,
2724
+ appName,
2725
+ loginActions
2811
2726
  };
2812
- }
2813
- /**
2814
- * Check if user is currently authenticated
2815
- */
2816
- isAuthenticated() {
2817
- return this.isTokenValid();
2818
- }
2819
- /**
2820
- * Get time until token expires in minutes
2821
- */
2822
- getTimeUntilExpiration() {
2823
- const expiration = this.getTokenExpiration();
2824
- if (!expiration) return null;
2825
- const now = /* @__PURE__ */ new Date();
2826
- const minutesUntilExpiry = Math.floor((expiration.getTime() - now.getTime()) / (60 * 1e3));
2827
- return Math.max(0, minutesUntilExpiry);
2828
- }
2829
- /**
2830
- * Cleanup resources (call when the component unmounts)
2831
- */
2832
- cleanup() {
2833
- if (this.expirationCheckInterval) {
2834
- window.clearInterval(this.expirationCheckInterval);
2835
- this.expirationCheckInterval = null;
2836
- }
2837
- if (this.storageEventListener) {
2838
- window.removeEventListener("storage", this.storageEventListener);
2839
- this.storageEventListener = null;
2727
+ }, [config]);
2728
+ return { config: finalConfig };
2729
+ };
2730
+
2731
+ // src/components/CrudifyLogin/index.tsx
2732
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2733
+ var CrudifyLoginInternal = ({
2734
+ onScreenChange,
2735
+ onExternalNavigate,
2736
+ onLoginSuccess,
2737
+ onError,
2738
+ redirectUrl = "/"
2739
+ }) => {
2740
+ const { t } = useTranslation();
2741
+ const { state, setScreen } = useLoginState();
2742
+ const handleScreenChange = (screen2, params) => {
2743
+ let finalParams = params;
2744
+ if (screen2 === "login") {
2745
+ finalParams = {};
2746
+ } else if (screen2 === "forgotPassword" && !params) {
2747
+ finalParams = {};
2840
2748
  }
2841
- console.log("\u{1F510} TokenManager - Cleanup completed");
2842
- }
2843
- /**
2844
- * Get debug information about the current token state
2845
- */
2846
- getDebugInfo() {
2847
- const token = this.getToken();
2848
- const parsed = this.parseToken();
2849
- const expiration = this.getTokenExpiration();
2850
- return {
2851
- hasToken: !!token,
2852
- tokenLength: token?.length || 0,
2853
- isValid: this.isTokenValid(),
2854
- isAuthenticated: this.isAuthenticated(),
2855
- expiration: expiration?.toISOString() || null,
2856
- minutesUntilExpiry: this.getTimeUntilExpiration(),
2857
- userInfo: this.getUserInfo(),
2858
- parsedTokenKeys: parsed ? Object.keys(parsed) : []
2749
+ setScreen(screen2, finalParams);
2750
+ onScreenChange?.(screen2, finalParams);
2751
+ };
2752
+ const renderCurrentForm = () => {
2753
+ const commonProps = {
2754
+ onScreenChange: handleScreenChange,
2755
+ onExternalNavigate,
2756
+ onError,
2757
+ redirectUrl
2859
2758
  };
2860
- }
2759
+ switch (state.currentScreen) {
2760
+ case "forgotPassword":
2761
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ForgotPasswordForm_default, { ...commonProps });
2762
+ case "checkCode":
2763
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CheckCodeForm_default, { ...commonProps, searchParams: state.searchParams });
2764
+ case "resetPassword":
2765
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2766
+ ResetPasswordForm_default,
2767
+ {
2768
+ ...commonProps,
2769
+ searchParams: state.searchParams,
2770
+ onResetSuccess: () => {
2771
+ handleScreenChange("login");
2772
+ }
2773
+ }
2774
+ );
2775
+ default:
2776
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LoginForm_default, { ...commonProps, onLoginSuccess });
2777
+ }
2778
+ };
2779
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(CrudifyInitializer2, { children: [
2780
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_material6.Box, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2781
+ "img",
2782
+ {
2783
+ src: state.config.logo || "/nocios-default.png",
2784
+ alt: t("login.logoAlt"),
2785
+ style: {
2786
+ width: "100%",
2787
+ maxWidth: "150px",
2788
+ height: "auto"
2789
+ },
2790
+ onError: (e) => {
2791
+ const target = e.target;
2792
+ target.src = "/nocios-default.png";
2793
+ }
2794
+ }
2795
+ ) }),
2796
+ state.config.appName && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2797
+ import_material6.Typography,
2798
+ {
2799
+ variant: "h6",
2800
+ component: "h1",
2801
+ sx: {
2802
+ textAlign: "center",
2803
+ mb: 2,
2804
+ color: state.config.colors?.primaryColor || "#1066BA"
2805
+ },
2806
+ children: state.config.appName
2807
+ }
2808
+ ),
2809
+ renderCurrentForm()
2810
+ ] });
2861
2811
  };
2862
- _TokenManager.instance = null;
2863
- var TokenManager = _TokenManager;
2864
- var tokenManager = TokenManager.getInstance();
2865
-
2866
- // src/providers/CrudifyDataProvider.tsx
2867
- var import_jsx_runtime11 = require("react/jsx-runtime");
2868
- var CrudifyDataContext = (0, import_react12.createContext)(null);
2869
- var CrudifyDataProvider = ({
2870
- children,
2871
- env,
2872
- publicApiKey,
2873
- loginActions,
2874
- appName,
2875
- logo,
2876
- colors
2812
+ var CrudifyLogin = ({
2813
+ translations,
2814
+ translationsUrl,
2815
+ language = "en",
2816
+ config = {},
2817
+ initialScreen = "login",
2818
+ autoReadFromCookies = true,
2819
+ ...props
2877
2820
  }) => {
2878
- const [config, setConfig] = (0, import_react12.useState)(null);
2879
- const [isConfigured, setIsConfigured] = (0, import_react12.useState)(false);
2880
- const [configError, setConfigError] = (0, import_react12.useState)(null);
2881
- const [isInitialized, setIsInitialized] = (0, import_react12.useState)(false);
2882
- const [isInitializing, setIsInitializing] = (0, import_react12.useState)(false);
2883
- const [initializationError, setInitializationError] = (0, import_react12.useState)(null);
2884
- const [isAuthenticated, setIsAuthenticated] = (0, import_react12.useState)(false);
2885
- const [token, setTokenState] = (0, import_react12.useState)(null);
2886
- const [user, setUser] = (0, import_react12.useState)(null);
2887
- const [tokenExpiration, setTokenExpiration] = (0, import_react12.useState)(null);
2888
- const initializeConfiguration = (0, import_react12.useCallback)(() => {
2889
- try {
2890
- console.log("\u{1F30D} CrudifyDataProvider - Initializing configuration");
2891
- const propsConfig = {
2892
- env,
2893
- publicApiKey,
2894
- loginActions,
2895
- appName,
2896
- logo,
2897
- colors
2898
- };
2899
- const resolvedConfig = configurationManager.resolveConfig(propsConfig);
2900
- const error = configurationManager.getConfigError();
2901
- setConfig(resolvedConfig);
2902
- setConfigError(error);
2903
- setIsConfigured(configurationManager.isConfigured());
2904
- console.log("\u{1F30D} CrudifyDataProvider - Configuration initialized:", {
2905
- isConfigured: configurationManager.isConfigured(),
2906
- error,
2907
- sources: resolvedConfig.configSource
2908
- });
2909
- return resolvedConfig;
2910
- } catch (error) {
2911
- const errorMessage = error instanceof Error ? error.message : "Configuration initialization failed";
2912
- console.error("\u{1F30D} CrudifyDataProvider - Configuration error:", errorMessage);
2913
- setConfigError(errorMessage);
2914
- setIsConfigured(false);
2915
- return null;
2916
- }
2917
- }, [env, publicApiKey, loginActions, appName, logo, colors]);
2918
- const initializeCrudify = (0, import_react12.useCallback)(async (resolvedConfig) => {
2919
- if (!resolvedConfig || !resolvedConfig.publicApiKey) {
2920
- setInitializationError("Cannot initialize crudify without valid configuration");
2821
+ const { config: finalConfig } = useCrudifyLogin(config);
2822
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(I18nProvider, { translations, translationsUrl, language, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CrudifyProvider, { config: finalConfig, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LoginStateProvider, { config, initialScreen, autoReadFromCookies, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CrudifyLoginInternal, { config, ...props }) }) }) });
2823
+ };
2824
+ var CrudifyLogin_default = CrudifyLogin;
2825
+
2826
+ // src/components/UserProfile/UserProfileDisplay.tsx
2827
+ var import_material7 = require("@mui/material");
2828
+ var import_icons_material = require("@mui/icons-material");
2829
+
2830
+ // src/hooks/useUserProfile.ts
2831
+ var import_react11 = require("react");
2832
+ var import_crudify_browser4 = __toESM(require("@nocios/crudify-browser"));
2833
+ var useUserProfile = (options = {}) => {
2834
+ const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
2835
+ const [userProfile, setUserProfile] = (0, import_react11.useState)(null);
2836
+ const [loading, setLoading] = (0, import_react11.useState)(false);
2837
+ const [error, setError] = (0, import_react11.useState)(null);
2838
+ const [extendedData, setExtendedData] = (0, import_react11.useState)({});
2839
+ const abortControllerRef = (0, import_react11.useRef)(null);
2840
+ const mountedRef = (0, import_react11.useRef)(true);
2841
+ const requestIdRef = (0, import_react11.useRef)(0);
2842
+ const retryCountRef = (0, import_react11.useRef)(0);
2843
+ const clearProfile = (0, import_react11.useCallback)(() => {
2844
+ setUserProfile(null);
2845
+ setError(null);
2846
+ setLoading(false);
2847
+ setExtendedData({});
2848
+ }, []);
2849
+ const refreshProfile = (0, import_react11.useCallback)(async () => {
2850
+ const userEmail = getCurrentUserEmail();
2851
+ if (!userEmail) {
2852
+ if (mountedRef.current) {
2853
+ setError("No user email available");
2854
+ setLoading(false);
2855
+ }
2921
2856
  return;
2922
2857
  }
2923
- try {
2924
- setIsInitializing(true);
2925
- setInitializationError(null);
2926
- console.log("\u{1F680} CrudifyDataProvider - Starting crudify initialization");
2927
- await crudifyInitializer.initialize({
2928
- env: resolvedConfig.env,
2929
- publicApiKey: resolvedConfig.publicApiKey,
2930
- loginActions: resolvedConfig.loginActions,
2931
- appName: resolvedConfig.appName,
2932
- logo: resolvedConfig.logo,
2933
- colors: resolvedConfig.colors
2934
- });
2935
- setIsInitialized(true);
2936
- console.log("\u{1F680} CrudifyDataProvider - Crudify initialization completed");
2937
- } catch (error) {
2938
- const errorMessage = error instanceof Error ? error.message : "Crudify initialization failed";
2939
- console.error("\u{1F680} CrudifyDataProvider - Initialization error:", errorMessage);
2940
- setInitializationError(errorMessage);
2941
- setIsInitialized(false);
2942
- } finally {
2943
- setIsInitializing(false);
2858
+ if (abortControllerRef.current) {
2859
+ abortControllerRef.current.abort();
2944
2860
  }
2945
- }, []);
2946
- const updateAuthenticationState = (0, import_react12.useCallback)(() => {
2947
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Starting authentication state update");
2861
+ const abortController = new AbortController();
2862
+ abortControllerRef.current = abortController;
2863
+ const currentRequestId = ++requestIdRef.current;
2948
2864
  try {
2949
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting token from TokenManager");
2950
- const currentToken = tokenManager.getToken();
2951
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token retrieved:", !!currentToken);
2952
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Parsing token");
2953
- const parsedUser = tokenManager.parseToken();
2954
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token parsed:", !!parsedUser);
2955
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting expiration");
2956
- const expiration = tokenManager.getTokenExpiration();
2957
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Expiration retrieved:", !!expiration);
2958
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Checking authentication");
2959
- const authenticated = tokenManager.isAuthenticated();
2960
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication checked:", authenticated);
2961
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Updating state variables");
2962
- setTokenState(currentToken);
2963
- setUser(parsedUser);
2964
- setTokenExpiration(expiration);
2965
- setIsAuthenticated(authenticated);
2966
- console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication state updated successfully:", {
2967
- hasToken: !!currentToken,
2968
- isAuthenticated: authenticated,
2969
- userEmail: parsedUser?.email || null,
2970
- expiration: expiration?.toISOString() || null
2971
- });
2972
- } catch (error) {
2973
- console.error("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Error updating authentication state:", error);
2974
- }
2975
- }, []);
2976
- const setToken = (0, import_react12.useCallback)((newToken) => {
2977
- console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting new token:", newToken ? "provided" : "null");
2978
- tokenManager.setToken(newToken);
2979
- console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Updating state using newToken directly");
2980
- if (newToken) {
2981
- const parsedUser = tokenManager.parseToken(newToken);
2982
- const expiration = tokenManager.getTokenExpiration();
2983
- const authenticated = tokenManager.isTokenValid(newToken);
2984
- setTokenState(newToken);
2985
- setUser(parsedUser);
2986
- setTokenExpiration(expiration);
2987
- setIsAuthenticated(authenticated);
2988
- console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Token set, state updated", {
2989
- hasToken: true,
2990
- isAuthenticated: authenticated,
2991
- userEmail: parsedUser?.email || null
2865
+ if (mountedRef.current) {
2866
+ setLoading(true);
2867
+ setError(null);
2868
+ }
2869
+ const response = await import_crudify_browser4.default.readItems("users", {
2870
+ where: { email: userEmail },
2871
+ limit: 1
2992
2872
  });
2993
- } else {
2994
- setTokenState(null);
2995
- setUser(null);
2996
- setTokenExpiration(null);
2997
- setIsAuthenticated(false);
2998
- console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Token cleared, state reset");
2999
- }
3000
- }, []);
3001
- const logout = (0, import_react12.useCallback)(() => {
3002
- console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Logging out user");
3003
- tokenManager.clearToken();
3004
- console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Updating state directly");
3005
- setTokenState(null);
3006
- setUser(null);
3007
- setTokenExpiration(null);
3008
- setIsAuthenticated(false);
3009
- console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: User logged out, state cleared");
3010
- }, []);
3011
- const refreshConfig = (0, import_react12.useCallback)(() => {
3012
- console.log("\u{1F30D} CrudifyDataProvider - Refreshing configuration");
3013
- configurationManager.clearConfig();
3014
- const newConfig = initializeConfiguration();
3015
- if (newConfig && newConfig.publicApiKey) {
3016
- initializeCrudify(newConfig);
3017
- }
3018
- }, [initializeConfiguration, initializeCrudify]);
3019
- const reinitialize = (0, import_react12.useCallback)(async () => {
3020
- if (!config || !config.publicApiKey) {
3021
- console.warn("\u{1F680} CrudifyDataProvider - Cannot reinitialize without valid configuration");
3022
- return;
2873
+ if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
2874
+ if (response.success && response.data && response.data.length > 0) {
2875
+ const userData = response.data[0];
2876
+ setUserProfile(userData);
2877
+ const additionalData = {
2878
+ fullProfile: userData,
2879
+ totalFields: Object.keys(userData).length,
2880
+ displayData: {
2881
+ id: userData.id,
2882
+ email: userData.email,
2883
+ username: userData.username,
2884
+ firstName: userData.firstName,
2885
+ lastName: userData.lastName,
2886
+ fullName: userData.fullName || `${userData.firstName || ""} ${userData.lastName || ""}`.trim(),
2887
+ role: userData.role,
2888
+ permissions: userData.permissions || [],
2889
+ isActive: userData.isActive,
2890
+ lastLogin: userData.lastLogin,
2891
+ createdAt: userData.createdAt,
2892
+ updatedAt: userData.updatedAt,
2893
+ // Include any custom fields
2894
+ ...Object.keys(userData).filter((key) => !["id", "email", "username", "firstName", "lastName", "fullName", "role", "permissions", "isActive", "lastLogin", "createdAt", "updatedAt"].includes(key)).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
2895
+ }
2896
+ };
2897
+ setExtendedData(additionalData);
2898
+ setError(null);
2899
+ retryCountRef.current = 0;
2900
+ } else {
2901
+ setError("User profile not found");
2902
+ setUserProfile(null);
2903
+ setExtendedData({});
2904
+ }
2905
+ }
2906
+ } catch (err) {
2907
+ if (currentRequestId === requestIdRef.current && mountedRef.current) {
2908
+ const error2 = err;
2909
+ if (error2.name === "AbortError") {
2910
+ return;
2911
+ }
2912
+ const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
2913
+ if (shouldRetry) {
2914
+ retryCountRef.current++;
2915
+ setTimeout(() => {
2916
+ if (mountedRef.current) {
2917
+ refreshProfile();
2918
+ }
2919
+ }, 1e3 * retryCountRef.current);
2920
+ } else {
2921
+ setError("Failed to load user profile");
2922
+ setUserProfile(null);
2923
+ setExtendedData({});
2924
+ }
2925
+ }
2926
+ } finally {
2927
+ if (currentRequestId === requestIdRef.current && mountedRef.current) {
2928
+ setLoading(false);
2929
+ }
2930
+ if (abortControllerRef.current === abortController) {
2931
+ abortControllerRef.current = null;
2932
+ }
3023
2933
  }
3024
- console.log("\u{1F680} CrudifyDataProvider - Force reinitializing crudify");
3025
- crudifyInitializer.reset();
3026
- await initializeCrudify(config);
3027
- }, [config, initializeCrudify]);
3028
- const getDebugInfo = (0, import_react12.useCallback)(() => {
3029
- return {
3030
- provider: {
3031
- isConfigured,
3032
- configError,
3033
- isInitialized,
3034
- isInitializing,
3035
- initializationError,
3036
- isAuthenticated
3037
- },
3038
- configuration: {
3039
- config: config ? {
3040
- env: config.env,
3041
- publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
3042
- appName: config.appName,
3043
- loginActionsCount: config.loginActions.length,
3044
- hasLogo: !!config.logo,
3045
- colorsCount: Object.keys(config.colors).length
3046
- } : null,
3047
- sources: config?.configSource || null,
3048
- rawConfig: config?.rawConfig || null
3049
- },
3050
- authentication: {
3051
- hasToken: !!token,
3052
- tokenLength: token?.length || 0,
3053
- userEmail: user?.email || null,
3054
- userId: user?.sub || null,
3055
- expiration: tokenExpiration?.toISOString() || null,
3056
- minutesUntilExpiry: tokenManager.getTimeUntilExpiration()
3057
- },
3058
- tokenManager: tokenManager.getDebugInfo(),
3059
- crudifyInitializer: crudifyInitializer.getStatus()
3060
- };
3061
- }, [isConfigured, configError, isInitialized, isInitializing, initializationError, isAuthenticated, config, token, user, tokenExpiration]);
3062
- (0, import_react12.useEffect)(() => {
3063
- console.log("\u{1F30D} CrudifyDataProvider - Provider mounting, starting initialization");
3064
- const resolvedConfig = initializeConfiguration();
3065
- updateAuthenticationState();
3066
- if (resolvedConfig && resolvedConfig.publicApiKey) {
3067
- initializeCrudify(resolvedConfig);
2934
+ }, [retryOnError, maxRetries]);
2935
+ (0, import_react11.useEffect)(() => {
2936
+ if (autoFetch) {
2937
+ refreshProfile();
3068
2938
  }
2939
+ }, [autoFetch, refreshProfile]);
2940
+ (0, import_react11.useEffect)(() => {
2941
+ mountedRef.current = true;
3069
2942
  return () => {
3070
- console.log("\u{1F30D} CrudifyDataProvider - Provider unmounting, cleaning up");
3071
- tokenManager.cleanup();
2943
+ mountedRef.current = false;
2944
+ if (abortControllerRef.current) {
2945
+ abortControllerRef.current.abort();
2946
+ abortControllerRef.current = null;
2947
+ }
3072
2948
  };
3073
2949
  }, []);
3074
- (0, import_react12.useEffect)(() => {
3075
- console.log("\u{1F510} CrudifyDataProvider - INITIAL_AUTH_EFFECT: Loading initial authentication state");
3076
- updateAuthenticationState();
3077
- }, []);
3078
- const contextValue = {
3079
- // Configuration
3080
- config,
3081
- isConfigured,
3082
- configError,
3083
- configSource: config ? JSON.stringify(config.configSource) : "none",
3084
- // Initialization
3085
- isInitialized,
3086
- isInitializing,
3087
- initializationError,
3088
- // Authentication
3089
- isAuthenticated,
3090
- token,
3091
- user,
3092
- tokenExpiration,
3093
- // Actions
3094
- setToken,
3095
- logout,
3096
- refreshConfig,
3097
- reinitialize,
3098
- // Debug
3099
- getDebugInfo
2950
+ return {
2951
+ userProfile,
2952
+ loading,
2953
+ error,
2954
+ extendedData,
2955
+ refreshProfile,
2956
+ clearProfile
3100
2957
  };
3101
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CrudifyDataContext.Provider, { value: contextValue, children });
3102
2958
  };
3103
- var useCrudifyDataContext = () => {
3104
- const context = (0, import_react12.useContext)(CrudifyDataContext);
3105
- if (!context) {
3106
- throw new Error(
3107
- "useCrudifyDataContext must be used within a CrudifyDataProvider. Make sure to wrap your app with <CrudifyDataProvider>."
2959
+
2960
+ // src/components/UserProfile/UserProfileDisplay.tsx
2961
+ var import_react12 = require("react");
2962
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2963
+ var UserProfileDisplay = ({
2964
+ showExtendedData = true,
2965
+ showProfileCard = true,
2966
+ autoRefresh = true
2967
+ }) => {
2968
+ const { userProfile, loading, error, extendedData, refreshProfile } = useUserProfile({
2969
+ autoFetch: autoRefresh,
2970
+ retryOnError: true,
2971
+ maxRetries: 3
2972
+ });
2973
+ const [showAllFields, setShowAllFields] = (0, import_react12.useState)(false);
2974
+ if (loading) {
2975
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", justifyContent: "center", alignItems: "center", p: 3, children: [
2976
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.CircularProgress, {}),
2977
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "body2", sx: { ml: 2 }, children: "Cargando perfil de usuario..." })
2978
+ ] });
2979
+ }
2980
+ if (error) {
2981
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2982
+ import_material7.Alert,
2983
+ {
2984
+ severity: "error",
2985
+ action: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.IconButton, { color: "inherit", size: "small", onClick: refreshProfile, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "caption", children: "Reintentar" }) }),
2986
+ children: [
2987
+ "Error al cargar el perfil: ",
2988
+ error
2989
+ ]
2990
+ }
3108
2991
  );
3109
2992
  }
3110
- return context;
3111
- };
3112
-
3113
- // src/hooks/useCrudifyAuth.ts
3114
- var useCrudifyAuth = () => {
3115
- const {
3116
- isAuthenticated,
3117
- isInitializing,
3118
- initializationError,
3119
- token,
3120
- user,
3121
- tokenExpiration,
3122
- setToken,
3123
- logout
3124
- } = useCrudifyDataContext();
3125
- return {
3126
- // Estado básico
3127
- isAuthenticated,
3128
- loading: isInitializing,
3129
- error: initializationError,
3130
- // Datos del token
3131
- token,
3132
- user,
3133
- tokenExpiration,
3134
- // Acciones
3135
- setToken,
3136
- logout,
3137
- refreshToken: void 0
3138
- // Will be implemented in future versions
2993
+ if (!userProfile) {
2994
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Alert, { severity: "warning", children: "No se encontr\xF3 informaci\xF3n del usuario" });
2995
+ }
2996
+ const displayData = extendedData?.displayData || {};
2997
+ const totalFields = extendedData?.totalFields || 0;
2998
+ const formatDate = (dateString) => {
2999
+ if (!dateString) return "No disponible";
3000
+ try {
3001
+ return new Date(dateString).toLocaleString("es-ES", {
3002
+ year: "numeric",
3003
+ month: "short",
3004
+ day: "numeric",
3005
+ hour: "2-digit",
3006
+ minute: "2-digit"
3007
+ });
3008
+ } catch {
3009
+ return dateString;
3010
+ }
3011
+ };
3012
+ const renderFieldValue = (key, value) => {
3013
+ if (value === null || value === void 0) return "No disponible";
3014
+ if (typeof value === "boolean") return value ? "S\xED" : "No";
3015
+ if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "Ninguno";
3016
+ if (typeof value === "object") return JSON.stringify(value, null, 2);
3017
+ return String(value);
3139
3018
  };
3019
+ const basicFields = [
3020
+ { key: "id", label: "ID", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Badge, {}) },
3021
+ { key: "email", label: "Email", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Email, {}) },
3022
+ { key: "username", label: "Usuario", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Person, {}) },
3023
+ { key: "fullName", label: "Nombre completo", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.AccountCircle, {}) },
3024
+ { key: "role", label: "Rol", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Security, {}) }
3025
+ ];
3026
+ const extendedFields = [
3027
+ { key: "firstName", label: "Nombre" },
3028
+ { key: "lastName", label: "Apellido" },
3029
+ { key: "isActive", label: "Activo" },
3030
+ { key: "lastLogin", label: "\xDAltimo login" },
3031
+ { key: "createdAt", label: "Creado" },
3032
+ { key: "updatedAt", label: "Actualizado" }
3033
+ ];
3034
+ const knownFields = [...basicFields.map((f) => f.key), ...extendedFields.map((f) => f.key), "permissions"];
3035
+ const customFields = Object.keys(displayData).filter((key) => !knownFields.includes(key)).map((key) => ({ key, label: key }));
3036
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { children: [
3037
+ showProfileCard && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Card, { sx: { mb: 2 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.CardContent, { children: [
3038
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", alignItems: "center", mb: 2, children: [
3039
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3040
+ import_material7.Avatar,
3041
+ {
3042
+ src: displayData.avatar,
3043
+ sx: { width: 56, height: 56, mr: 2 },
3044
+ children: displayData.fullName?.[0] || displayData.username?.[0] || displayData.email?.[0]
3045
+ }
3046
+ ),
3047
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { children: [
3048
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "h6", children: displayData.fullName || displayData.username || displayData.email }),
3049
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "body2", color: "text.secondary", children: displayData.role || "Usuario" }),
3050
+ displayData.isActive !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3051
+ import_material7.Chip,
3052
+ {
3053
+ label: displayData.isActive ? "Activo" : "Inactivo",
3054
+ color: displayData.isActive ? "success" : "error",
3055
+ size: "small",
3056
+ sx: { mt: 0.5 }
3057
+ }
3058
+ )
3059
+ ] })
3060
+ ] }),
3061
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Box, { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: 2, children: basicFields.map(
3062
+ ({ key, label, icon }) => displayData[key] ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", alignItems: "center", children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Box, { sx: { mr: 1, color: "text.secondary" }, children: icon }),
3064
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { children: [
3065
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "caption", color: "text.secondary", children: label }),
3066
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "body2", children: renderFieldValue(key, displayData[key]) })
3067
+ ] })
3068
+ ] }, key) : null
3069
+ ) }),
3070
+ displayData.permissions && Array.isArray(displayData.permissions) && displayData.permissions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { mt: 2, children: [
3071
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "caption", color: "text.secondary", display: "block", children: "Permisos" }),
3072
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", flexWrap: "wrap", gap: 0.5, mt: 0.5, children: [
3073
+ displayData.permissions.slice(0, 5).map((permission, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Chip, { label: permission, size: "small", variant: "outlined" }, index)),
3074
+ displayData.permissions.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Chip, { label: `+${displayData.permissions.length - 5} m\xE1s`, size: "small" })
3075
+ ] })
3076
+ ] })
3077
+ ] }) }),
3078
+ showExtendedData && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Card, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.CardContent, { children: [
3079
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2, children: [
3080
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Typography, { variant: "h6", display: "flex", alignItems: "center", children: [
3081
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Info, { sx: { mr: 1 } }),
3082
+ "Informaci\xF3n Detallada"
3083
+ ] }),
3084
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Chip, { label: `${totalFields} campos totales`, size: "small" })
3085
+ ] }),
3086
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.List, { dense: true, children: [
3087
+ extendedFields.map(({ key, label }) => displayData[key] !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.ListItem, { divider: true, children: [
3088
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.ListItemIcon, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.Schedule, { fontSize: "small" }) }),
3089
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3090
+ import_material7.ListItemText,
3091
+ {
3092
+ primary: label,
3093
+ secondary: key.includes("At") || key.includes("Login") ? formatDate(displayData[key]) : renderFieldValue(key, displayData[key])
3094
+ }
3095
+ )
3096
+ ] }, key)),
3097
+ customFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3098
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Divider, { sx: { my: 1 } }),
3099
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.ListItem, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3100
+ import_material7.ListItemText,
3101
+ {
3102
+ primary: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
3103
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Typography, { variant: "subtitle2", children: [
3104
+ "Campos Personalizados (",
3105
+ customFields.length,
3106
+ ")"
3107
+ ] }),
3108
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.IconButton, { size: "small", onClick: () => setShowAllFields(!showAllFields), children: showAllFields ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.ExpandLess, {}) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material.ExpandMore, {}) })
3109
+ ] })
3110
+ }
3111
+ ) }),
3112
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Collapse, { in: showAllFields, children: customFields.map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.ListItem, { sx: { pl: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3113
+ import_material7.ListItemText,
3114
+ {
3115
+ primary: label,
3116
+ secondary: renderFieldValue(key, displayData[key])
3117
+ }
3118
+ ) }, key)) })
3119
+ ] })
3120
+ ] }),
3121
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Box, { mt: 2, display: "flex", justifyContent: "space-between", alignItems: "center", children: [
3122
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_material7.Typography, { variant: "caption", color: "text.secondary", children: [
3123
+ "\xDAltima actualizaci\xF3n: ",
3124
+ formatDate(displayData.updatedAt)
3125
+ ] }),
3126
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.IconButton, { size: "small", onClick: refreshProfile, disabled: loading, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_material7.Typography, { variant: "caption", children: "Actualizar" }) })
3127
+ ] })
3128
+ ] }) })
3129
+ ] });
3140
3130
  };
3131
+ var UserProfileDisplay_default = UserProfileDisplay;
3141
3132
 
3142
3133
  // src/hooks/useCrudifyUser.ts
3143
3134
  var import_react13 = require("react");