@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.
- package/dist/index.js +2109 -2118
- package/dist/index.mjs +2176 -2185
- 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
|
|
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/
|
|
833
|
-
var
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
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
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
|
|
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
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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 (
|
|
880
|
-
|
|
881
|
-
return;
|
|
954
|
+
if (envValue !== void 0) {
|
|
955
|
+
configSource[key] = "env";
|
|
956
|
+
return envValue;
|
|
882
957
|
}
|
|
883
|
-
|
|
884
|
-
|
|
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
|
-
|
|
887
|
-
|
|
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
|
|
890
|
-
|
|
891
|
-
|
|
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
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
-
|
|
1041
|
+
_ConfigurationManager.instance = null;
|
|
1042
|
+
var ConfigurationManager = _ConfigurationManager;
|
|
1043
|
+
var configurationManager = ConfigurationManager.getInstance();
|
|
1040
1044
|
|
|
1041
|
-
// src/
|
|
1042
|
-
var
|
|
1043
|
-
var
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
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
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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 (
|
|
1083
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
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
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
-
|
|
1344
|
-
|
|
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
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
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
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
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
|
-
|
|
1384
|
-
|
|
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
|
-
|
|
1220
|
+
_CrudifyInitializer.instance = null;
|
|
1221
|
+
var CrudifyInitializer = _CrudifyInitializer;
|
|
1222
|
+
var crudifyInitializer = CrudifyInitializer.getInstance();
|
|
1457
1223
|
|
|
1458
|
-
// src/
|
|
1459
|
-
var
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
var
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
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
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
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
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
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 (
|
|
1510
|
-
|
|
1511
|
-
return;
|
|
1257
|
+
if (!token) {
|
|
1258
|
+
console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
|
|
1259
|
+
return null;
|
|
1512
1260
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
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/
|
|
1832
|
-
var
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
1306
|
+
* Reset the singleton instance (useful for testing)
|
|
2143
1307
|
*/
|
|
2144
|
-
static
|
|
2145
|
-
if (
|
|
2146
|
-
|
|
1308
|
+
static resetInstance() {
|
|
1309
|
+
if (_TokenManager.instance) {
|
|
1310
|
+
_TokenManager.instance.cleanup();
|
|
2147
1311
|
}
|
|
2148
|
-
|
|
1312
|
+
_TokenManager.instance = null;
|
|
2149
1313
|
}
|
|
2150
1314
|
/**
|
|
2151
|
-
*
|
|
1315
|
+
* Initialize the token manager with storage synchronization
|
|
2152
1316
|
*/
|
|
2153
|
-
|
|
2154
|
-
|
|
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
|
-
*
|
|
1326
|
+
* Migrate tokens from localStorage to sessionStorage for better security
|
|
1327
|
+
* This ensures compatibility with older implementations
|
|
2158
1328
|
*/
|
|
2159
|
-
|
|
2160
|
-
if (this.resolvedConfig && this.isConfigStillValid(propsConfig)) {
|
|
2161
|
-
return this.resolvedConfig;
|
|
2162
|
-
}
|
|
1329
|
+
migrateFromLocalStorage() {
|
|
2163
1330
|
try {
|
|
2164
|
-
|
|
2165
|
-
const
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
1346
|
+
* Load token from storage and synchronize with crudify
|
|
2240
1347
|
*/
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
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
|
-
*
|
|
1372
|
+
* Set up automatic token expiration checking
|
|
2248
1373
|
*/
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
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
|
-
*
|
|
1383
|
+
* Set up storage event listener for cross-tab synchronization
|
|
2267
1384
|
*/
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
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
|
-
*
|
|
1395
|
+
* Set a new JWT token with automatic synchronization
|
|
2278
1396
|
*/
|
|
2279
|
-
|
|
2280
|
-
|
|
1397
|
+
setToken(token) {
|
|
1398
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Entry point - setting token:", token ? "provided" : "null");
|
|
2281
1399
|
try {
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
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
|
-
|
|
2303
|
-
if (
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
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.
|
|
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
|
|
1425
|
+
* Get the current JWT token
|
|
2323
1426
|
*/
|
|
2324
|
-
|
|
2325
|
-
|
|
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
|
-
*
|
|
1447
|
+
* Parse the current JWT token
|
|
2329
1448
|
*/
|
|
2330
|
-
|
|
2331
|
-
|
|
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
|
-
*
|
|
1471
|
+
* Check if a token is valid (properly formatted and not expired)
|
|
2335
1472
|
*/
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
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
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
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
|
-
|
|
2401
|
-
|
|
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
|
-
*
|
|
1498
|
+
* Get token expiration time as Date object
|
|
2410
1499
|
*/
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
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
|
-
*
|
|
1508
|
+
* Clear the current token from all storages and crudify
|
|
2438
1509
|
*/
|
|
2439
|
-
|
|
2440
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
1526
|
+
* Synchronize token with crudify library
|
|
2467
1527
|
*/
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
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
|
-
*
|
|
1537
|
+
* Refresh token (placeholder for future implementation)
|
|
2474
1538
|
*/
|
|
2475
|
-
|
|
2476
|
-
|
|
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
|
|
1543
|
+
* Get user information from the current token
|
|
2487
1544
|
*/
|
|
2488
|
-
|
|
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
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
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
|
|
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
|
-
|
|
2506
|
-
return this.
|
|
1565
|
+
isAuthenticated() {
|
|
1566
|
+
return this.isTokenValid();
|
|
2507
1567
|
}
|
|
2508
1568
|
/**
|
|
2509
|
-
*
|
|
1569
|
+
* Get time until token expires in minutes
|
|
2510
1570
|
*/
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
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
|
-
*
|
|
1579
|
+
* Cleanup resources (call when the component unmounts)
|
|
2518
1580
|
*/
|
|
2519
|
-
|
|
2520
|
-
|
|
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
|
-
*
|
|
1593
|
+
* Get debug information about the current token state
|
|
2524
1594
|
*/
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
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
|
-
|
|
2532
|
-
var
|
|
2533
|
-
var
|
|
1611
|
+
_TokenManager.instance = null;
|
|
1612
|
+
var TokenManager = _TokenManager;
|
|
1613
|
+
var tokenManager = TokenManager.getInstance();
|
|
2534
1614
|
|
|
2535
|
-
// src/
|
|
2536
|
-
var
|
|
2537
|
-
var
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
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
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
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
|
|
2555
|
-
}
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
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
|
-
|
|
2564
|
-
}
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
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
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2603
|
-
const
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
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
|
-
|
|
2158
|
+
const parsedErrors = handleCrudifyError(response);
|
|
2159
|
+
const translatedErrors = parsedErrors.map(translateError);
|
|
2160
|
+
setErrors(translatedErrors);
|
|
2616
2161
|
}
|
|
2617
2162
|
} catch (error) {
|
|
2618
|
-
|
|
2619
|
-
|
|
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
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
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
|
-
}
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
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
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
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
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
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
|
-
|
|
2672
|
-
|
|
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
|
-
|
|
2438
|
+
onScreenChange?.("forgotPassword");
|
|
2691
2439
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
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
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
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
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
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
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
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
|
-
|
|
2782
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
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
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
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
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2722
|
+
publicApiKey,
|
|
2723
|
+
env,
|
|
2724
|
+
appName,
|
|
2725
|
+
loginActions
|
|
2811
2726
|
};
|
|
2812
|
-
}
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
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
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
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
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
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
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
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
|
-
|
|
2924
|
-
|
|
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
|
-
|
|
2947
|
-
|
|
2861
|
+
const abortController = new AbortController();
|
|
2862
|
+
abortControllerRef.current = abortController;
|
|
2863
|
+
const currentRequestId = ++requestIdRef.current;
|
|
2948
2864
|
try {
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
const
|
|
2954
|
-
|
|
2955
|
-
|
|
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
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
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
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
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
|
-
|
|
3071
|
-
|
|
2943
|
+
mountedRef.current = false;
|
|
2944
|
+
if (abortControllerRef.current) {
|
|
2945
|
+
abortControllerRef.current.abort();
|
|
2946
|
+
abortControllerRef.current = null;
|
|
2947
|
+
}
|
|
3072
2948
|
};
|
|
3073
2949
|
}, []);
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
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
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
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
|
-
|
|
3111
|
-
};
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
const {
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
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");
|