@nocios/crudify-ui 1.0.45 → 1.0.46
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.d.mts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +188 -26
- package/dist/index.mjs +181 -24
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _nocios_crudify_browser from '@nocios/crudify-browser';
|
|
1
2
|
export * from '@nocios/crudify-browser';
|
|
2
3
|
export { default as crudify } from '@nocios/crudify-browser';
|
|
3
4
|
import React from 'react';
|
|
@@ -27,6 +28,47 @@ interface CrudifyLoginProps {
|
|
|
27
28
|
|
|
28
29
|
declare const CrudifyLogin: React.FC<CrudifyLoginProps>;
|
|
29
30
|
|
|
31
|
+
interface UseUserProfileOptions {
|
|
32
|
+
autoFetch?: boolean;
|
|
33
|
+
retryOnError?: boolean;
|
|
34
|
+
maxRetries?: number;
|
|
35
|
+
}
|
|
36
|
+
interface UseUserProfileReturn {
|
|
37
|
+
userProfile: any | null;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
error: string | null;
|
|
40
|
+
refreshProfile: () => Promise<void>;
|
|
41
|
+
clearProfile: () => void;
|
|
42
|
+
}
|
|
43
|
+
declare const useUserProfile: (options?: UseUserProfileOptions) => UseUserProfileReturn;
|
|
44
|
+
|
|
45
|
+
interface UseCrudifyLoginOptions {
|
|
46
|
+
showErrorNotifications?: boolean;
|
|
47
|
+
showSuccessNotifications?: boolean;
|
|
48
|
+
}
|
|
49
|
+
declare const useCrudifyLogin: (config: CrudifyLoginConfig, _options?: UseCrudifyLoginOptions) => {
|
|
50
|
+
crudify: {
|
|
51
|
+
login: (identifier: string, password: string) => Promise<_nocios_crudify_browser.CrudifyResponse>;
|
|
52
|
+
transaction: (data: any, options?: {
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
}) => Promise<_nocios_crudify_browser.CrudifyResponse>;
|
|
55
|
+
} | null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
interface JWTPayload {
|
|
59
|
+
email?: string;
|
|
60
|
+
"cognito:username"?: string;
|
|
61
|
+
sub?: string;
|
|
62
|
+
exp?: number;
|
|
63
|
+
iat?: number;
|
|
64
|
+
iss?: string;
|
|
65
|
+
aud?: string;
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}
|
|
68
|
+
declare const decodeJwtSafely: (token: string) => JWTPayload | null;
|
|
69
|
+
declare const getCurrentUserEmail: () => string | null;
|
|
70
|
+
declare const isTokenExpired: (token: string) => boolean;
|
|
71
|
+
|
|
30
72
|
declare const getCookie: (name: string) => string | null;
|
|
31
73
|
|
|
32
74
|
declare class SecureStorage {
|
|
@@ -43,4 +85,4 @@ declare class SecureStorage {
|
|
|
43
85
|
declare const secureSessionStorage: SecureStorage;
|
|
44
86
|
declare const secureLocalStorage: SecureStorage;
|
|
45
87
|
|
|
46
|
-
export { type BoxScreenType, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, getCookie, secureLocalStorage, secureSessionStorage };
|
|
88
|
+
export { type BoxScreenType, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, decodeJwtSafely, getCookie, getCurrentUserEmail, isTokenExpired, secureLocalStorage, secureSessionStorage, useCrudifyLogin, useUserProfile };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _nocios_crudify_browser from '@nocios/crudify-browser';
|
|
1
2
|
export * from '@nocios/crudify-browser';
|
|
2
3
|
export { default as crudify } from '@nocios/crudify-browser';
|
|
3
4
|
import React from 'react';
|
|
@@ -27,6 +28,47 @@ interface CrudifyLoginProps {
|
|
|
27
28
|
|
|
28
29
|
declare const CrudifyLogin: React.FC<CrudifyLoginProps>;
|
|
29
30
|
|
|
31
|
+
interface UseUserProfileOptions {
|
|
32
|
+
autoFetch?: boolean;
|
|
33
|
+
retryOnError?: boolean;
|
|
34
|
+
maxRetries?: number;
|
|
35
|
+
}
|
|
36
|
+
interface UseUserProfileReturn {
|
|
37
|
+
userProfile: any | null;
|
|
38
|
+
loading: boolean;
|
|
39
|
+
error: string | null;
|
|
40
|
+
refreshProfile: () => Promise<void>;
|
|
41
|
+
clearProfile: () => void;
|
|
42
|
+
}
|
|
43
|
+
declare const useUserProfile: (options?: UseUserProfileOptions) => UseUserProfileReturn;
|
|
44
|
+
|
|
45
|
+
interface UseCrudifyLoginOptions {
|
|
46
|
+
showErrorNotifications?: boolean;
|
|
47
|
+
showSuccessNotifications?: boolean;
|
|
48
|
+
}
|
|
49
|
+
declare const useCrudifyLogin: (config: CrudifyLoginConfig, _options?: UseCrudifyLoginOptions) => {
|
|
50
|
+
crudify: {
|
|
51
|
+
login: (identifier: string, password: string) => Promise<_nocios_crudify_browser.CrudifyResponse>;
|
|
52
|
+
transaction: (data: any, options?: {
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
}) => Promise<_nocios_crudify_browser.CrudifyResponse>;
|
|
55
|
+
} | null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
interface JWTPayload {
|
|
59
|
+
email?: string;
|
|
60
|
+
"cognito:username"?: string;
|
|
61
|
+
sub?: string;
|
|
62
|
+
exp?: number;
|
|
63
|
+
iat?: number;
|
|
64
|
+
iss?: string;
|
|
65
|
+
aud?: string;
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}
|
|
68
|
+
declare const decodeJwtSafely: (token: string) => JWTPayload | null;
|
|
69
|
+
declare const getCurrentUserEmail: () => string | null;
|
|
70
|
+
declare const isTokenExpired: (token: string) => boolean;
|
|
71
|
+
|
|
30
72
|
declare const getCookie: (name: string) => string | null;
|
|
31
73
|
|
|
32
74
|
declare class SecureStorage {
|
|
@@ -43,4 +85,4 @@ declare class SecureStorage {
|
|
|
43
85
|
declare const secureSessionStorage: SecureStorage;
|
|
44
86
|
declare const secureLocalStorage: SecureStorage;
|
|
45
87
|
|
|
46
|
-
export { type BoxScreenType, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, getCookie, secureLocalStorage, secureSessionStorage };
|
|
88
|
+
export { type BoxScreenType, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, decodeJwtSafely, getCookie, getCurrentUserEmail, isTokenExpired, secureLocalStorage, secureSessionStorage, useCrudifyLogin, useUserProfile };
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
CrudifyLogin: () => CrudifyLogin_default,
|
|
35
|
-
crudify: () =>
|
|
35
|
+
crudify: () => import_crudify_browser3.default,
|
|
36
|
+
decodeJwtSafely: () => decodeJwtSafely,
|
|
36
37
|
getCookie: () => getCookie,
|
|
38
|
+
getCurrentUserEmail: () => getCurrentUserEmail,
|
|
39
|
+
isTokenExpired: () => isTokenExpired,
|
|
37
40
|
secureLocalStorage: () => secureLocalStorage,
|
|
38
|
-
secureSessionStorage: () => secureSessionStorage
|
|
41
|
+
secureSessionStorage: () => secureSessionStorage,
|
|
42
|
+
useCrudifyLogin: () => useCrudifyLogin,
|
|
43
|
+
useUserProfile: () => useUserProfile
|
|
39
44
|
});
|
|
40
45
|
module.exports = __toCommonJS(index_exports);
|
|
41
|
-
var
|
|
46
|
+
var import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
|
|
42
47
|
__reExport(index_exports, require("@nocios/crudify-browser"), module.exports);
|
|
43
48
|
|
|
44
49
|
// src/components/CrudifyLogin/index.tsx
|
|
@@ -64,10 +69,18 @@ var getCookie = (name) => {
|
|
|
64
69
|
// src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
|
|
65
70
|
var useCrudifyLogin = (config, _options = {}) => {
|
|
66
71
|
const finalConfig = (0, import_react.useMemo)(() => {
|
|
67
|
-
const publicApiKey = config.publicApiKey || getCookie("publicApiKey");
|
|
68
|
-
const
|
|
72
|
+
const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
|
|
73
|
+
const rawEnv = config.env || getCookie("environment") || "prod";
|
|
74
|
+
const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
|
|
69
75
|
const appName = config.appName || getCookie("appName") || "Crudia";
|
|
70
|
-
const loginActions = config.loginActions || (
|
|
76
|
+
const loginActions = config.loginActions || (() => {
|
|
77
|
+
try {
|
|
78
|
+
const cookieValue = getCookie("loginActions");
|
|
79
|
+
return cookieValue ? cookieValue.split(",").map((action) => action.trim()).filter(Boolean) : [];
|
|
80
|
+
} catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
71
84
|
return {
|
|
72
85
|
publicApiKey,
|
|
73
86
|
env,
|
|
@@ -76,15 +89,14 @@ var useCrudifyLogin = (config, _options = {}) => {
|
|
|
76
89
|
};
|
|
77
90
|
}, [config]);
|
|
78
91
|
(0, import_react.useEffect)(() => {
|
|
79
|
-
if (finalConfig.publicApiKey)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
92
|
+
if (!finalConfig.publicApiKey) return;
|
|
93
|
+
try {
|
|
94
|
+
import_crudify_browser.default.config(finalConfig.env);
|
|
95
|
+
import_crudify_browser.default.init(finalConfig.publicApiKey, "none");
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("Error initializing crudify:", error);
|
|
86
98
|
}
|
|
87
|
-
}, [finalConfig]);
|
|
99
|
+
}, [finalConfig.publicApiKey, finalConfig.env]);
|
|
88
100
|
const crudifyMethods = (0, import_react.useMemo)(() => {
|
|
89
101
|
if (!finalConfig.publicApiKey) {
|
|
90
102
|
return null;
|
|
@@ -430,13 +442,13 @@ var ForgotPasswordForm = ({ config, onNavigate, onError }) => {
|
|
|
430
442
|
const [emailSent, setEmailSent] = (0, import_react3.useState)(false);
|
|
431
443
|
const [codeAlreadyExists, setCodeAlreadyExists] = (0, import_react3.useState)(false);
|
|
432
444
|
const { t } = (0, import_react_i18next2.useTranslation)();
|
|
433
|
-
const { crudify:
|
|
445
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
434
446
|
const validateEmail = (email2) => {
|
|
435
447
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
436
448
|
return emailRegex.test(email2);
|
|
437
449
|
};
|
|
438
450
|
const handleSubmit = async () => {
|
|
439
|
-
if (loading || !
|
|
451
|
+
if (loading || !crudify3) return;
|
|
440
452
|
setErrors([]);
|
|
441
453
|
setHelperTextEmail(null);
|
|
442
454
|
if (!email) {
|
|
@@ -450,7 +462,7 @@ var ForgotPasswordForm = ({ config, onNavigate, onError }) => {
|
|
|
450
462
|
setLoading(true);
|
|
451
463
|
try {
|
|
452
464
|
const data = [{ operation: "requestPasswordReset", data: { email } }];
|
|
453
|
-
const response = await
|
|
465
|
+
const response = await crudify3.transaction(data);
|
|
454
466
|
if (response.success) {
|
|
455
467
|
if (response.data && response.data.existingCodeValid) {
|
|
456
468
|
setCodeAlreadyExists(true);
|
|
@@ -558,10 +570,10 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
558
570
|
const [codeValidated, setCodeValidated] = (0, import_react4.useState)(false);
|
|
559
571
|
const [resetSuccess, setResetSuccess] = (0, import_react4.useState)(false);
|
|
560
572
|
const { t } = (0, import_react_i18next3.useTranslation)();
|
|
561
|
-
const { crudify:
|
|
573
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
562
574
|
(0, import_react4.useEffect)(() => {
|
|
563
575
|
const validateCode = async (emailToValidate, codeToValidate) => {
|
|
564
|
-
if (!
|
|
576
|
+
if (!crudify3) return;
|
|
565
577
|
try {
|
|
566
578
|
const data = [
|
|
567
579
|
{
|
|
@@ -569,7 +581,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
569
581
|
data: { email: emailToValidate, codePassword: codeToValidate }
|
|
570
582
|
}
|
|
571
583
|
];
|
|
572
|
-
const response = await
|
|
584
|
+
const response = await crudify3.transaction(data);
|
|
573
585
|
if (response.success) {
|
|
574
586
|
setCodeValidated(true);
|
|
575
587
|
} else {
|
|
@@ -597,7 +609,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
597
609
|
setValidatingCode(false);
|
|
598
610
|
setErrors([t("resetPassword.missingParameters")]);
|
|
599
611
|
}
|
|
600
|
-
}, [searchParams,
|
|
612
|
+
}, [searchParams, crudify3, t]);
|
|
601
613
|
const validatePasswords = () => {
|
|
602
614
|
setHelperTextNewPassword(null);
|
|
603
615
|
setHelperTextConfirmPassword(null);
|
|
@@ -620,7 +632,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
620
632
|
return true;
|
|
621
633
|
};
|
|
622
634
|
const handleSubmit = async () => {
|
|
623
|
-
if (loading || !
|
|
635
|
+
if (loading || !crudify3) return;
|
|
624
636
|
setErrors([]);
|
|
625
637
|
if (!validatePasswords()) return;
|
|
626
638
|
setLoading(true);
|
|
@@ -631,7 +643,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
631
643
|
data: { email, codePassword: code, newPassword }
|
|
632
644
|
}
|
|
633
645
|
];
|
|
634
|
-
const response = await
|
|
646
|
+
const response = await crudify3.transaction(data);
|
|
635
647
|
if (response.success) {
|
|
636
648
|
setResetSuccess(true);
|
|
637
649
|
} else {
|
|
@@ -775,7 +787,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
775
787
|
const [helperTextEmail, setHelperTextEmail] = (0, import_react5.useState)(null);
|
|
776
788
|
const [helperTextCode, setHelperTextCode] = (0, import_react5.useState)(null);
|
|
777
789
|
const { t } = (0, import_react_i18next4.useTranslation)();
|
|
778
|
-
const { crudify:
|
|
790
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
779
791
|
(0, import_react5.useEffect)(() => {
|
|
780
792
|
const timer = setTimeout(() => {
|
|
781
793
|
const emailInput = document.getElementById("email");
|
|
@@ -788,7 +800,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
788
800
|
return emailRegex.test(email2);
|
|
789
801
|
};
|
|
790
802
|
const handleSubmit = async () => {
|
|
791
|
-
if (loading || !
|
|
803
|
+
if (loading || !crudify3) return;
|
|
792
804
|
setErrors([]);
|
|
793
805
|
setHelperTextEmail(null);
|
|
794
806
|
setHelperTextCode(null);
|
|
@@ -812,7 +824,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
812
824
|
data: { email, codePassword: code }
|
|
813
825
|
}
|
|
814
826
|
];
|
|
815
|
-
const response = await
|
|
827
|
+
const response = await crudify3.transaction(data);
|
|
816
828
|
if (response.success) {
|
|
817
829
|
const params = new URLSearchParams({ email, code }).toString();
|
|
818
830
|
onNavigate?.(`/login/resetPassword?${params}`);
|
|
@@ -1074,12 +1086,162 @@ var CrudifyLogin = ({
|
|
|
1074
1086
|
);
|
|
1075
1087
|
};
|
|
1076
1088
|
var CrudifyLogin_default = CrudifyLogin;
|
|
1089
|
+
|
|
1090
|
+
// src/hooks/useUserProfile.ts
|
|
1091
|
+
var import_react7 = require("react");
|
|
1092
|
+
var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
|
|
1093
|
+
|
|
1094
|
+
// src/utils/jwtUtils.ts
|
|
1095
|
+
var decodeJwtSafely = (token) => {
|
|
1096
|
+
try {
|
|
1097
|
+
const parts = token.split(".");
|
|
1098
|
+
if (parts.length !== 3) {
|
|
1099
|
+
console.warn("Invalid JWT format: token must have 3 parts");
|
|
1100
|
+
return null;
|
|
1101
|
+
}
|
|
1102
|
+
const payload = parts[1];
|
|
1103
|
+
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
1104
|
+
const decodedPayload = JSON.parse(atob(paddedPayload));
|
|
1105
|
+
return decodedPayload;
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
console.warn("Failed to decode JWT token:", error);
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
var getCurrentUserEmail = () => {
|
|
1112
|
+
try {
|
|
1113
|
+
const token = sessionStorage.getItem("token");
|
|
1114
|
+
if (!token) return null;
|
|
1115
|
+
const payload = decodeJwtSafely(token);
|
|
1116
|
+
if (!payload) return null;
|
|
1117
|
+
return payload.email || payload["cognito:username"] || null;
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
console.warn("Failed to get current user email:", error);
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
var isTokenExpired = (token) => {
|
|
1124
|
+
try {
|
|
1125
|
+
const payload = decodeJwtSafely(token);
|
|
1126
|
+
if (!payload || !payload.exp) return true;
|
|
1127
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
1128
|
+
return payload.exp < currentTime;
|
|
1129
|
+
} catch {
|
|
1130
|
+
return true;
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
// src/hooks/useUserProfile.ts
|
|
1135
|
+
var useUserProfile = (options = {}) => {
|
|
1136
|
+
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
1137
|
+
const [userProfile, setUserProfile] = (0, import_react7.useState)(null);
|
|
1138
|
+
const [loading, setLoading] = (0, import_react7.useState)(false);
|
|
1139
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
1140
|
+
const abortControllerRef = (0, import_react7.useRef)(null);
|
|
1141
|
+
const mountedRef = (0, import_react7.useRef)(true);
|
|
1142
|
+
const requestIdRef = (0, import_react7.useRef)(0);
|
|
1143
|
+
const retryCountRef = (0, import_react7.useRef)(0);
|
|
1144
|
+
const clearProfile = (0, import_react7.useCallback)(() => {
|
|
1145
|
+
setUserProfile(null);
|
|
1146
|
+
setError(null);
|
|
1147
|
+
setLoading(false);
|
|
1148
|
+
}, []);
|
|
1149
|
+
const refreshProfile = (0, import_react7.useCallback)(async () => {
|
|
1150
|
+
const userEmail = getCurrentUserEmail();
|
|
1151
|
+
if (!userEmail) {
|
|
1152
|
+
if (mountedRef.current) {
|
|
1153
|
+
setError("No user email available");
|
|
1154
|
+
setLoading(false);
|
|
1155
|
+
}
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
if (abortControllerRef.current) {
|
|
1159
|
+
abortControllerRef.current.abort();
|
|
1160
|
+
}
|
|
1161
|
+
const abortController = new AbortController();
|
|
1162
|
+
abortControllerRef.current = abortController;
|
|
1163
|
+
const currentRequestId = ++requestIdRef.current;
|
|
1164
|
+
try {
|
|
1165
|
+
if (mountedRef.current) {
|
|
1166
|
+
setLoading(true);
|
|
1167
|
+
setError(null);
|
|
1168
|
+
}
|
|
1169
|
+
const response = await import_crudify_browser2.default.readItems("users", {
|
|
1170
|
+
where: { email: userEmail },
|
|
1171
|
+
limit: 1
|
|
1172
|
+
});
|
|
1173
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
1174
|
+
if (response.success && response.data && response.data.length > 0) {
|
|
1175
|
+
setUserProfile(response.data[0]);
|
|
1176
|
+
setError(null);
|
|
1177
|
+
retryCountRef.current = 0;
|
|
1178
|
+
} else {
|
|
1179
|
+
setError("User profile not found");
|
|
1180
|
+
setUserProfile(null);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
} catch (err) {
|
|
1184
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
1185
|
+
if (err.name === "AbortError") {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
console.error("Error loading user profile:", err);
|
|
1189
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (err.message?.includes("Network Error") || err.message?.includes("Failed to fetch"));
|
|
1190
|
+
if (shouldRetry) {
|
|
1191
|
+
retryCountRef.current++;
|
|
1192
|
+
setTimeout(() => {
|
|
1193
|
+
if (mountedRef.current) {
|
|
1194
|
+
refreshProfile();
|
|
1195
|
+
}
|
|
1196
|
+
}, 1e3 * retryCountRef.current);
|
|
1197
|
+
} else {
|
|
1198
|
+
setError("Failed to load user profile");
|
|
1199
|
+
setUserProfile(null);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
} finally {
|
|
1203
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
1204
|
+
setLoading(false);
|
|
1205
|
+
}
|
|
1206
|
+
if (abortControllerRef.current === abortController) {
|
|
1207
|
+
abortControllerRef.current = null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}, [retryOnError, maxRetries]);
|
|
1211
|
+
(0, import_react7.useEffect)(() => {
|
|
1212
|
+
if (autoFetch) {
|
|
1213
|
+
refreshProfile();
|
|
1214
|
+
}
|
|
1215
|
+
}, [autoFetch, refreshProfile]);
|
|
1216
|
+
(0, import_react7.useEffect)(() => {
|
|
1217
|
+
mountedRef.current = true;
|
|
1218
|
+
return () => {
|
|
1219
|
+
mountedRef.current = false;
|
|
1220
|
+
if (abortControllerRef.current) {
|
|
1221
|
+
abortControllerRef.current.abort();
|
|
1222
|
+
abortControllerRef.current = null;
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
}, []);
|
|
1226
|
+
return {
|
|
1227
|
+
userProfile,
|
|
1228
|
+
loading,
|
|
1229
|
+
error,
|
|
1230
|
+
refreshProfile,
|
|
1231
|
+
clearProfile
|
|
1232
|
+
};
|
|
1233
|
+
};
|
|
1077
1234
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1078
1235
|
0 && (module.exports = {
|
|
1079
1236
|
CrudifyLogin,
|
|
1080
1237
|
crudify,
|
|
1238
|
+
decodeJwtSafely,
|
|
1081
1239
|
getCookie,
|
|
1240
|
+
getCurrentUserEmail,
|
|
1241
|
+
isTokenExpired,
|
|
1082
1242
|
secureLocalStorage,
|
|
1083
1243
|
secureSessionStorage,
|
|
1244
|
+
useCrudifyLogin,
|
|
1245
|
+
useUserProfile,
|
|
1084
1246
|
...require("@nocios/crudify-browser")
|
|
1085
1247
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -25,10 +25,18 @@ var getCookie = (name) => {
|
|
|
25
25
|
// src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
|
|
26
26
|
var useCrudifyLogin = (config, _options = {}) => {
|
|
27
27
|
const finalConfig = useMemo(() => {
|
|
28
|
-
const publicApiKey = config.publicApiKey || getCookie("publicApiKey");
|
|
29
|
-
const
|
|
28
|
+
const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
|
|
29
|
+
const rawEnv = config.env || getCookie("environment") || "prod";
|
|
30
|
+
const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
|
|
30
31
|
const appName = config.appName || getCookie("appName") || "Crudia";
|
|
31
|
-
const loginActions = config.loginActions || (
|
|
32
|
+
const loginActions = config.loginActions || (() => {
|
|
33
|
+
try {
|
|
34
|
+
const cookieValue = getCookie("loginActions");
|
|
35
|
+
return cookieValue ? cookieValue.split(",").map((action) => action.trim()).filter(Boolean) : [];
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
32
40
|
return {
|
|
33
41
|
publicApiKey,
|
|
34
42
|
env,
|
|
@@ -37,15 +45,14 @@ var useCrudifyLogin = (config, _options = {}) => {
|
|
|
37
45
|
};
|
|
38
46
|
}, [config]);
|
|
39
47
|
useEffect(() => {
|
|
40
|
-
if (finalConfig.publicApiKey)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
48
|
+
if (!finalConfig.publicApiKey) return;
|
|
49
|
+
try {
|
|
50
|
+
crudify.config(finalConfig.env);
|
|
51
|
+
crudify.init(finalConfig.publicApiKey, "none");
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Error initializing crudify:", error);
|
|
47
54
|
}
|
|
48
|
-
}, [finalConfig]);
|
|
55
|
+
}, [finalConfig.publicApiKey, finalConfig.env]);
|
|
49
56
|
const crudifyMethods = useMemo(() => {
|
|
50
57
|
if (!finalConfig.publicApiKey) {
|
|
51
58
|
return null;
|
|
@@ -391,13 +398,13 @@ var ForgotPasswordForm = ({ config, onNavigate, onError }) => {
|
|
|
391
398
|
const [emailSent, setEmailSent] = useState2(false);
|
|
392
399
|
const [codeAlreadyExists, setCodeAlreadyExists] = useState2(false);
|
|
393
400
|
const { t } = useTranslation2();
|
|
394
|
-
const { crudify:
|
|
401
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
395
402
|
const validateEmail = (email2) => {
|
|
396
403
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
397
404
|
return emailRegex.test(email2);
|
|
398
405
|
};
|
|
399
406
|
const handleSubmit = async () => {
|
|
400
|
-
if (loading || !
|
|
407
|
+
if (loading || !crudify3) return;
|
|
401
408
|
setErrors([]);
|
|
402
409
|
setHelperTextEmail(null);
|
|
403
410
|
if (!email) {
|
|
@@ -411,7 +418,7 @@ var ForgotPasswordForm = ({ config, onNavigate, onError }) => {
|
|
|
411
418
|
setLoading(true);
|
|
412
419
|
try {
|
|
413
420
|
const data = [{ operation: "requestPasswordReset", data: { email } }];
|
|
414
|
-
const response = await
|
|
421
|
+
const response = await crudify3.transaction(data);
|
|
415
422
|
if (response.success) {
|
|
416
423
|
if (response.data && response.data.existingCodeValid) {
|
|
417
424
|
setCodeAlreadyExists(true);
|
|
@@ -519,10 +526,10 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
519
526
|
const [codeValidated, setCodeValidated] = useState3(false);
|
|
520
527
|
const [resetSuccess, setResetSuccess] = useState3(false);
|
|
521
528
|
const { t } = useTranslation3();
|
|
522
|
-
const { crudify:
|
|
529
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
523
530
|
useEffect3(() => {
|
|
524
531
|
const validateCode = async (emailToValidate, codeToValidate) => {
|
|
525
|
-
if (!
|
|
532
|
+
if (!crudify3) return;
|
|
526
533
|
try {
|
|
527
534
|
const data = [
|
|
528
535
|
{
|
|
@@ -530,7 +537,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
530
537
|
data: { email: emailToValidate, codePassword: codeToValidate }
|
|
531
538
|
}
|
|
532
539
|
];
|
|
533
|
-
const response = await
|
|
540
|
+
const response = await crudify3.transaction(data);
|
|
534
541
|
if (response.success) {
|
|
535
542
|
setCodeValidated(true);
|
|
536
543
|
} else {
|
|
@@ -558,7 +565,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
558
565
|
setValidatingCode(false);
|
|
559
566
|
setErrors([t("resetPassword.missingParameters")]);
|
|
560
567
|
}
|
|
561
|
-
}, [searchParams,
|
|
568
|
+
}, [searchParams, crudify3, t]);
|
|
562
569
|
const validatePasswords = () => {
|
|
563
570
|
setHelperTextNewPassword(null);
|
|
564
571
|
setHelperTextConfirmPassword(null);
|
|
@@ -581,7 +588,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
581
588
|
return true;
|
|
582
589
|
};
|
|
583
590
|
const handleSubmit = async () => {
|
|
584
|
-
if (loading || !
|
|
591
|
+
if (loading || !crudify3) return;
|
|
585
592
|
setErrors([]);
|
|
586
593
|
if (!validatePasswords()) return;
|
|
587
594
|
setLoading(true);
|
|
@@ -592,7 +599,7 @@ var ResetPasswordForm = ({ config, onNavigate, onError, searchParams }) => {
|
|
|
592
599
|
data: { email, codePassword: code, newPassword }
|
|
593
600
|
}
|
|
594
601
|
];
|
|
595
|
-
const response = await
|
|
602
|
+
const response = await crudify3.transaction(data);
|
|
596
603
|
if (response.success) {
|
|
597
604
|
setResetSuccess(true);
|
|
598
605
|
} else {
|
|
@@ -736,7 +743,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
736
743
|
const [helperTextEmail, setHelperTextEmail] = useState4(null);
|
|
737
744
|
const [helperTextCode, setHelperTextCode] = useState4(null);
|
|
738
745
|
const { t } = useTranslation4();
|
|
739
|
-
const { crudify:
|
|
746
|
+
const { crudify: crudify3 } = useCrudifyLogin(config);
|
|
740
747
|
useEffect4(() => {
|
|
741
748
|
const timer = setTimeout(() => {
|
|
742
749
|
const emailInput = document.getElementById("email");
|
|
@@ -749,7 +756,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
749
756
|
return emailRegex.test(email2);
|
|
750
757
|
};
|
|
751
758
|
const handleSubmit = async () => {
|
|
752
|
-
if (loading || !
|
|
759
|
+
if (loading || !crudify3) return;
|
|
753
760
|
setErrors([]);
|
|
754
761
|
setHelperTextEmail(null);
|
|
755
762
|
setHelperTextCode(null);
|
|
@@ -773,7 +780,7 @@ var CheckCodeForm = ({ config, onNavigate, onError }) => {
|
|
|
773
780
|
data: { email, codePassword: code }
|
|
774
781
|
}
|
|
775
782
|
];
|
|
776
|
-
const response = await
|
|
783
|
+
const response = await crudify3.transaction(data);
|
|
777
784
|
if (response.success) {
|
|
778
785
|
const params = new URLSearchParams({ email, code }).toString();
|
|
779
786
|
onNavigate?.(`/login/resetPassword?${params}`);
|
|
@@ -1035,10 +1042,160 @@ var CrudifyLogin = ({
|
|
|
1035
1042
|
);
|
|
1036
1043
|
};
|
|
1037
1044
|
var CrudifyLogin_default = CrudifyLogin;
|
|
1045
|
+
|
|
1046
|
+
// src/hooks/useUserProfile.ts
|
|
1047
|
+
import { useState as useState6, useEffect as useEffect5, useCallback, useRef as useRef2 } from "react";
|
|
1048
|
+
import crudify2 from "@nocios/crudify-browser";
|
|
1049
|
+
|
|
1050
|
+
// src/utils/jwtUtils.ts
|
|
1051
|
+
var decodeJwtSafely = (token) => {
|
|
1052
|
+
try {
|
|
1053
|
+
const parts = token.split(".");
|
|
1054
|
+
if (parts.length !== 3) {
|
|
1055
|
+
console.warn("Invalid JWT format: token must have 3 parts");
|
|
1056
|
+
return null;
|
|
1057
|
+
}
|
|
1058
|
+
const payload = parts[1];
|
|
1059
|
+
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
1060
|
+
const decodedPayload = JSON.parse(atob(paddedPayload));
|
|
1061
|
+
return decodedPayload;
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
console.warn("Failed to decode JWT token:", error);
|
|
1064
|
+
return null;
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
var getCurrentUserEmail = () => {
|
|
1068
|
+
try {
|
|
1069
|
+
const token = sessionStorage.getItem("token");
|
|
1070
|
+
if (!token) return null;
|
|
1071
|
+
const payload = decodeJwtSafely(token);
|
|
1072
|
+
if (!payload) return null;
|
|
1073
|
+
return payload.email || payload["cognito:username"] || null;
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
console.warn("Failed to get current user email:", error);
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
var isTokenExpired = (token) => {
|
|
1080
|
+
try {
|
|
1081
|
+
const payload = decodeJwtSafely(token);
|
|
1082
|
+
if (!payload || !payload.exp) return true;
|
|
1083
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
1084
|
+
return payload.exp < currentTime;
|
|
1085
|
+
} catch {
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// src/hooks/useUserProfile.ts
|
|
1091
|
+
var useUserProfile = (options = {}) => {
|
|
1092
|
+
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
1093
|
+
const [userProfile, setUserProfile] = useState6(null);
|
|
1094
|
+
const [loading, setLoading] = useState6(false);
|
|
1095
|
+
const [error, setError] = useState6(null);
|
|
1096
|
+
const abortControllerRef = useRef2(null);
|
|
1097
|
+
const mountedRef = useRef2(true);
|
|
1098
|
+
const requestIdRef = useRef2(0);
|
|
1099
|
+
const retryCountRef = useRef2(0);
|
|
1100
|
+
const clearProfile = useCallback(() => {
|
|
1101
|
+
setUserProfile(null);
|
|
1102
|
+
setError(null);
|
|
1103
|
+
setLoading(false);
|
|
1104
|
+
}, []);
|
|
1105
|
+
const refreshProfile = useCallback(async () => {
|
|
1106
|
+
const userEmail = getCurrentUserEmail();
|
|
1107
|
+
if (!userEmail) {
|
|
1108
|
+
if (mountedRef.current) {
|
|
1109
|
+
setError("No user email available");
|
|
1110
|
+
setLoading(false);
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (abortControllerRef.current) {
|
|
1115
|
+
abortControllerRef.current.abort();
|
|
1116
|
+
}
|
|
1117
|
+
const abortController = new AbortController();
|
|
1118
|
+
abortControllerRef.current = abortController;
|
|
1119
|
+
const currentRequestId = ++requestIdRef.current;
|
|
1120
|
+
try {
|
|
1121
|
+
if (mountedRef.current) {
|
|
1122
|
+
setLoading(true);
|
|
1123
|
+
setError(null);
|
|
1124
|
+
}
|
|
1125
|
+
const response = await crudify2.readItems("users", {
|
|
1126
|
+
where: { email: userEmail },
|
|
1127
|
+
limit: 1
|
|
1128
|
+
});
|
|
1129
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
1130
|
+
if (response.success && response.data && response.data.length > 0) {
|
|
1131
|
+
setUserProfile(response.data[0]);
|
|
1132
|
+
setError(null);
|
|
1133
|
+
retryCountRef.current = 0;
|
|
1134
|
+
} else {
|
|
1135
|
+
setError("User profile not found");
|
|
1136
|
+
setUserProfile(null);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
} catch (err) {
|
|
1140
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
1141
|
+
if (err.name === "AbortError") {
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
console.error("Error loading user profile:", err);
|
|
1145
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (err.message?.includes("Network Error") || err.message?.includes("Failed to fetch"));
|
|
1146
|
+
if (shouldRetry) {
|
|
1147
|
+
retryCountRef.current++;
|
|
1148
|
+
setTimeout(() => {
|
|
1149
|
+
if (mountedRef.current) {
|
|
1150
|
+
refreshProfile();
|
|
1151
|
+
}
|
|
1152
|
+
}, 1e3 * retryCountRef.current);
|
|
1153
|
+
} else {
|
|
1154
|
+
setError("Failed to load user profile");
|
|
1155
|
+
setUserProfile(null);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
} finally {
|
|
1159
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
1160
|
+
setLoading(false);
|
|
1161
|
+
}
|
|
1162
|
+
if (abortControllerRef.current === abortController) {
|
|
1163
|
+
abortControllerRef.current = null;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}, [retryOnError, maxRetries]);
|
|
1167
|
+
useEffect5(() => {
|
|
1168
|
+
if (autoFetch) {
|
|
1169
|
+
refreshProfile();
|
|
1170
|
+
}
|
|
1171
|
+
}, [autoFetch, refreshProfile]);
|
|
1172
|
+
useEffect5(() => {
|
|
1173
|
+
mountedRef.current = true;
|
|
1174
|
+
return () => {
|
|
1175
|
+
mountedRef.current = false;
|
|
1176
|
+
if (abortControllerRef.current) {
|
|
1177
|
+
abortControllerRef.current.abort();
|
|
1178
|
+
abortControllerRef.current = null;
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
}, []);
|
|
1182
|
+
return {
|
|
1183
|
+
userProfile,
|
|
1184
|
+
loading,
|
|
1185
|
+
error,
|
|
1186
|
+
refreshProfile,
|
|
1187
|
+
clearProfile
|
|
1188
|
+
};
|
|
1189
|
+
};
|
|
1038
1190
|
export {
|
|
1039
1191
|
CrudifyLogin_default as CrudifyLogin,
|
|
1040
1192
|
default2 as crudify,
|
|
1193
|
+
decodeJwtSafely,
|
|
1041
1194
|
getCookie,
|
|
1195
|
+
getCurrentUserEmail,
|
|
1196
|
+
isTokenExpired,
|
|
1042
1197
|
secureLocalStorage,
|
|
1043
|
-
secureSessionStorage
|
|
1198
|
+
secureSessionStorage,
|
|
1199
|
+
useCrudifyLogin,
|
|
1200
|
+
useUserProfile
|
|
1044
1201
|
};
|