@nocios/crudify-ui 3.0.6 → 3.0.10

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.mjs CHANGED
@@ -667,7 +667,7 @@ function handleCrudifyError(error) {
667
667
  // src/components/CrudifyLogin/Forms/LoginForm.tsx
668
668
  import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
669
669
  var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
670
- const { crudify: crudify7 } = useCrudify();
670
+ const { crudify: crudify6 } = useCrudify();
671
671
  const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
672
672
  const { t } = useTranslation();
673
673
  const usernameInputRef = useRef(null);
@@ -718,10 +718,10 @@ var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError,
718
718
  clearErrors();
719
719
  setLoading(true);
720
720
  try {
721
- if (!crudify7) {
721
+ if (!crudify6) {
722
722
  throw new Error("Crudify not initialized");
723
723
  }
724
- const response = await crudify7.login(state.formData.username, state.formData.password);
724
+ const response = await crudify6.login(state.formData.username, state.formData.password);
725
725
  setLoading(false);
726
726
  if (response.success) {
727
727
  console.log("\u{1F510} LoginForm - Login successful, calling onLoginSuccess");
@@ -876,7 +876,7 @@ import { useState as useState3 } from "react";
876
876
  import { Typography as Typography2, TextField as TextField2, Button as Button2, Box as Box2, CircularProgress as CircularProgress2, Alert as Alert2, Link as Link2 } from "@mui/material";
877
877
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
878
878
  var ForgotPasswordForm = ({ onScreenChange, onError }) => {
879
- const { crudify: crudify7 } = useCrudify();
879
+ const { crudify: crudify6 } = useCrudify();
880
880
  const [email, setEmail] = useState3("");
881
881
  const [loading, setLoading] = useState3(false);
882
882
  const [errors, setErrors] = useState3([]);
@@ -905,7 +905,7 @@ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
905
905
  return emailRegex.test(email2);
906
906
  };
907
907
  const handleSubmit = async () => {
908
- if (loading || !crudify7) return;
908
+ if (loading || !crudify6) return;
909
909
  setErrors([]);
910
910
  setHelperTextEmail(null);
911
911
  if (!email) {
@@ -919,7 +919,7 @@ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
919
919
  setLoading(true);
920
920
  try {
921
921
  const data = [{ operation: "requestPasswordReset", data: { email } }];
922
- const response = await crudify7.transaction(data);
922
+ const response = await crudify6.transaction(data);
923
923
  if (response.success) {
924
924
  if (response.data && response.data.existingCodeValid) {
925
925
  setCodeAlreadyExists(true);
@@ -1022,7 +1022,7 @@ import { useState as useState4, useEffect as useEffect5 } from "react";
1022
1022
  import { Typography as Typography3, TextField as TextField3, Button as Button3, Box as Box3, CircularProgress as CircularProgress3, Alert as Alert3, Link as Link3 } from "@mui/material";
1023
1023
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1024
1024
  var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
1025
- const { crudify: crudify7 } = useCrudify();
1025
+ const { crudify: crudify6 } = useCrudify();
1026
1026
  const [newPassword, setNewPassword] = useState4("");
1027
1027
  const [confirmPassword, setConfirmPassword] = useState4("");
1028
1028
  const [loading, setLoading] = useState4(false);
@@ -1102,9 +1102,9 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
1102
1102
  setErrors([t("resetPassword.invalidCode")]);
1103
1103
  setValidatingCode(false);
1104
1104
  setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
1105
- }, [searchParams, crudify7, t, onScreenChange]);
1105
+ }, [searchParams, crudify6, t, onScreenChange]);
1106
1106
  useEffect5(() => {
1107
- if (crudify7 && pendingValidation && !isValidating) {
1107
+ if (crudify6 && pendingValidation && !isValidating) {
1108
1108
  setIsValidating(true);
1109
1109
  const validateCode = async (emailToValidate, codeToValidate) => {
1110
1110
  try {
@@ -1114,7 +1114,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
1114
1114
  data: { email: emailToValidate, codePassword: codeToValidate }
1115
1115
  }
1116
1116
  ];
1117
- const response = await crudify7.transaction(data);
1117
+ const response = await crudify6.transaction(data);
1118
1118
  if (response.data && Array.isArray(response.data)) {
1119
1119
  const validationResult = response.data[0];
1120
1120
  if (validationResult && validationResult.response && validationResult.response.status === "OK") {
@@ -1143,7 +1143,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
1143
1143
  };
1144
1144
  validateCode(pendingValidation.email, pendingValidation.code);
1145
1145
  }
1146
- }, [crudify7, pendingValidation, t, onScreenChange]);
1146
+ }, [crudify6, pendingValidation, t, onScreenChange]);
1147
1147
  const validatePassword = (password) => {
1148
1148
  if (password.length < 8) {
1149
1149
  return t("resetPassword.passwordTooShort");
@@ -1151,7 +1151,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
1151
1151
  return null;
1152
1152
  };
1153
1153
  const handleSubmit = async () => {
1154
- if (loading || !crudify7) return;
1154
+ if (loading || !crudify6) return;
1155
1155
  setErrors([]);
1156
1156
  setHelperTextNewPassword(null);
1157
1157
  setHelperTextConfirmPassword(null);
@@ -1182,7 +1182,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
1182
1182
  data: { email, codePassword: code, newPassword }
1183
1183
  }
1184
1184
  ];
1185
- const response = await crudify7.transaction(data);
1185
+ const response = await crudify6.transaction(data);
1186
1186
  if (response.success) {
1187
1187
  setErrors([]);
1188
1188
  setTimeout(() => {
@@ -1293,7 +1293,7 @@ import { useState as useState5, useEffect as useEffect6 } from "react";
1293
1293
  import { Typography as Typography4, TextField as TextField4, Button as Button4, Box as Box4, CircularProgress as CircularProgress4, Alert as Alert4, Link as Link4 } from "@mui/material";
1294
1294
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1295
1295
  var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
1296
- const { crudify: crudify7 } = useCrudify();
1296
+ const { crudify: crudify6 } = useCrudify();
1297
1297
  const [code, setCode] = useState5("");
1298
1298
  const [loading, setLoading] = useState5(false);
1299
1299
  const [errors, setErrors] = useState5([]);
@@ -1332,7 +1332,7 @@ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
1332
1332
  }
1333
1333
  }, [searchParams, onScreenChange]);
1334
1334
  const handleSubmit = async () => {
1335
- if (loading || !crudify7) return;
1335
+ if (loading || !crudify6) return;
1336
1336
  setErrors([]);
1337
1337
  setHelperTextCode(null);
1338
1338
  if (!code) {
@@ -1351,7 +1351,7 @@ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
1351
1351
  data: { email, codePassword: code }
1352
1352
  }
1353
1353
  ];
1354
- const response = await crudify7.transaction(data);
1354
+ const response = await crudify6.transaction(data);
1355
1355
  if (response.success) {
1356
1356
  onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
1357
1357
  } else {
@@ -1474,1868 +1474,1881 @@ var CrudifyInitializer = ({ children, fallback }) => {
1474
1474
  return /* @__PURE__ */ jsx8(Fragment5, { children });
1475
1475
  };
1476
1476
 
1477
- // src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
1478
- import { useMemo as useMemo2 } from "react";
1479
- import crudify2 from "@nocios/crudify-browser";
1480
- var useCrudifyLogin = (config, _options = {}) => {
1481
- console.log("\u{1F50D} useCrudifyLogin - Input config:", config);
1482
- const finalConfig = useMemo2(() => {
1483
- const publicApiKey = config.publicApiKey || crudify2?.publicApiKey || crudify2?.apiKey || getCookie("publicApiKey") || null;
1484
- let detectedEnv = "prod";
1485
- if (config.env) {
1486
- detectedEnv = config.env;
1487
- } else if (getCookie("environment")) {
1488
- detectedEnv = getCookie("environment") || "prod";
1489
- } else if (typeof process !== "undefined" && process.env && process.env.NODE_ENV === "development") {
1490
- detectedEnv = "dev";
1491
- }
1492
- const rawEnv = detectedEnv;
1493
- const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
1494
- const appName = config.appName || getCookie("appName") || "Crudia";
1495
- const loginActions = config.loginActions || (() => {
1496
- try {
1497
- const cookieValue = getCookie("loginActions");
1498
- return cookieValue ? cookieValue.split(",").map((action) => action.trim()).filter(Boolean) : [];
1499
- } catch {
1500
- return [];
1501
- }
1502
- })();
1503
- console.log("\u{1F50D} useCrudifyLogin - Resolved publicApiKey:", publicApiKey);
1504
- console.log(
1505
- "\u{1F50D} useCrudifyLogin - Sources - props:",
1506
- config.publicApiKey,
1507
- "crudify:",
1508
- crudify2?.publicApiKey,
1509
- "cookie:",
1510
- getCookie("publicApiKey")
1511
- );
1512
- console.log("\u{1F50D} useCrudifyLogin - Environment detection:");
1513
- console.log(" - config.env:", config.env);
1514
- console.log(" - cookie environment:", getCookie("environment"));
1515
- console.log(" - NODE_ENV:", typeof process !== "undefined" ? process.env?.NODE_ENV : "undefined");
1516
- console.log(" - detectedEnv:", detectedEnv);
1517
- console.log(" - final env:", env);
1518
- const finalResult = {
1519
- publicApiKey,
1520
- env,
1521
- appName,
1522
- loginActions
1523
- };
1524
- console.log("\u{1F50D} useCrudifyLogin - Final config result:", finalResult);
1525
- return finalResult;
1526
- }, [config]);
1527
- return { config: finalConfig };
1528
- };
1529
-
1530
- // src/components/CrudifyLogin/index.tsx
1531
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1532
- var CrudifyLoginInternal = ({
1533
- onScreenChange,
1534
- onExternalNavigate,
1535
- onLoginSuccess,
1536
- onError,
1537
- redirectUrl = "/"
1538
- }) => {
1539
- const { t } = useTranslation();
1540
- const { state, setScreen } = useLoginState();
1541
- const handleScreenChange = (screen2, params) => {
1542
- let finalParams = params;
1543
- if (screen2 === "login") {
1544
- finalParams = {};
1545
- } else if (screen2 === "forgotPassword" && !params) {
1546
- finalParams = {};
1547
- }
1548
- setScreen(screen2, finalParams);
1549
- onScreenChange?.(screen2, finalParams);
1550
- };
1551
- const renderCurrentForm = () => {
1552
- const commonProps = {
1553
- onScreenChange: handleScreenChange,
1554
- onExternalNavigate,
1555
- onError,
1556
- redirectUrl
1557
- };
1558
- switch (state.currentScreen) {
1559
- case "forgotPassword":
1560
- return /* @__PURE__ */ jsx9(ForgotPasswordForm_default, { ...commonProps });
1561
- case "checkCode":
1562
- return /* @__PURE__ */ jsx9(CheckCodeForm_default, { ...commonProps, searchParams: state.searchParams });
1563
- case "resetPassword":
1564
- return /* @__PURE__ */ jsx9(
1565
- ResetPasswordForm_default,
1566
- {
1567
- ...commonProps,
1568
- searchParams: state.searchParams,
1569
- onResetSuccess: () => {
1570
- handleScreenChange("login");
1571
- }
1572
- }
1573
- );
1574
- default:
1575
- return /* @__PURE__ */ jsx9(LoginForm_default, { ...commonProps, onLoginSuccess });
1576
- }
1577
- };
1578
- return /* @__PURE__ */ jsxs6(CrudifyInitializer, { children: [
1579
- /* @__PURE__ */ jsx9(Box6, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ jsx9(
1580
- "img",
1581
- {
1582
- src: state.config.logo || "/nocios-default.png",
1583
- alt: t("login.logoAlt"),
1584
- style: {
1585
- width: "100%",
1586
- maxWidth: "150px",
1587
- height: "auto"
1588
- },
1589
- onError: (e) => {
1590
- const target = e.target;
1591
- target.src = "/nocios-default.png";
1592
- }
1593
- }
1594
- ) }),
1595
- state.config.appName && /* @__PURE__ */ jsx9(
1596
- Typography6,
1597
- {
1598
- variant: "h6",
1599
- component: "h1",
1600
- sx: {
1601
- textAlign: "center",
1602
- mb: 2,
1603
- color: state.config.colors?.primaryColor || "#1066BA"
1604
- },
1605
- children: state.config.appName
1606
- }
1607
- ),
1608
- renderCurrentForm()
1609
- ] });
1610
- };
1611
- var CrudifyLogin = ({
1612
- translations,
1613
- translationsUrl,
1614
- language = "en",
1615
- config = {},
1616
- initialScreen = "login",
1617
- autoReadFromCookies = true,
1618
- ...props
1619
- }) => {
1620
- const { config: finalConfig } = useCrudifyLogin(config);
1621
- return /* @__PURE__ */ jsx9(I18nProvider, { translations, translationsUrl, language, children: /* @__PURE__ */ jsx9(CrudifyProvider, { config: finalConfig, children: /* @__PURE__ */ jsx9(LoginStateProvider, { config, initialScreen, autoReadFromCookies, children: /* @__PURE__ */ jsx9(CrudifyLoginInternal, { config, ...props }) }) }) });
1622
- };
1623
- var CrudifyLogin_default = CrudifyLogin;
1477
+ // src/providers/SessionProvider.tsx
1478
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo2 } from "react";
1624
1479
 
1625
- // src/components/UserProfile/UserProfileDisplay.tsx
1626
- import {
1627
- Box as Box7,
1628
- Card,
1629
- CardContent,
1630
- Typography as Typography7,
1631
- Chip,
1632
- Avatar,
1633
- Divider,
1634
- CircularProgress as CircularProgress6,
1635
- Alert as Alert6,
1636
- List,
1637
- ListItem,
1638
- ListItemText,
1639
- ListItemIcon,
1640
- Collapse,
1641
- IconButton
1642
- } from "@mui/material";
1643
- import {
1644
- Person,
1645
- Email,
1646
- Badge,
1647
- Security,
1648
- Schedule,
1649
- AccountCircle,
1650
- ExpandMore,
1651
- ExpandLess,
1652
- Info
1653
- } from "@mui/icons-material";
1480
+ // src/hooks/useSession.ts
1481
+ import { useState as useState6, useEffect as useEffect7, useCallback } from "react";
1654
1482
 
1655
- // src/hooks/useUserProfile.ts
1656
- import { useState as useState6, useEffect as useEffect7, useCallback, useRef as useRef2 } from "react";
1657
- import crudify3 from "@nocios/crudify-browser";
1483
+ // src/core/SessionManager.ts
1484
+ import crudify2 from "@nocios/crudify-browser";
1658
1485
 
1659
- // src/utils/jwtUtils.ts
1660
- var decodeJwtSafely = (token) => {
1661
- try {
1662
- const parts = token.split(".");
1663
- if (parts.length !== 3) {
1664
- console.warn("Invalid JWT format: token must have 3 parts");
1665
- return null;
1666
- }
1667
- const payload = parts[1];
1668
- const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
1669
- const decodedPayload = JSON.parse(atob(paddedPayload));
1670
- return decodedPayload;
1671
- } catch (error) {
1672
- console.warn("Failed to decode JWT token:", error);
1673
- return null;
1486
+ // src/utils/tokenStorage.ts
1487
+ import CryptoJS from "crypto-js";
1488
+ var _TokenStorage = class _TokenStorage {
1489
+ /**
1490
+ * Configurar tipo de almacenamiento
1491
+ */
1492
+ static setStorageType(type) {
1493
+ _TokenStorage.storageType = type;
1674
1494
  }
1675
- };
1676
- var getCurrentUserEmail = () => {
1677
- try {
1678
- let token = null;
1679
- token = sessionStorage.getItem("authToken");
1680
- console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
1681
- if (!token) {
1682
- token = sessionStorage.getItem("token");
1683
- console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
1684
- }
1685
- if (!token) {
1686
- token = localStorage.getItem("authToken") || localStorage.getItem("token");
1687
- console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
1688
- }
1689
- if (!token) {
1690
- console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
1691
- return null;
1495
+ /**
1496
+ * Verificar si el storage está disponible
1497
+ */
1498
+ static isStorageAvailable(type) {
1499
+ try {
1500
+ const storage = window[type];
1501
+ const testKey = "__storage_test__";
1502
+ storage.setItem(testKey, "test");
1503
+ storage.removeItem(testKey);
1504
+ return true;
1505
+ } catch {
1506
+ return false;
1692
1507
  }
1693
- const payload = decodeJwtSafely(token);
1694
- if (!payload) {
1695
- console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
1508
+ }
1509
+ /**
1510
+ * Obtener instancia de storage
1511
+ */
1512
+ static getStorage() {
1513
+ if (_TokenStorage.storageType === "none") return null;
1514
+ if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
1515
+ console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
1696
1516
  return null;
1697
1517
  }
1698
- const email = payload.email || payload["cognito:username"] || null;
1699
- console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
1700
- return email;
1701
- } catch (error) {
1702
- console.warn("Failed to get current user email:", error);
1703
- return null;
1704
- }
1705
- };
1706
- var isTokenExpired = (token) => {
1707
- try {
1708
- const payload = decodeJwtSafely(token);
1709
- if (!payload || !payload.exp) return true;
1710
- const currentTime = Math.floor(Date.now() / 1e3);
1711
- return payload.exp < currentTime;
1712
- } catch {
1713
- return true;
1518
+ return window[_TokenStorage.storageType];
1714
1519
  }
1715
- };
1716
-
1717
- // src/hooks/useUserProfile.ts
1718
- var useUserProfile = (options = {}) => {
1719
- const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
1720
- const [userProfile, setUserProfile] = useState6(null);
1721
- const [loading, setLoading] = useState6(false);
1722
- const [error, setError] = useState6(null);
1723
- const [extendedData, setExtendedData] = useState6({});
1724
- const abortControllerRef = useRef2(null);
1725
- const mountedRef = useRef2(true);
1726
- const requestIdRef = useRef2(0);
1727
- const retryCountRef = useRef2(0);
1728
- const clearProfile = useCallback(() => {
1729
- setUserProfile(null);
1730
- setError(null);
1731
- setLoading(false);
1732
- setExtendedData({});
1733
- }, []);
1734
- const refreshProfile = useCallback(async () => {
1735
- const userEmail = getCurrentUserEmail();
1736
- if (!userEmail) {
1737
- if (mountedRef.current) {
1738
- setError("No user email available");
1739
- setLoading(false);
1740
- }
1741
- return;
1742
- }
1743
- if (abortControllerRef.current) {
1744
- abortControllerRef.current.abort();
1520
+ /**
1521
+ * Encriptar datos sensibles
1522
+ */
1523
+ static encrypt(data) {
1524
+ try {
1525
+ return CryptoJS.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
1526
+ } catch (error) {
1527
+ console.error("Crudify: Encryption failed", error);
1528
+ return data;
1745
1529
  }
1746
- const abortController = new AbortController();
1747
- abortControllerRef.current = abortController;
1748
- const currentRequestId = ++requestIdRef.current;
1530
+ }
1531
+ /**
1532
+ * Desencriptar datos
1533
+ */
1534
+ static decrypt(encryptedData) {
1749
1535
  try {
1750
- if (mountedRef.current) {
1751
- setLoading(true);
1752
- setError(null);
1753
- }
1754
- const response = await crudify3.readItems("users", {
1755
- filter: { email: userEmail },
1756
- pagination: { limit: 1 }
1757
- });
1758
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
1759
- if (response.success && response.data && response.data.length > 0) {
1760
- const userData = response.data[0];
1761
- setUserProfile(userData);
1762
- const additionalData = {
1763
- fullProfile: userData,
1764
- totalFields: Object.keys(userData).length,
1765
- displayData: {
1766
- id: userData.id,
1767
- email: userData.email,
1768
- username: userData.username,
1769
- firstName: userData.firstName,
1770
- lastName: userData.lastName,
1771
- fullName: userData.fullName || `${userData.firstName || ""} ${userData.lastName || ""}`.trim(),
1772
- role: userData.role,
1773
- permissions: userData.permissions || [],
1774
- isActive: userData.isActive,
1775
- lastLogin: userData.lastLogin,
1776
- createdAt: userData.createdAt,
1777
- updatedAt: userData.updatedAt,
1778
- // Include any custom fields
1779
- ...Object.keys(userData).filter(
1780
- (key) => ![
1781
- "id",
1782
- "email",
1783
- "username",
1784
- "firstName",
1785
- "lastName",
1786
- "fullName",
1787
- "role",
1788
- "permissions",
1789
- "isActive",
1790
- "lastLogin",
1791
- "createdAt",
1792
- "updatedAt"
1793
- ].includes(key)
1794
- ).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
1795
- }
1796
- };
1797
- setExtendedData(additionalData);
1798
- setError(null);
1799
- retryCountRef.current = 0;
1800
- } else {
1801
- setError("User profile not found");
1802
- setUserProfile(null);
1803
- setExtendedData({});
1804
- }
1805
- }
1806
- } catch (err) {
1807
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
1808
- const error2 = err;
1809
- if (error2.name === "AbortError") {
1810
- return;
1811
- }
1812
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
1813
- if (shouldRetry) {
1814
- retryCountRef.current++;
1815
- setTimeout(() => {
1816
- if (mountedRef.current) {
1817
- refreshProfile();
1818
- }
1819
- }, 1e3 * retryCountRef.current);
1820
- } else {
1821
- setError("Failed to load user profile");
1822
- setUserProfile(null);
1823
- setExtendedData({});
1824
- }
1825
- }
1826
- } finally {
1827
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
1828
- setLoading(false);
1536
+ const bytes = CryptoJS.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
1537
+ const decrypted = bytes.toString(CryptoJS.enc.Utf8);
1538
+ return decrypted || encryptedData;
1539
+ } catch (error) {
1540
+ console.error("Crudify: Decryption failed", error);
1541
+ return encryptedData;
1542
+ }
1543
+ }
1544
+ /**
1545
+ * Guardar tokens de forma segura
1546
+ */
1547
+ static saveTokens(tokens) {
1548
+ const storage = _TokenStorage.getStorage();
1549
+ if (!storage) return;
1550
+ try {
1551
+ const tokenData = {
1552
+ accessToken: tokens.accessToken,
1553
+ refreshToken: tokens.refreshToken,
1554
+ expiresAt: tokens.expiresAt,
1555
+ refreshExpiresAt: tokens.refreshExpiresAt,
1556
+ savedAt: Date.now()
1557
+ };
1558
+ const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
1559
+ storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
1560
+ console.debug("Crudify: Tokens saved successfully");
1561
+ } catch (error) {
1562
+ console.error("Crudify: Failed to save tokens", error);
1563
+ }
1564
+ }
1565
+ /**
1566
+ * Obtener tokens guardados
1567
+ */
1568
+ static getTokens() {
1569
+ const storage = _TokenStorage.getStorage();
1570
+ if (!storage) return null;
1571
+ try {
1572
+ const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
1573
+ if (!encrypted) return null;
1574
+ const decrypted = _TokenStorage.decrypt(encrypted);
1575
+ const tokenData = JSON.parse(decrypted);
1576
+ if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
1577
+ console.warn("Crudify: Incomplete token data found, clearing storage");
1578
+ _TokenStorage.clearTokens();
1579
+ return null;
1829
1580
  }
1830
- if (abortControllerRef.current === abortController) {
1831
- abortControllerRef.current = null;
1581
+ if (Date.now() >= tokenData.refreshExpiresAt) {
1582
+ console.info("Crudify: Refresh token expired, clearing storage");
1583
+ _TokenStorage.clearTokens();
1584
+ return null;
1832
1585
  }
1586
+ return {
1587
+ accessToken: tokenData.accessToken,
1588
+ refreshToken: tokenData.refreshToken,
1589
+ expiresAt: tokenData.expiresAt,
1590
+ refreshExpiresAt: tokenData.refreshExpiresAt
1591
+ };
1592
+ } catch (error) {
1593
+ console.error("Crudify: Failed to retrieve tokens", error);
1594
+ _TokenStorage.clearTokens();
1595
+ return null;
1833
1596
  }
1834
- }, [retryOnError, maxRetries]);
1835
- useEffect7(() => {
1836
- if (autoFetch) {
1837
- refreshProfile();
1597
+ }
1598
+ /**
1599
+ * Limpiar tokens almacenados
1600
+ */
1601
+ static clearTokens() {
1602
+ const storage = _TokenStorage.getStorage();
1603
+ if (!storage) return;
1604
+ try {
1605
+ storage.removeItem(_TokenStorage.TOKEN_KEY);
1606
+ console.debug("Crudify: Tokens cleared from storage");
1607
+ } catch (error) {
1608
+ console.error("Crudify: Failed to clear tokens", error);
1838
1609
  }
1839
- }, [autoFetch, refreshProfile]);
1840
- useEffect7(() => {
1841
- mountedRef.current = true;
1842
- return () => {
1843
- mountedRef.current = false;
1844
- if (abortControllerRef.current) {
1845
- abortControllerRef.current.abort();
1846
- abortControllerRef.current = null;
1847
- }
1610
+ }
1611
+ /**
1612
+ * Verificar si hay tokens válidos guardados
1613
+ */
1614
+ static hasValidTokens() {
1615
+ const tokens = _TokenStorage.getTokens();
1616
+ return tokens !== null;
1617
+ }
1618
+ /**
1619
+ * Obtener información de expiración
1620
+ */
1621
+ static getExpirationInfo() {
1622
+ const tokens = _TokenStorage.getTokens();
1623
+ if (!tokens) return null;
1624
+ const now = Date.now();
1625
+ return {
1626
+ accessExpired: now >= tokens.expiresAt,
1627
+ refreshExpired: now >= tokens.refreshExpiresAt,
1628
+ accessExpiresIn: Math.max(0, tokens.expiresAt - now),
1629
+ refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
1848
1630
  };
1849
- }, []);
1850
- return {
1851
- userProfile,
1852
- loading,
1853
- error,
1854
- extendedData,
1855
- refreshProfile,
1856
- clearProfile
1857
- };
1858
- };
1859
-
1860
- // src/components/UserProfile/UserProfileDisplay.tsx
1861
- import { useState as useState7 } from "react";
1862
- import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1863
- var UserProfileDisplay = ({
1864
- showExtendedData = true,
1865
- showProfileCard = true,
1866
- autoRefresh = true
1867
- }) => {
1868
- const { userProfile, loading, error, extendedData, refreshProfile } = useUserProfile({
1869
- autoFetch: autoRefresh,
1870
- retryOnError: true,
1871
- maxRetries: 3
1872
- });
1873
- const [showAllFields, setShowAllFields] = useState7(false);
1874
- if (loading) {
1875
- return /* @__PURE__ */ jsxs7(Box7, { display: "flex", justifyContent: "center", alignItems: "center", p: 3, children: [
1876
- /* @__PURE__ */ jsx10(CircularProgress6, {}),
1877
- /* @__PURE__ */ jsx10(Typography7, { variant: "body2", sx: { ml: 2 }, children: "Cargando perfil de usuario..." })
1878
- ] });
1879
1631
  }
1880
- if (error) {
1881
- return /* @__PURE__ */ jsxs7(
1882
- Alert6,
1883
- {
1884
- severity: "error",
1885
- action: /* @__PURE__ */ jsx10(IconButton, { color: "inherit", size: "small", onClick: refreshProfile, children: /* @__PURE__ */ jsx10(Typography7, { variant: "caption", children: "Reintentar" }) }),
1886
- children: [
1887
- "Error al cargar el perfil: ",
1888
- error
1889
- ]
1890
- }
1891
- );
1632
+ /**
1633
+ * Actualizar solo el access token (después de refresh)
1634
+ */
1635
+ static updateAccessToken(newAccessToken, newExpiresAt) {
1636
+ const existingTokens = _TokenStorage.getTokens();
1637
+ if (!existingTokens) {
1638
+ console.warn("Crudify: Cannot update access token, no existing tokens found");
1639
+ return;
1640
+ }
1641
+ _TokenStorage.saveTokens({
1642
+ ...existingTokens,
1643
+ accessToken: newAccessToken,
1644
+ expiresAt: newExpiresAt
1645
+ });
1892
1646
  }
1893
- if (!userProfile) {
1894
- return /* @__PURE__ */ jsx10(Alert6, { severity: "warning", children: "No se encontr\xF3 informaci\xF3n del usuario" });
1647
+ };
1648
+ _TokenStorage.TOKEN_KEY = "crudify_tokens";
1649
+ _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
1650
+ _TokenStorage.storageType = "localStorage";
1651
+ var TokenStorage = _TokenStorage;
1652
+
1653
+ // src/core/SessionManager.ts
1654
+ var SessionManager = class _SessionManager {
1655
+ constructor() {
1656
+ this.config = {};
1657
+ this.initialized = false;
1895
1658
  }
1896
- const displayData = extendedData?.displayData || {};
1897
- const totalFields = extendedData?.totalFields || 0;
1898
- const formatDate = (dateString) => {
1899
- if (!dateString) return "No disponible";
1900
- try {
1901
- return new Date(dateString).toLocaleString("es-ES", {
1902
- year: "numeric",
1903
- month: "short",
1904
- day: "numeric",
1905
- hour: "2-digit",
1906
- minute: "2-digit"
1907
- });
1908
- } catch {
1909
- return dateString;
1659
+ static getInstance() {
1660
+ if (!_SessionManager.instance) {
1661
+ _SessionManager.instance = new _SessionManager();
1910
1662
  }
1911
- };
1912
- const renderFieldValue = (key, value) => {
1913
- if (value === null || value === void 0) return "No disponible";
1914
- if (typeof value === "boolean") return value ? "S\xED" : "No";
1915
- if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "Ninguno";
1916
- if (typeof value === "object") return JSON.stringify(value, null, 2);
1917
- return String(value);
1918
- };
1919
- const basicFields = [
1920
- { key: "id", label: "ID", icon: /* @__PURE__ */ jsx10(Badge, {}) },
1921
- { key: "email", label: "Email", icon: /* @__PURE__ */ jsx10(Email, {}) },
1922
- { key: "username", label: "Usuario", icon: /* @__PURE__ */ jsx10(Person, {}) },
1923
- { key: "fullName", label: "Nombre completo", icon: /* @__PURE__ */ jsx10(AccountCircle, {}) },
1924
- { key: "role", label: "Rol", icon: /* @__PURE__ */ jsx10(Security, {}) }
1925
- ];
1926
- const extendedFields = [
1927
- { key: "firstName", label: "Nombre" },
1928
- { key: "lastName", label: "Apellido" },
1929
- { key: "isActive", label: "Activo" },
1930
- { key: "lastLogin", label: "\xDAltimo login" },
1931
- { key: "createdAt", label: "Creado" },
1932
- { key: "updatedAt", label: "Actualizado" }
1933
- ];
1934
- const knownFields = [...basicFields.map((f) => f.key), ...extendedFields.map((f) => f.key), "permissions"];
1935
- const customFields = Object.keys(displayData).filter((key) => !knownFields.includes(key)).map((key) => ({ key, label: key }));
1936
- return /* @__PURE__ */ jsxs7(Box7, { children: [
1937
- showProfileCard && /* @__PURE__ */ jsx10(Card, { sx: { mb: 2 }, children: /* @__PURE__ */ jsxs7(CardContent, { children: [
1938
- /* @__PURE__ */ jsxs7(Box7, { display: "flex", alignItems: "center", mb: 2, children: [
1939
- /* @__PURE__ */ jsx10(
1940
- Avatar,
1941
- {
1942
- src: displayData.avatar,
1943
- sx: { width: 56, height: 56, mr: 2 },
1944
- children: displayData.fullName?.[0] || displayData.username?.[0] || displayData.email?.[0]
1663
+ return _SessionManager.instance;
1664
+ }
1665
+ /**
1666
+ * Inicializar el SessionManager
1667
+ */
1668
+ async initialize(config = {}) {
1669
+ if (this.initialized) {
1670
+ console.warn("SessionManager: Already initialized");
1671
+ return;
1672
+ }
1673
+ this.config = {
1674
+ storageType: "localStorage",
1675
+ autoRestore: true,
1676
+ enableLogging: false,
1677
+ ...config
1678
+ };
1679
+ TokenStorage.setStorageType(this.config.storageType || "localStorage");
1680
+ if (this.config.enableLogging) {
1681
+ }
1682
+ if (this.config.autoRestore) {
1683
+ await this.restoreSession();
1684
+ }
1685
+ this.initialized = true;
1686
+ this.log("SessionManager initialized successfully");
1687
+ }
1688
+ /**
1689
+ * Login con persistencia automática
1690
+ */
1691
+ async login(email, password) {
1692
+ try {
1693
+ this.log("Attempting login...");
1694
+ const response = await crudify2.login(email, password);
1695
+ if (!response.success) {
1696
+ this.log("Login failed:", response.errors);
1697
+ return {
1698
+ success: false,
1699
+ error: this.formatError(response.errors)
1700
+ };
1701
+ }
1702
+ const tokens = {
1703
+ accessToken: response.data.token,
1704
+ refreshToken: response.data.refreshToken,
1705
+ expiresAt: response.data.expiresAt,
1706
+ refreshExpiresAt: response.data.refreshExpiresAt
1707
+ };
1708
+ TokenStorage.saveTokens(tokens);
1709
+ this.log("Login successful, tokens saved");
1710
+ this.config.onLoginSuccess?.(tokens);
1711
+ return {
1712
+ success: true,
1713
+ tokens
1714
+ };
1715
+ } catch (error) {
1716
+ this.log("Login error:", error);
1717
+ return {
1718
+ success: false,
1719
+ error: error instanceof Error ? error.message : "Unknown error"
1720
+ };
1721
+ }
1722
+ }
1723
+ /**
1724
+ * Logout con limpieza de tokens
1725
+ */
1726
+ async logout() {
1727
+ try {
1728
+ this.log("Logging out...");
1729
+ await crudify2.logout();
1730
+ TokenStorage.clearTokens();
1731
+ this.log("Logout successful");
1732
+ this.config.onLogout?.();
1733
+ } catch (error) {
1734
+ this.log("Logout error:", error);
1735
+ TokenStorage.clearTokens();
1736
+ }
1737
+ }
1738
+ /**
1739
+ * Restaurar sesión desde storage
1740
+ */
1741
+ async restoreSession() {
1742
+ try {
1743
+ this.log("Attempting to restore session...");
1744
+ const savedTokens = TokenStorage.getTokens();
1745
+ if (!savedTokens) {
1746
+ this.log("No valid tokens found in storage");
1747
+ return false;
1748
+ }
1749
+ crudify2.setTokens({
1750
+ accessToken: savedTokens.accessToken,
1751
+ refreshToken: savedTokens.refreshToken,
1752
+ expiresAt: savedTokens.expiresAt,
1753
+ refreshExpiresAt: savedTokens.refreshExpiresAt
1754
+ });
1755
+ this.log("Session restored successfully");
1756
+ this.config.onSessionRestored?.(savedTokens);
1757
+ return true;
1758
+ } catch (error) {
1759
+ this.log("Session restore error:", error);
1760
+ TokenStorage.clearTokens();
1761
+ return false;
1762
+ }
1763
+ }
1764
+ /**
1765
+ * Verificar si el usuario está autenticado
1766
+ */
1767
+ isAuthenticated() {
1768
+ return crudify2.isLogin() || TokenStorage.hasValidTokens();
1769
+ }
1770
+ /**
1771
+ * Obtener información de tokens actuales
1772
+ */
1773
+ getTokenInfo() {
1774
+ const crudifyTokens = crudify2.getTokenData();
1775
+ const storageInfo = TokenStorage.getExpirationInfo();
1776
+ return {
1777
+ isLoggedIn: this.isAuthenticated(),
1778
+ crudifyTokens,
1779
+ storageInfo,
1780
+ hasValidTokens: TokenStorage.hasValidTokens()
1781
+ };
1782
+ }
1783
+ /**
1784
+ * Refrescar tokens manualmente
1785
+ */
1786
+ async refreshTokens() {
1787
+ try {
1788
+ this.log("Manually refreshing tokens...");
1789
+ const response = await crudify2.refreshAccessToken();
1790
+ if (!response.success) {
1791
+ this.log("Token refresh failed:", response.errors);
1792
+ TokenStorage.clearTokens();
1793
+ this.config.onSessionExpired?.();
1794
+ return false;
1795
+ }
1796
+ const newTokens = {
1797
+ accessToken: response.data.token,
1798
+ refreshToken: response.data.refreshToken,
1799
+ expiresAt: response.data.expiresAt,
1800
+ refreshExpiresAt: response.data.refreshExpiresAt
1801
+ };
1802
+ TokenStorage.saveTokens(newTokens);
1803
+ this.log("Tokens refreshed and saved successfully");
1804
+ return true;
1805
+ } catch (error) {
1806
+ this.log("Token refresh error:", error);
1807
+ TokenStorage.clearTokens();
1808
+ this.config.onSessionExpired?.();
1809
+ return false;
1810
+ }
1811
+ }
1812
+ /**
1813
+ * Configurar interceptor de respuesta para manejo automático de errores
1814
+ */
1815
+ setupResponseInterceptor() {
1816
+ crudify2.setResponseInterceptor(async (response) => {
1817
+ if (response.errors) {
1818
+ const hasAuthError = response.errors.some(
1819
+ (error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
1820
+ );
1821
+ if (hasAuthError && TokenStorage.hasValidTokens()) {
1822
+ this.log("Auth error detected, attempting token refresh...");
1823
+ const refreshSuccess = await this.refreshTokens();
1824
+ if (!refreshSuccess) {
1825
+ this.log("Session expired, triggering callback");
1826
+ this.config.onSessionExpired?.();
1945
1827
  }
1946
- ),
1947
- /* @__PURE__ */ jsxs7(Box7, { children: [
1948
- /* @__PURE__ */ jsx10(Typography7, { variant: "h6", children: displayData.fullName || displayData.username || displayData.email }),
1949
- /* @__PURE__ */ jsx10(Typography7, { variant: "body2", color: "text.secondary", children: displayData.role || "Usuario" }),
1950
- displayData.isActive !== void 0 && /* @__PURE__ */ jsx10(
1951
- Chip,
1952
- {
1953
- label: displayData.isActive ? "Activo" : "Inactivo",
1954
- color: displayData.isActive ? "success" : "error",
1955
- size: "small",
1956
- sx: { mt: 0.5 }
1957
- }
1958
- )
1959
- ] })
1960
- ] }),
1961
- /* @__PURE__ */ jsx10(Box7, { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: 2, children: basicFields.map(
1962
- ({ key, label, icon }) => displayData[key] ? /* @__PURE__ */ jsxs7(Box7, { display: "flex", alignItems: "center", children: [
1963
- /* @__PURE__ */ jsx10(Box7, { sx: { mr: 1, color: "text.secondary" }, children: icon }),
1964
- /* @__PURE__ */ jsxs7(Box7, { children: [
1965
- /* @__PURE__ */ jsx10(Typography7, { variant: "caption", color: "text.secondary", children: label }),
1966
- /* @__PURE__ */ jsx10(Typography7, { variant: "body2", children: renderFieldValue(key, displayData[key]) })
1967
- ] })
1968
- ] }, key) : null
1969
- ) }),
1970
- displayData.permissions && Array.isArray(displayData.permissions) && displayData.permissions.length > 0 && /* @__PURE__ */ jsxs7(Box7, { mt: 2, children: [
1971
- /* @__PURE__ */ jsx10(Typography7, { variant: "caption", color: "text.secondary", display: "block", children: "Permisos" }),
1972
- /* @__PURE__ */ jsxs7(Box7, { display: "flex", flexWrap: "wrap", gap: 0.5, mt: 0.5, children: [
1973
- displayData.permissions.slice(0, 5).map((permission, index) => /* @__PURE__ */ jsx10(Chip, { label: permission, size: "small", variant: "outlined" }, index)),
1974
- displayData.permissions.length > 5 && /* @__PURE__ */ jsx10(Chip, { label: `+${displayData.permissions.length - 5} m\xE1s`, size: "small" })
1975
- ] })
1976
- ] })
1977
- ] }) }),
1978
- showExtendedData && /* @__PURE__ */ jsx10(Card, { children: /* @__PURE__ */ jsxs7(CardContent, { children: [
1979
- /* @__PURE__ */ jsxs7(Box7, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2, children: [
1980
- /* @__PURE__ */ jsxs7(Typography7, { variant: "h6", display: "flex", alignItems: "center", children: [
1981
- /* @__PURE__ */ jsx10(Info, { sx: { mr: 1 } }),
1982
- "Informaci\xF3n Detallada"
1983
- ] }),
1984
- /* @__PURE__ */ jsx10(Chip, { label: `${totalFields} campos totales`, size: "small" })
1985
- ] }),
1986
- /* @__PURE__ */ jsxs7(List, { dense: true, children: [
1987
- extendedFields.map(({ key, label }) => displayData[key] !== void 0 && /* @__PURE__ */ jsxs7(ListItem, { divider: true, children: [
1988
- /* @__PURE__ */ jsx10(ListItemIcon, { children: /* @__PURE__ */ jsx10(Schedule, { fontSize: "small" }) }),
1989
- /* @__PURE__ */ jsx10(
1990
- ListItemText,
1991
- {
1992
- primary: label,
1993
- secondary: key.includes("At") || key.includes("Login") ? formatDate(displayData[key]) : renderFieldValue(key, displayData[key])
1994
- }
1995
- )
1996
- ] }, key)),
1997
- customFields.length > 0 && /* @__PURE__ */ jsxs7(Fragment6, { children: [
1998
- /* @__PURE__ */ jsx10(Divider, { sx: { my: 1 } }),
1999
- /* @__PURE__ */ jsx10(ListItem, { children: /* @__PURE__ */ jsx10(
2000
- ListItemText,
2001
- {
2002
- primary: /* @__PURE__ */ jsxs7(Box7, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2003
- /* @__PURE__ */ jsxs7(Typography7, { variant: "subtitle2", children: [
2004
- "Campos Personalizados (",
2005
- customFields.length,
2006
- ")"
2007
- ] }),
2008
- /* @__PURE__ */ jsx10(IconButton, { size: "small", onClick: () => setShowAllFields(!showAllFields), children: showAllFields ? /* @__PURE__ */ jsx10(ExpandLess, {}) : /* @__PURE__ */ jsx10(ExpandMore, {}) })
2009
- ] })
2010
- }
2011
- ) }),
2012
- /* @__PURE__ */ jsx10(Collapse, { in: showAllFields, children: customFields.map(({ key, label }) => /* @__PURE__ */ jsx10(ListItem, { sx: { pl: 4 }, children: /* @__PURE__ */ jsx10(
2013
- ListItemText,
2014
- {
2015
- primary: label,
2016
- secondary: renderFieldValue(key, displayData[key])
2017
- }
2018
- ) }, key)) })
2019
- ] })
2020
- ] }),
2021
- /* @__PURE__ */ jsxs7(Box7, { mt: 2, display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2022
- /* @__PURE__ */ jsxs7(Typography7, { variant: "caption", color: "text.secondary", children: [
2023
- "\xDAltima actualizaci\xF3n: ",
2024
- formatDate(displayData.updatedAt)
2025
- ] }),
2026
- /* @__PURE__ */ jsx10(IconButton, { size: "small", onClick: refreshProfile, disabled: loading, children: /* @__PURE__ */ jsx10(Typography7, { variant: "caption", children: "Actualizar" }) })
2027
- ] })
2028
- ] }) })
2029
- ] });
1828
+ }
1829
+ }
1830
+ return response;
1831
+ });
1832
+ this.log("Response interceptor configured");
1833
+ }
1834
+ /**
1835
+ * Limpiar sesión completamente
1836
+ */
1837
+ clearSession() {
1838
+ TokenStorage.clearTokens();
1839
+ crudify2.logout();
1840
+ this.log("Session cleared completely");
1841
+ }
1842
+ // Métodos privados
1843
+ log(message, ...args) {
1844
+ if (this.config.enableLogging) {
1845
+ console.log(`[SessionManager] ${message}`, ...args);
1846
+ }
1847
+ }
1848
+ formatError(errors) {
1849
+ if (!errors) return "Unknown error";
1850
+ if (typeof errors === "string") return errors;
1851
+ if (typeof errors === "object") {
1852
+ const errorMessages = Object.values(errors).flat();
1853
+ return errorMessages.join(", ");
1854
+ }
1855
+ return "Authentication failed";
1856
+ }
2030
1857
  };
2031
- var UserProfileDisplay_default = UserProfileDisplay;
2032
1858
 
2033
- // src/components/PublicPolicies/Policies.tsx
2034
- import { useRef as useRef4 } from "react";
2035
- import { useTranslation as useTranslation4 } from "react-i18next";
2036
- import {
2037
- Box as Box10,
2038
- Typography as Typography10,
2039
- Button as Button7,
2040
- Stack as Stack3,
2041
- Alert as Alert7,
2042
- Divider as Divider3
2043
- } from "@mui/material";
2044
- import { Add } from "@mui/icons-material";
2045
-
2046
- // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
2047
- import { forwardRef } from "react";
2048
- import { useTranslation as useTranslation3 } from "react-i18next";
2049
- import {
2050
- Box as Box9,
2051
- FormControl,
2052
- InputLabel,
2053
- Select,
2054
- MenuItem,
2055
- IconButton as IconButton2,
2056
- Typography as Typography9,
2057
- FormHelperText as FormHelperText2,
2058
- Stack as Stack2,
2059
- Paper,
2060
- Divider as Divider2,
2061
- Button as Button6
2062
- } from "@mui/material";
2063
- import { Delete, SelectAll as SelectAll2, ClearAll as ClearAll2 } from "@mui/icons-material";
2064
-
2065
- // src/components/PublicPolicies/FieldSelector/FieldSelector.tsx
2066
- import { useState as useState8, useEffect as useEffect8, useRef as useRef3 } from "react";
2067
- import { useTranslation as useTranslation2 } from "react-i18next";
2068
- import {
2069
- Box as Box8,
2070
- Typography as Typography8,
2071
- Button as Button5,
2072
- Stack,
2073
- FormHelperText,
2074
- ToggleButton,
2075
- ToggleButtonGroup
2076
- } from "@mui/material";
2077
- import {
2078
- CheckCircle,
2079
- Cancel,
2080
- SelectAll,
2081
- ClearAll
2082
- } from "@mui/icons-material";
2083
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2084
- var FieldSelector = ({
2085
- value,
2086
- onChange,
2087
- availableFields,
2088
- error,
2089
- disabled = false
2090
- }) => {
2091
- const { t } = useTranslation2();
2092
- const [mode, setMode] = useState8("custom");
2093
- const isUpdatingRef = useRef3(false);
2094
- useEffect8(() => {
2095
- const current = value || { allow: [], owner_allow: [], deny: [] };
2096
- const all = new Set(availableFields);
2097
- const allow = (current.allow || []).filter((f) => all.has(f));
2098
- const owner = (current.owner_allow || []).filter((f) => all.has(f));
2099
- const deny = (current.deny || []).filter((f) => all.has(f));
2100
- availableFields.forEach((f) => {
2101
- if (!allow.includes(f) && !owner.includes(f) && !deny.includes(f)) deny.push(f);
2102
- });
2103
- const normalized = { allow, owner_allow: owner, deny };
2104
- if (JSON.stringify(normalized) !== JSON.stringify(current)) {
2105
- onChange(normalized);
2106
- }
2107
- if (allow.length === availableFields.length) setMode("all");
2108
- else if (deny.length === availableFields.length) setMode("none");
2109
- else setMode("custom");
2110
- }, [availableFields, value]);
2111
- const setAllAllow = () => {
2112
- isUpdatingRef.current = true;
2113
- onChange({ allow: [...availableFields], owner_allow: [], deny: [] });
2114
- setMode("all");
2115
- setTimeout(() => {
2116
- isUpdatingRef.current = false;
2117
- }, 0);
2118
- };
2119
- const setAllDeny = () => {
2120
- isUpdatingRef.current = true;
2121
- onChange({ allow: [], owner_allow: [], deny: [...availableFields] });
2122
- setMode("none");
2123
- setTimeout(() => {
2124
- isUpdatingRef.current = false;
2125
- }, 0);
2126
- };
2127
- const getFieldState = (fieldName) => {
2128
- if (value?.allow?.includes(fieldName)) return "allow";
2129
- if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
2130
- return "deny";
2131
- };
2132
- const setFieldState = (fieldName, state) => {
2133
- isUpdatingRef.current = true;
2134
- const allow = new Set(value?.allow || []);
2135
- const owner = new Set(value?.owner_allow || []);
2136
- const deny = new Set(value?.deny || []);
2137
- allow.delete(fieldName);
2138
- owner.delete(fieldName);
2139
- deny.delete(fieldName);
2140
- if (state === "allow") allow.add(fieldName);
2141
- if (state === "owner_allow") owner.add(fieldName);
2142
- if (state === "deny") deny.add(fieldName);
2143
- onChange({ allow: Array.from(allow), owner_allow: Array.from(owner), deny: Array.from(deny) });
2144
- setMode("custom");
2145
- setTimeout(() => {
2146
- isUpdatingRef.current = false;
2147
- }, 0);
2148
- };
2149
- if (availableFields.length === 0) {
2150
- return /* @__PURE__ */ jsxs8(Box8, { children: [
2151
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
2152
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: t("modules.form.publicPolicies.fields.conditions.noFieldsAvailable") }),
2153
- error && /* @__PURE__ */ jsx11(FormHelperText, { error: true, sx: { mt: 1 }, children: error })
2154
- ] });
2155
- }
2156
- return /* @__PURE__ */ jsxs8(Box8, { children: [
2157
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
2158
- /* @__PURE__ */ jsxs8(Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
2159
- /* @__PURE__ */ jsx11(
2160
- Button5,
2161
- {
2162
- variant: mode === "all" ? "contained" : "outlined",
2163
- startIcon: /* @__PURE__ */ jsx11(SelectAll, {}),
2164
- onClick: setAllAllow,
2165
- disabled,
2166
- size: "small",
2167
- sx: {
2168
- minWidth: 120,
2169
- ...mode === "all" && {
2170
- backgroundColor: "#16a34a",
2171
- "&:hover": { backgroundColor: "#15803d" }
2172
- }
2173
- },
2174
- children: t("modules.form.publicPolicies.fields.conditions.allFields")
2175
- }
2176
- ),
2177
- /* @__PURE__ */ jsx11(
2178
- Button5,
2179
- {
2180
- variant: mode === "none" ? "contained" : "outlined",
2181
- startIcon: /* @__PURE__ */ jsx11(ClearAll, {}),
2182
- onClick: setAllDeny,
2183
- disabled,
2184
- size: "small",
2185
- sx: {
2186
- minWidth: 120,
2187
- ...mode === "none" && {
2188
- backgroundColor: "#cf222e",
2189
- "&:hover": { backgroundColor: "#bc1f2c" }
2190
- }
2191
- },
2192
- children: t("modules.form.publicPolicies.fields.conditions.noFields")
1859
+ // src/hooks/useSession.ts
1860
+ function useSession(options = {}) {
1861
+ const [state, setState] = useState6({
1862
+ isAuthenticated: false,
1863
+ isLoading: true,
1864
+ isInitialized: false,
1865
+ tokens: null,
1866
+ error: null
1867
+ });
1868
+ const sessionManager = SessionManager.getInstance();
1869
+ const initialize = useCallback(async () => {
1870
+ try {
1871
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
1872
+ const config = {
1873
+ autoRestore: options.autoRestore ?? true,
1874
+ enableLogging: options.enableLogging ?? false,
1875
+ onSessionExpired: () => {
1876
+ setState((prev) => ({
1877
+ ...prev,
1878
+ isAuthenticated: false,
1879
+ tokens: null,
1880
+ error: "Session expired"
1881
+ }));
1882
+ options.onSessionExpired?.();
1883
+ },
1884
+ onSessionRestored: (tokens) => {
1885
+ setState((prev) => ({
1886
+ ...prev,
1887
+ isAuthenticated: true,
1888
+ tokens,
1889
+ error: null
1890
+ }));
1891
+ options.onSessionRestored?.(tokens);
1892
+ },
1893
+ onLoginSuccess: (tokens) => {
1894
+ setState((prev) => ({
1895
+ ...prev,
1896
+ isAuthenticated: true,
1897
+ tokens,
1898
+ error: null
1899
+ }));
1900
+ },
1901
+ onLogout: () => {
1902
+ setState((prev) => ({
1903
+ ...prev,
1904
+ isAuthenticated: false,
1905
+ tokens: null,
1906
+ error: null
1907
+ }));
2193
1908
  }
2194
- )
2195
- ] }),
2196
- /* @__PURE__ */ jsxs8(Box8, { sx: { p: 2, border: "1px solid #d1d9e0", borderRadius: 1, backgroundColor: "#f6f8fa" }, children: [
2197
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.help") }),
2198
- /* @__PURE__ */ jsx11(Stack, { spacing: 1, children: availableFields.map((fieldName) => {
2199
- const fieldState = getFieldState(fieldName);
2200
- return /* @__PURE__ */ jsxs8(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
2201
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", sx: { minWidth: 100, fontFamily: "monospace" }, children: fieldName }),
2202
- /* @__PURE__ */ jsxs8(ToggleButtonGroup, { value: fieldState, exclusive: true, size: "small", children: [
2203
- /* @__PURE__ */ jsxs8(
2204
- ToggleButton,
2205
- {
2206
- value: "allow",
2207
- onClick: () => setFieldState(fieldName, "allow"),
2208
- disabled,
2209
- sx: {
2210
- px: 2,
2211
- color: fieldState === "allow" ? "#ffffff" : "#6b7280",
2212
- backgroundColor: fieldState === "allow" ? "#16a34a" : "#f3f4f6",
2213
- borderColor: fieldState === "allow" ? "#16a34a" : "#d1d5db",
2214
- "&:hover": {
2215
- backgroundColor: fieldState === "allow" ? "#15803d" : "#e5e7eb",
2216
- borderColor: fieldState === "allow" ? "#15803d" : "#9ca3af"
2217
- },
2218
- "&.Mui-selected": {
2219
- backgroundColor: "#16a34a",
2220
- color: "#ffffff",
2221
- "&:hover": {
2222
- backgroundColor: "#15803d"
2223
- }
2224
- }
2225
- },
2226
- children: [
2227
- /* @__PURE__ */ jsx11(CheckCircle, { sx: { fontSize: 16, mr: 0.5 } }),
2228
- t("modules.form.publicPolicies.fields.conditions.states.allow")
2229
- ]
2230
- }
2231
- ),
2232
- /* @__PURE__ */ jsx11(
2233
- ToggleButton,
2234
- {
2235
- value: "owner_allow",
2236
- onClick: () => setFieldState(fieldName, "owner_allow"),
2237
- disabled,
2238
- sx: {
2239
- px: 2,
2240
- color: fieldState === "owner_allow" ? "#ffffff" : "#6b7280",
2241
- backgroundColor: fieldState === "owner_allow" ? "#0ea5e9" : "#f3f4f6",
2242
- borderColor: fieldState === "owner_allow" ? "#0ea5e9" : "#d1d5db",
2243
- "&:hover": {
2244
- backgroundColor: fieldState === "owner_allow" ? "#0284c7" : "#e5e7eb",
2245
- borderColor: fieldState === "owner_allow" ? "#0284c7" : "#9ca3af"
2246
- },
2247
- "&.Mui-selected": {
2248
- backgroundColor: "#0ea5e9",
2249
- color: "#ffffff",
2250
- "&:hover": {
2251
- backgroundColor: "#0284c7"
2252
- }
2253
- }
2254
- },
2255
- children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
2256
- }
2257
- ),
2258
- /* @__PURE__ */ jsxs8(
2259
- ToggleButton,
2260
- {
2261
- value: "deny",
2262
- onClick: () => setFieldState(fieldName, "deny"),
2263
- disabled,
2264
- sx: {
2265
- px: 2,
2266
- color: fieldState === "deny" ? "#ffffff" : "#6b7280",
2267
- backgroundColor: fieldState === "deny" ? "#dc2626" : "#f3f4f6",
2268
- borderColor: fieldState === "deny" ? "#dc2626" : "#d1d5db",
2269
- "&:hover": {
2270
- backgroundColor: fieldState === "deny" ? "#b91c1c" : "#e5e7eb",
2271
- borderColor: fieldState === "deny" ? "#b91c1c" : "#9ca3af"
2272
- },
2273
- "&.Mui-selected": {
2274
- backgroundColor: "#dc2626",
2275
- color: "#ffffff",
2276
- "&:hover": {
2277
- backgroundColor: "#b91c1c"
2278
- }
2279
- }
2280
- },
2281
- children: [
2282
- /* @__PURE__ */ jsx11(Cancel, { sx: { fontSize: 16, mr: 0.5 } }),
2283
- t("modules.form.publicPolicies.fields.conditions.states.deny")
2284
- ]
2285
- }
2286
- )
2287
- ] })
2288
- ] }, fieldName);
2289
- }) })
2290
- ] }),
2291
- error && /* @__PURE__ */ jsx11(FormHelperText, { error: true, sx: { mt: 1 }, children: error })
2292
- ] });
2293
- };
2294
- var FieldSelector_default = FieldSelector;
1909
+ };
1910
+ await sessionManager.initialize(config);
1911
+ sessionManager.setupResponseInterceptor();
1912
+ const isAuth = sessionManager.isAuthenticated();
1913
+ const tokenInfo = sessionManager.getTokenInfo();
1914
+ setState((prev) => ({
1915
+ ...prev,
1916
+ isAuthenticated: isAuth,
1917
+ isInitialized: true,
1918
+ isLoading: false,
1919
+ tokens: tokenInfo.crudifyTokens.accessToken ? {
1920
+ accessToken: tokenInfo.crudifyTokens.accessToken,
1921
+ refreshToken: tokenInfo.crudifyTokens.refreshToken,
1922
+ expiresAt: tokenInfo.crudifyTokens.expiresAt,
1923
+ refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
1924
+ } : null
1925
+ }));
1926
+ } catch (error) {
1927
+ setState((prev) => ({
1928
+ ...prev,
1929
+ isLoading: false,
1930
+ isInitialized: true,
1931
+ error: error instanceof Error ? error.message : "Initialization failed"
1932
+ }));
1933
+ }
1934
+ }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
1935
+ const login = useCallback(async (email, password) => {
1936
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
1937
+ try {
1938
+ const result = await sessionManager.login(email, password);
1939
+ if (result.success && result.tokens) {
1940
+ setState((prev) => ({
1941
+ ...prev,
1942
+ isAuthenticated: true,
1943
+ tokens: result.tokens,
1944
+ isLoading: false,
1945
+ error: null
1946
+ }));
1947
+ } else {
1948
+ setState((prev) => ({
1949
+ ...prev,
1950
+ isAuthenticated: false,
1951
+ tokens: null,
1952
+ isLoading: false,
1953
+ error: result.error || "Login failed"
1954
+ }));
1955
+ }
1956
+ return result;
1957
+ } catch (error) {
1958
+ const errorMsg = error instanceof Error ? error.message : "Login failed";
1959
+ setState((prev) => ({
1960
+ ...prev,
1961
+ isAuthenticated: false,
1962
+ tokens: null,
1963
+ isLoading: false,
1964
+ error: errorMsg
1965
+ }));
1966
+ return {
1967
+ success: false,
1968
+ error: errorMsg
1969
+ };
1970
+ }
1971
+ }, [sessionManager]);
1972
+ const logout = useCallback(async () => {
1973
+ setState((prev) => ({ ...prev, isLoading: true }));
1974
+ try {
1975
+ await sessionManager.logout();
1976
+ setState((prev) => ({
1977
+ ...prev,
1978
+ isAuthenticated: false,
1979
+ tokens: null,
1980
+ isLoading: false,
1981
+ error: null
1982
+ }));
1983
+ } catch (error) {
1984
+ setState((prev) => ({
1985
+ ...prev,
1986
+ isAuthenticated: false,
1987
+ tokens: null,
1988
+ isLoading: false,
1989
+ error: error instanceof Error ? error.message : "Logout error"
1990
+ }));
1991
+ }
1992
+ }, [sessionManager]);
1993
+ const refreshTokens = useCallback(async () => {
1994
+ try {
1995
+ const success = await sessionManager.refreshTokens();
1996
+ if (success) {
1997
+ const tokenInfo = sessionManager.getTokenInfo();
1998
+ setState((prev) => ({
1999
+ ...prev,
2000
+ tokens: tokenInfo.crudifyTokens.accessToken ? {
2001
+ accessToken: tokenInfo.crudifyTokens.accessToken,
2002
+ refreshToken: tokenInfo.crudifyTokens.refreshToken,
2003
+ expiresAt: tokenInfo.crudifyTokens.expiresAt,
2004
+ refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
2005
+ } : null,
2006
+ error: null
2007
+ }));
2008
+ } else {
2009
+ setState((prev) => ({
2010
+ ...prev,
2011
+ isAuthenticated: false,
2012
+ tokens: null,
2013
+ error: "Token refresh failed"
2014
+ }));
2015
+ }
2016
+ return success;
2017
+ } catch (error) {
2018
+ setState((prev) => ({
2019
+ ...prev,
2020
+ isAuthenticated: false,
2021
+ tokens: null,
2022
+ error: error instanceof Error ? error.message : "Token refresh failed"
2023
+ }));
2024
+ return false;
2025
+ }
2026
+ }, [sessionManager]);
2027
+ const clearError = useCallback(() => {
2028
+ setState((prev) => ({ ...prev, error: null }));
2029
+ }, []);
2030
+ const getTokenInfo = useCallback(() => {
2031
+ return sessionManager.getTokenInfo();
2032
+ }, [sessionManager]);
2033
+ useEffect7(() => {
2034
+ initialize();
2035
+ }, [initialize]);
2036
+ return {
2037
+ // Estado
2038
+ ...state,
2039
+ // Acciones
2040
+ login,
2041
+ logout,
2042
+ refreshTokens,
2043
+ clearError,
2044
+ getTokenInfo,
2045
+ // Utilidades
2046
+ isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
2047
+ // 5 minutos
2048
+ expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
2049
+ refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
2050
+ };
2051
+ }
2295
2052
 
2296
- // src/components/PublicPolicies/constants.ts
2297
- var POLICY_ACTIONS = ["create", "read", "update", "delete"];
2298
- var PREFERRED_POLICY_ORDER = [
2299
- "create",
2300
- "read",
2301
- "update",
2302
- "delete"
2303
- ];
2053
+ // src/utils/jwtUtils.ts
2054
+ var decodeJwtSafely = (token) => {
2055
+ try {
2056
+ const parts = token.split(".");
2057
+ if (parts.length !== 3) {
2058
+ console.warn("Invalid JWT format: token must have 3 parts");
2059
+ return null;
2060
+ }
2061
+ const payload = parts[1];
2062
+ const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
2063
+ const decodedPayload = JSON.parse(atob(paddedPayload));
2064
+ return decodedPayload;
2065
+ } catch (error) {
2066
+ console.warn("Failed to decode JWT token:", error);
2067
+ return null;
2068
+ }
2069
+ };
2070
+ var getCurrentUserEmail = () => {
2071
+ try {
2072
+ let token = null;
2073
+ token = sessionStorage.getItem("authToken");
2074
+ console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
2075
+ if (!token) {
2076
+ token = sessionStorage.getItem("token");
2077
+ console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
2078
+ }
2079
+ if (!token) {
2080
+ token = localStorage.getItem("authToken") || localStorage.getItem("token");
2081
+ console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
2082
+ }
2083
+ if (!token) {
2084
+ console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
2085
+ return null;
2086
+ }
2087
+ const payload = decodeJwtSafely(token);
2088
+ if (!payload) {
2089
+ console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
2090
+ return null;
2091
+ }
2092
+ const email = payload.email || payload["cognito:username"] || null;
2093
+ console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
2094
+ return email;
2095
+ } catch (error) {
2096
+ console.warn("Failed to get current user email:", error);
2097
+ return null;
2098
+ }
2099
+ };
2100
+ var isTokenExpired = (token) => {
2101
+ try {
2102
+ const payload = decodeJwtSafely(token);
2103
+ if (!payload || !payload.exp) return true;
2104
+ const currentTime = Math.floor(Date.now() / 1e3);
2105
+ return payload.exp < currentTime;
2106
+ } catch {
2107
+ return true;
2108
+ }
2109
+ };
2304
2110
 
2305
- // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
2306
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2307
- var PolicyItem = forwardRef(({
2308
- policy,
2309
- onChange,
2310
- onRemove,
2311
- availableFields,
2312
- isSubmitting = false,
2313
- usedActions,
2314
- error
2315
- }, ref) => {
2316
- const { t } = useTranslation3();
2317
- const takenActions = new Set(Array.from(usedActions || []));
2318
- takenActions.delete(policy.action);
2319
- const actionOptions = POLICY_ACTIONS.map((a) => ({
2320
- value: a,
2321
- label: t(`modules.form.publicPolicies.fields.action.options.${a}`)
2322
- }));
2323
- return /* @__PURE__ */ jsxs9(
2324
- Paper,
2325
- {
2326
- ref,
2327
- sx: {
2328
- p: 3,
2329
- border: "1px solid #d1d9e0",
2330
- borderRadius: 2,
2331
- position: "relative",
2332
- backgroundColor: "#ffffff"
2333
- },
2111
+ // src/providers/SessionProvider.tsx
2112
+ import { Fragment as Fragment6, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2113
+ var SessionContext = createContext4(void 0);
2114
+ function SessionProvider({ children, options = {}, config: propConfig }) {
2115
+ const sessionHook = useSession(options);
2116
+ const resolvedConfig = useMemo2(() => {
2117
+ let publicApiKey;
2118
+ let env;
2119
+ let appName;
2120
+ let loginActions;
2121
+ let logo;
2122
+ let colors;
2123
+ let configSource = "unknown";
2124
+ if (propConfig?.publicApiKey) {
2125
+ publicApiKey = propConfig.publicApiKey;
2126
+ configSource = "props";
2127
+ }
2128
+ if (propConfig?.env) {
2129
+ env = propConfig.env;
2130
+ }
2131
+ if (propConfig?.appName) {
2132
+ appName = propConfig.appName;
2133
+ }
2134
+ if (propConfig?.loginActions) {
2135
+ loginActions = propConfig.loginActions;
2136
+ }
2137
+ if (propConfig?.logo) {
2138
+ logo = propConfig.logo;
2139
+ }
2140
+ if (propConfig?.colors) {
2141
+ colors = propConfig.colors;
2142
+ }
2143
+ if (!publicApiKey) {
2144
+ const cookieApiKey = getCookie("publicApiKey");
2145
+ const cookieEnv = getCookie("environment");
2146
+ const cookieAppName = getCookie("appName");
2147
+ const cookieLoginActions = getCookie("loginActions");
2148
+ if (cookieApiKey) {
2149
+ publicApiKey = cookieApiKey;
2150
+ configSource = "cookies";
2151
+ }
2152
+ if (cookieEnv && ["dev", "stg", "prod"].includes(cookieEnv)) {
2153
+ env = cookieEnv;
2154
+ }
2155
+ if (cookieAppName) {
2156
+ appName = cookieAppName;
2157
+ }
2158
+ if (cookieLoginActions) {
2159
+ loginActions = cookieLoginActions.split(",").map((s) => s.trim()).filter(Boolean);
2160
+ }
2161
+ }
2162
+ console.log("\u{1F50D} SessionProvider - Configuration Detection:");
2163
+ console.log(" - Config source:", configSource);
2164
+ console.log(" - PublicApiKey:", publicApiKey ? publicApiKey.substring(0, 15) + "..." : "undefined");
2165
+ console.log(" - Environment:", env);
2166
+ console.log(" - App name:", appName);
2167
+ console.log(" - Login actions:", loginActions);
2168
+ return {
2169
+ publicApiKey,
2170
+ env,
2171
+ appName,
2172
+ loginActions,
2173
+ logo,
2174
+ colors
2175
+ };
2176
+ }, [propConfig]);
2177
+ const sessionData = useMemo2(() => {
2178
+ if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
2179
+ return null;
2180
+ }
2181
+ try {
2182
+ const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
2183
+ if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
2184
+ const result = {
2185
+ _id: decoded.sub,
2186
+ email: decoded.email,
2187
+ subscriberKey: decoded.subscriber
2188
+ };
2189
+ Object.keys(decoded).forEach((key) => {
2190
+ if (!["sub", "email", "subscriber"].includes(key)) {
2191
+ result[key] = decoded[key];
2192
+ }
2193
+ });
2194
+ return result;
2195
+ }
2196
+ } catch (error) {
2197
+ console.error("Error decoding JWT token for sessionData:", error);
2198
+ }
2199
+ return null;
2200
+ }, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
2201
+ const contextValue = {
2202
+ ...sessionHook,
2203
+ sessionData,
2204
+ config: resolvedConfig
2205
+ };
2206
+ return /* @__PURE__ */ jsx9(SessionContext.Provider, { value: contextValue, children });
2207
+ }
2208
+ function useSessionContext() {
2209
+ const context = useContext4(SessionContext);
2210
+ if (context === void 0) {
2211
+ throw new Error("useSessionContext must be used within a SessionProvider");
2212
+ }
2213
+ return context;
2214
+ }
2215
+ function ProtectedRoute({ children, fallback = /* @__PURE__ */ jsx9("div", { children: "Please log in to access this content" }), redirectTo }) {
2216
+ const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
2217
+ if (!isInitialized || isLoading) {
2218
+ return /* @__PURE__ */ jsx9("div", { children: "Loading..." });
2219
+ }
2220
+ if (!isAuthenticated) {
2221
+ if (redirectTo) {
2222
+ redirectTo();
2223
+ return null;
2224
+ }
2225
+ return /* @__PURE__ */ jsx9(Fragment6, { children: fallback });
2226
+ }
2227
+ return /* @__PURE__ */ jsx9(Fragment6, { children });
2228
+ }
2229
+ function SessionDebugInfo() {
2230
+ const session = useSessionContext();
2231
+ if (!session.isInitialized) {
2232
+ return /* @__PURE__ */ jsx9("div", { children: "Session not initialized" });
2233
+ }
2234
+ return /* @__PURE__ */ jsxs6(
2235
+ "div",
2236
+ {
2237
+ style: {
2238
+ padding: "10px",
2239
+ margin: "10px",
2240
+ border: "1px solid #ccc",
2241
+ borderRadius: "4px",
2242
+ fontSize: "12px",
2243
+ fontFamily: "monospace"
2244
+ },
2334
2245
  children: [
2335
- /* @__PURE__ */ jsxs9(Box9, { sx: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", mb: 3 }, children: [
2336
- /* @__PURE__ */ jsx12(
2337
- Typography9,
2338
- {
2339
- variant: "subtitle1",
2340
- sx: {
2341
- fontWeight: 600,
2342
- color: "#111418",
2343
- fontSize: "1rem"
2344
- },
2345
- children: t("modules.form.publicPolicies.policyTitle")
2346
- }
2347
- ),
2348
- /* @__PURE__ */ jsx12(
2349
- IconButton2,
2350
- {
2351
- onClick: onRemove,
2352
- size: "small",
2353
- disabled: isSubmitting,
2354
- "aria-label": t("modules.form.publicPolicies.removePolicy"),
2355
- sx: {
2356
- color: "#656d76",
2357
- "&:hover": {
2358
- color: "#cf222e",
2359
- backgroundColor: "rgba(207, 34, 46, 0.1)"
2360
- }
2361
- },
2362
- children: /* @__PURE__ */ jsx12(Delete, {})
2363
- }
2364
- )
2246
+ /* @__PURE__ */ jsx9("h4", { children: "Session Debug Info" }),
2247
+ /* @__PURE__ */ jsxs6("div", { children: [
2248
+ /* @__PURE__ */ jsx9("strong", { children: "Authenticated:" }),
2249
+ " ",
2250
+ session.isAuthenticated ? "Yes" : "No"
2365
2251
  ] }),
2366
- /* @__PURE__ */ jsxs9(Stack2, { spacing: 3, children: [
2367
- /* @__PURE__ */ jsx12(Stack2, { direction: { xs: "column", md: "row" }, spacing: 2, children: /* @__PURE__ */ jsx12(Box9, { sx: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxs9(FormControl, { fullWidth: true, children: [
2368
- /* @__PURE__ */ jsx12(InputLabel, { children: t("modules.form.publicPolicies.fields.action.label") }),
2369
- /* @__PURE__ */ jsx12(
2370
- Select,
2371
- {
2372
- value: policy.action,
2373
- label: t("modules.form.publicPolicies.fields.action.label"),
2374
- disabled: isSubmitting,
2375
- onChange: (e) => {
2376
- const newAction = e.target.value;
2377
- const next = { ...policy, action: newAction };
2378
- if (newAction === "delete") {
2379
- next.permission = "deny";
2380
- delete next.fields;
2381
- } else {
2382
- next.fields = { allow: [], owner_allow: [], deny: availableFields };
2383
- delete next.permission;
2384
- }
2385
- onChange(next);
2386
- },
2387
- sx: {
2388
- backgroundColor: "#ffffff",
2389
- "&:hover .MuiOutlinedInput-notchedOutline": {
2390
- borderColor: "#8c959f"
2391
- },
2392
- "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
2393
- borderColor: "#0969da",
2394
- borderWidth: 2
2395
- }
2396
- },
2397
- children: actionOptions.map((option) => {
2398
- const disabledOption = takenActions.has(option.value);
2399
- return /* @__PURE__ */ jsx12(MenuItem, { value: option.value, disabled: disabledOption, children: option.label }, option.value);
2400
- })
2401
- }
2402
- ),
2403
- error && /* @__PURE__ */ jsx12(FormHelperText2, { error: true, children: error })
2404
- ] }) }) }),
2405
- policy.action === "delete" ? /* @__PURE__ */ jsxs9(Box9, { children: [
2406
- /* @__PURE__ */ jsx12(Typography9, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
2407
- /* @__PURE__ */ jsxs9(Stack2, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
2408
- /* @__PURE__ */ jsx12(
2409
- Button6,
2410
- {
2411
- variant: policy.permission === "*" ? "contained" : "outlined",
2412
- startIcon: /* @__PURE__ */ jsx12(SelectAll2, {}),
2413
- onClick: () => onChange({ ...policy, permission: "*" }),
2414
- disabled: isSubmitting,
2415
- size: "small",
2416
- sx: {
2417
- minWidth: 140,
2418
- whiteSpace: "nowrap",
2419
- ...policy.permission === "*" && {
2420
- backgroundColor: "#16a34a",
2421
- "&:hover": { backgroundColor: "#15803d" }
2422
- }
2423
- },
2424
- children: t("modules.form.publicPolicies.fields.conditions.allFields")
2425
- }
2426
- ),
2427
- /* @__PURE__ */ jsx12(
2428
- Button6,
2429
- {
2430
- variant: policy.permission === "owner" ? "contained" : "outlined",
2431
- onClick: () => onChange({ ...policy, permission: "owner" }),
2432
- disabled: isSubmitting,
2433
- size: "small",
2434
- sx: {
2435
- minWidth: 140,
2436
- whiteSpace: "nowrap",
2437
- ...policy.permission === "owner" && {
2438
- backgroundColor: "#0ea5e9",
2439
- "&:hover": { backgroundColor: "#0284c7" }
2440
- }
2441
- },
2442
- children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
2443
- }
2444
- ),
2445
- /* @__PURE__ */ jsx12(
2446
- Button6,
2447
- {
2448
- variant: policy.permission === "deny" ? "contained" : "outlined",
2449
- startIcon: /* @__PURE__ */ jsx12(ClearAll2, {}),
2450
- onClick: () => onChange({ ...policy, permission: "deny" }),
2451
- disabled: isSubmitting,
2452
- size: "small",
2453
- sx: {
2454
- minWidth: 140,
2455
- whiteSpace: "nowrap",
2456
- ...policy.permission === "deny" && {
2457
- backgroundColor: "#cf222e",
2458
- "&:hover": { backgroundColor: "#bc1f2c" }
2459
- }
2460
- },
2461
- children: t("modules.form.publicPolicies.fields.conditions.noFields")
2462
- }
2463
- )
2464
- ] })
2465
- ] }) : /* @__PURE__ */ jsx12(
2466
- FieldSelector_default,
2467
- {
2468
- value: policy.fields || { allow: [], owner_allow: [], deny: [] },
2469
- onChange: (nextFields) => onChange({ ...policy, fields: nextFields }),
2470
- availableFields,
2471
- disabled: isSubmitting
2472
- }
2473
- ),
2474
- /* @__PURE__ */ jsx12(Paper, { variant: "outlined", sx: { p: 2, backgroundColor: "#f9fafb" }, children: policy.action === "delete" ? /* @__PURE__ */ jsxs9(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
2475
- /* @__PURE__ */ jsxs9(Box9, { component: "span", sx: {
2476
- color: policy.permission === "*" ? "#16a34a" : policy.permission === "owner" ? "#0ea5e9" : "#dc2626"
2477
- }, children: [
2478
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
2479
- ":"
2480
- ] }),
2252
+ /* @__PURE__ */ jsxs6("div", { children: [
2253
+ /* @__PURE__ */ jsx9("strong", { children: "Loading:" }),
2254
+ " ",
2255
+ session.isLoading ? "Yes" : "No"
2256
+ ] }),
2257
+ /* @__PURE__ */ jsxs6("div", { children: [
2258
+ /* @__PURE__ */ jsx9("strong", { children: "Error:" }),
2259
+ " ",
2260
+ session.error || "None"
2261
+ ] }),
2262
+ session.tokens && /* @__PURE__ */ jsxs6(Fragment6, { children: [
2263
+ /* @__PURE__ */ jsxs6("div", { children: [
2264
+ /* @__PURE__ */ jsx9("strong", { children: "Access Token:" }),
2481
2265
  " ",
2482
- policy.permission || "-"
2483
- ] }) : /* @__PURE__ */ jsxs9(Stack2, { spacing: 0.5, divider: /* @__PURE__ */ jsx12(Divider2, { sx: { borderColor: "#e5e7eb" } }), children: [
2484
- /* @__PURE__ */ jsxs9(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
2485
- /* @__PURE__ */ jsxs9(Box9, { component: "span", sx: { color: "#16a34a" }, children: [
2486
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
2487
- ":"
2488
- ] }),
2489
- " ",
2490
- (policy?.fields?.allow || []).join(", ") || "-"
2491
- ] }),
2492
- /* @__PURE__ */ jsxs9(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
2493
- /* @__PURE__ */ jsxs9(Box9, { component: "span", sx: { color: "#0ea5e9" }, children: [
2494
- t("modules.form.publicPolicies.fields.conditions.states.ownerAllow"),
2495
- ":"
2496
- ] }),
2497
- " ",
2498
- (policy?.fields?.owner_allow || []).join(", ") || "-"
2499
- ] }),
2500
- /* @__PURE__ */ jsxs9(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
2501
- /* @__PURE__ */ jsxs9(Box9, { component: "span", sx: { color: "#dc2626" }, children: [
2502
- t("modules.form.publicPolicies.fields.conditions.states.deny"),
2503
- ":"
2504
- ] }),
2505
- " ",
2506
- (policy?.fields?.deny || []).join(", ") || "-"
2507
- ] })
2508
- ] }) })
2266
+ session.tokens.accessToken.substring(0, 20),
2267
+ "..."
2268
+ ] }),
2269
+ /* @__PURE__ */ jsxs6("div", { children: [
2270
+ /* @__PURE__ */ jsx9("strong", { children: "Refresh Token:" }),
2271
+ " ",
2272
+ session.tokens.refreshToken.substring(0, 20),
2273
+ "..."
2274
+ ] }),
2275
+ /* @__PURE__ */ jsxs6("div", { children: [
2276
+ /* @__PURE__ */ jsx9("strong", { children: "Access Expires In:" }),
2277
+ " ",
2278
+ Math.round(session.expiresIn / 1e3 / 60),
2279
+ " minutes"
2280
+ ] }),
2281
+ /* @__PURE__ */ jsxs6("div", { children: [
2282
+ /* @__PURE__ */ jsx9("strong", { children: "Refresh Expires In:" }),
2283
+ " ",
2284
+ Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
2285
+ " hours"
2286
+ ] }),
2287
+ /* @__PURE__ */ jsxs6("div", { children: [
2288
+ /* @__PURE__ */ jsx9("strong", { children: "Expiring Soon:" }),
2289
+ " ",
2290
+ session.isExpiringSoon ? "Yes" : "No"
2291
+ ] })
2509
2292
  ] })
2510
2293
  ]
2511
2294
  }
2512
2295
  );
2513
- });
2514
- var PolicyItem_default = PolicyItem;
2296
+ }
2515
2297
 
2516
- // src/components/PublicPolicies/Policies.tsx
2517
- import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2518
- var generateId = () => {
2519
- const c = globalThis?.crypto;
2520
- if (c && typeof c.randomUUID === "function") return c.randomUUID();
2521
- return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
2522
- };
2523
- var Policies = ({
2524
- policies,
2525
- onChange,
2526
- availableFields,
2527
- errors,
2528
- isSubmitting = false
2298
+ // src/components/CrudifyLogin/index.tsx
2299
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2300
+ var CrudifyLoginInternal = ({
2301
+ onScreenChange,
2302
+ onExternalNavigate,
2303
+ onLoginSuccess,
2304
+ onError,
2305
+ redirectUrl = "/"
2529
2306
  }) => {
2530
- const { t } = useTranslation4();
2531
- const policyRefs = useRef4({});
2532
- const takenActions = new Set((policies || []).map((p) => p.action).filter(Boolean));
2533
- const remainingActions = PREFERRED_POLICY_ORDER.filter((a) => !takenActions.has(a));
2534
- const canAddPolicy = remainingActions.length > 0;
2535
- const addPolicy = () => {
2536
- const defaultAction = remainingActions[0] || "create";
2537
- const newPolicy = {
2538
- id: generateId(),
2539
- action: defaultAction
2540
- };
2541
- if (defaultAction === "delete") {
2542
- newPolicy.permission = "deny";
2543
- } else {
2544
- newPolicy.fields = {
2545
- allow: [],
2546
- owner_allow: [],
2547
- deny: availableFields
2548
- };
2307
+ const { t } = useTranslation();
2308
+ const { state, setScreen } = useLoginState();
2309
+ const { config } = useSessionContext();
2310
+ const handleScreenChange = (screen2, params) => {
2311
+ let finalParams = params;
2312
+ if (screen2 === "login") {
2313
+ finalParams = {};
2314
+ } else if (screen2 === "forgotPassword" && !params) {
2315
+ finalParams = {};
2549
2316
  }
2550
- const next = [...policies || [], newPolicy];
2551
- onChange(next);
2552
- setTimeout(() => {
2553
- const newIndex = next.length - 1;
2554
- const el = policyRefs.current[newIndex];
2555
- if (el) {
2556
- el.scrollIntoView({ behavior: "smooth", block: "center" });
2557
- }
2558
- }, 100);
2559
- };
2560
- const removePolicy = (index) => {
2561
- const next = [...policies];
2562
- next.splice(index, 1);
2563
- onChange(next);
2317
+ setScreen(screen2, finalParams);
2318
+ onScreenChange?.(screen2, finalParams);
2564
2319
  };
2565
- const arrayError = (() => {
2566
- if (!errors) return null;
2567
- if (typeof errors === "string") return errors;
2568
- const msg = errors._error;
2569
- return typeof msg === "string" ? msg : null;
2570
- })();
2571
- const usedActions = new Set((policies || []).map((p) => p.action));
2572
- return /* @__PURE__ */ jsxs10(Fragment7, { children: [
2573
- /* @__PURE__ */ jsx13(Divider3, { sx: { borderColor: "#e0e4e7" } }),
2574
- /* @__PURE__ */ jsxs10(Box10, { children: [
2575
- /* @__PURE__ */ jsx13(Box10, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3, children: /* @__PURE__ */ jsxs10(Box10, { children: [
2576
- /* @__PURE__ */ jsx13(
2577
- Typography10,
2578
- {
2579
- variant: "h6",
2580
- sx: {
2581
- fontWeight: 600,
2582
- color: "#111418",
2583
- mb: 1
2584
- },
2585
- children: t("modules.form.publicPolicies.title")
2586
- }
2587
- ),
2588
- /* @__PURE__ */ jsx13(
2589
- Typography10,
2590
- {
2591
- variant: "body2",
2592
- color: "text.secondary",
2593
- sx: { fontSize: "0.875rem" },
2594
- children: t("modules.form.publicPolicies.description")
2595
- }
2596
- )
2597
- ] }) }),
2598
- arrayError && /* @__PURE__ */ jsx13(Alert7, { severity: "error", sx: { mb: 3 }, children: arrayError }),
2599
- /* @__PURE__ */ jsxs10(Stack3, { spacing: 3, children: [
2600
- (policies || []).length === 0 ? /* @__PURE__ */ jsx13(Alert7, { severity: "info", children: t("modules.form.publicPolicies.noPolicies") }) : policies.map((policy, index) => /* @__PURE__ */ jsx13(
2601
- PolicyItem_default,
2602
- {
2603
- ref: (el) => {
2604
- policyRefs.current[index] = el;
2605
- },
2606
- policy,
2607
- onChange: (nextPolicy) => {
2608
- const next = [...policies];
2609
- next[index] = nextPolicy;
2610
- onChange(next);
2611
- },
2612
- onRemove: () => removePolicy(index),
2613
- availableFields,
2614
- isSubmitting,
2615
- usedActions,
2616
- error: typeof errors === "object" && errors && policy.id in errors ? errors[policy.id] : void 0
2617
- },
2618
- policy.id
2619
- )),
2620
- canAddPolicy && /* @__PURE__ */ jsx13(Box10, { children: /* @__PURE__ */ jsx13(
2621
- Button7,
2320
+ const renderCurrentForm = () => {
2321
+ const commonProps = {
2322
+ onScreenChange: handleScreenChange,
2323
+ onExternalNavigate,
2324
+ onError,
2325
+ redirectUrl
2326
+ };
2327
+ switch (state.currentScreen) {
2328
+ case "forgotPassword":
2329
+ return /* @__PURE__ */ jsx10(ForgotPasswordForm_default, { ...commonProps });
2330
+ case "checkCode":
2331
+ return /* @__PURE__ */ jsx10(CheckCodeForm_default, { ...commonProps, searchParams: state.searchParams });
2332
+ case "resetPassword":
2333
+ return /* @__PURE__ */ jsx10(
2334
+ ResetPasswordForm_default,
2622
2335
  {
2623
- type: "button",
2624
- variant: "outlined",
2625
- startIcon: /* @__PURE__ */ jsx13(Add, {}),
2626
- onClick: addPolicy,
2627
- disabled: isSubmitting,
2628
- sx: {
2629
- borderColor: "#d0d7de",
2630
- color: "#656d76",
2631
- "&:hover": {
2632
- borderColor: "#8c959f",
2633
- backgroundColor: "transparent"
2634
- }
2635
- },
2636
- children: t("modules.form.publicPolicies.addPolicy")
2336
+ ...commonProps,
2337
+ searchParams: state.searchParams,
2338
+ onResetSuccess: () => {
2339
+ handleScreenChange("login");
2340
+ }
2637
2341
  }
2638
- ) })
2639
- ] })
2640
- ] })
2342
+ );
2343
+ default:
2344
+ return /* @__PURE__ */ jsx10(LoginForm_default, { ...commonProps, onLoginSuccess });
2345
+ }
2346
+ };
2347
+ return /* @__PURE__ */ jsxs7(CrudifyInitializer, { children: [
2348
+ /* @__PURE__ */ jsx10(Box6, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ jsx10(
2349
+ "img",
2350
+ {
2351
+ src: config.logo || "/nocios-default.png",
2352
+ alt: t("login.logoAlt"),
2353
+ style: {
2354
+ width: "100%",
2355
+ maxWidth: "150px",
2356
+ height: "auto"
2357
+ },
2358
+ onError: (e) => {
2359
+ const target = e.target;
2360
+ target.src = "/nocios-default.png";
2361
+ }
2362
+ }
2363
+ ) }),
2364
+ config.appName && /* @__PURE__ */ jsx10(
2365
+ Typography6,
2366
+ {
2367
+ variant: "h6",
2368
+ component: "h1",
2369
+ sx: {
2370
+ textAlign: "center",
2371
+ mb: 2,
2372
+ color: config.colors?.primaryColor || "#1066BA"
2373
+ },
2374
+ children: config.appName
2375
+ }
2376
+ ),
2377
+ renderCurrentForm()
2641
2378
  ] });
2642
2379
  };
2643
- var Policies_default = Policies;
2380
+ var CrudifyLogin = ({
2381
+ translations,
2382
+ translationsUrl,
2383
+ language = "en",
2384
+ initialScreen = "login",
2385
+ autoReadFromCookies = true,
2386
+ ...props
2387
+ }) => {
2388
+ const { config } = useSessionContext();
2389
+ return /* @__PURE__ */ jsx10(I18nProvider, { translations, translationsUrl, language, children: /* @__PURE__ */ jsx10(CrudifyProvider, { config, children: /* @__PURE__ */ jsx10(LoginStateProvider, { config, initialScreen, autoReadFromCookies, children: /* @__PURE__ */ jsx10(CrudifyLoginInternal, { ...props }) }) }) });
2390
+ };
2391
+ var CrudifyLogin_default = CrudifyLogin;
2644
2392
 
2645
- // src/core/SessionManager.ts
2646
- import crudify4 from "@nocios/crudify-browser";
2393
+ // src/components/UserProfile/UserProfileDisplay.tsx
2394
+ import {
2395
+ Box as Box7,
2396
+ Card,
2397
+ CardContent,
2398
+ Typography as Typography7,
2399
+ Chip,
2400
+ Avatar,
2401
+ Divider,
2402
+ CircularProgress as CircularProgress6,
2403
+ Alert as Alert6,
2404
+ List,
2405
+ ListItem,
2406
+ ListItemText,
2407
+ ListItemIcon,
2408
+ Collapse,
2409
+ IconButton
2410
+ } from "@mui/material";
2411
+ import {
2412
+ Person,
2413
+ Email,
2414
+ Badge,
2415
+ Security,
2416
+ Schedule,
2417
+ AccountCircle,
2418
+ ExpandMore,
2419
+ ExpandLess,
2420
+ Info
2421
+ } from "@mui/icons-material";
2647
2422
 
2648
- // src/utils/tokenStorage.ts
2649
- import CryptoJS from "crypto-js";
2650
- var _TokenStorage = class _TokenStorage {
2651
- /**
2652
- * Configurar tipo de almacenamiento
2653
- */
2654
- static setStorageType(type) {
2655
- _TokenStorage.storageType = type;
2656
- }
2657
- /**
2658
- * Verificar si el storage está disponible
2659
- */
2660
- static isStorageAvailable(type) {
2661
- try {
2662
- const storage = window[type];
2663
- const testKey = "__storage_test__";
2664
- storage.setItem(testKey, "test");
2665
- storage.removeItem(testKey);
2666
- return true;
2667
- } catch {
2668
- return false;
2669
- }
2670
- }
2671
- /**
2672
- * Obtener instancia de storage
2673
- */
2674
- static getStorage() {
2675
- if (_TokenStorage.storageType === "none") return null;
2676
- if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
2677
- console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
2678
- return null;
2423
+ // src/hooks/useUserProfile.ts
2424
+ import { useState as useState7, useEffect as useEffect8, useCallback as useCallback2, useRef as useRef2 } from "react";
2425
+ import crudify3 from "@nocios/crudify-browser";
2426
+ var useUserProfile = (options = {}) => {
2427
+ const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
2428
+ const [userProfile, setUserProfile] = useState7(null);
2429
+ const [loading, setLoading] = useState7(false);
2430
+ const [error, setError] = useState7(null);
2431
+ const [extendedData, setExtendedData] = useState7({});
2432
+ const abortControllerRef = useRef2(null);
2433
+ const mountedRef = useRef2(true);
2434
+ const requestIdRef = useRef2(0);
2435
+ const retryCountRef = useRef2(0);
2436
+ const clearProfile = useCallback2(() => {
2437
+ setUserProfile(null);
2438
+ setError(null);
2439
+ setLoading(false);
2440
+ setExtendedData({});
2441
+ }, []);
2442
+ const refreshProfile = useCallback2(async () => {
2443
+ const userEmail = getCurrentUserEmail();
2444
+ if (!userEmail) {
2445
+ if (mountedRef.current) {
2446
+ setError("No user email available");
2447
+ setLoading(false);
2448
+ }
2449
+ return;
2679
2450
  }
2680
- return window[_TokenStorage.storageType];
2681
- }
2682
- /**
2683
- * Encriptar datos sensibles
2684
- */
2685
- static encrypt(data) {
2686
- try {
2687
- return CryptoJS.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
2688
- } catch (error) {
2689
- console.error("Crudify: Encryption failed", error);
2690
- return data;
2451
+ if (abortControllerRef.current) {
2452
+ abortControllerRef.current.abort();
2691
2453
  }
2692
- }
2693
- /**
2694
- * Desencriptar datos
2695
- */
2696
- static decrypt(encryptedData) {
2454
+ const abortController = new AbortController();
2455
+ abortControllerRef.current = abortController;
2456
+ const currentRequestId = ++requestIdRef.current;
2697
2457
  try {
2698
- const bytes = CryptoJS.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
2699
- const decrypted = bytes.toString(CryptoJS.enc.Utf8);
2700
- return decrypted || encryptedData;
2701
- } catch (error) {
2702
- console.error("Crudify: Decryption failed", error);
2703
- return encryptedData;
2704
- }
2705
- }
2706
- /**
2707
- * Guardar tokens de forma segura
2708
- */
2709
- static saveTokens(tokens) {
2710
- const storage = _TokenStorage.getStorage();
2711
- if (!storage) return;
2712
- try {
2713
- const tokenData = {
2714
- accessToken: tokens.accessToken,
2715
- refreshToken: tokens.refreshToken,
2716
- expiresAt: tokens.expiresAt,
2717
- refreshExpiresAt: tokens.refreshExpiresAt,
2718
- savedAt: Date.now()
2719
- };
2720
- const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
2721
- storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
2722
- console.debug("Crudify: Tokens saved successfully");
2723
- } catch (error) {
2724
- console.error("Crudify: Failed to save tokens", error);
2725
- }
2726
- }
2727
- /**
2728
- * Obtener tokens guardados
2729
- */
2730
- static getTokens() {
2731
- const storage = _TokenStorage.getStorage();
2732
- if (!storage) return null;
2733
- try {
2734
- const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
2735
- if (!encrypted) return null;
2736
- const decrypted = _TokenStorage.decrypt(encrypted);
2737
- const tokenData = JSON.parse(decrypted);
2738
- if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
2739
- console.warn("Crudify: Incomplete token data found, clearing storage");
2740
- _TokenStorage.clearTokens();
2741
- return null;
2458
+ if (mountedRef.current) {
2459
+ setLoading(true);
2460
+ setError(null);
2742
2461
  }
2743
- if (Date.now() >= tokenData.refreshExpiresAt) {
2744
- console.info("Crudify: Refresh token expired, clearing storage");
2745
- _TokenStorage.clearTokens();
2746
- return null;
2462
+ const response = await crudify3.readItems("users", {
2463
+ filter: { email: userEmail },
2464
+ pagination: { limit: 1 }
2465
+ });
2466
+ if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
2467
+ if (response.success && response.data && response.data.length > 0) {
2468
+ const userData = response.data[0];
2469
+ setUserProfile(userData);
2470
+ const additionalData = {
2471
+ fullProfile: userData,
2472
+ totalFields: Object.keys(userData).length,
2473
+ displayData: {
2474
+ id: userData.id,
2475
+ email: userData.email,
2476
+ username: userData.username,
2477
+ firstName: userData.firstName,
2478
+ lastName: userData.lastName,
2479
+ fullName: userData.fullName || `${userData.firstName || ""} ${userData.lastName || ""}`.trim(),
2480
+ role: userData.role,
2481
+ permissions: userData.permissions || [],
2482
+ isActive: userData.isActive,
2483
+ lastLogin: userData.lastLogin,
2484
+ createdAt: userData.createdAt,
2485
+ updatedAt: userData.updatedAt,
2486
+ // Include any custom fields
2487
+ ...Object.keys(userData).filter(
2488
+ (key) => ![
2489
+ "id",
2490
+ "email",
2491
+ "username",
2492
+ "firstName",
2493
+ "lastName",
2494
+ "fullName",
2495
+ "role",
2496
+ "permissions",
2497
+ "isActive",
2498
+ "lastLogin",
2499
+ "createdAt",
2500
+ "updatedAt"
2501
+ ].includes(key)
2502
+ ).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
2503
+ }
2504
+ };
2505
+ setExtendedData(additionalData);
2506
+ setError(null);
2507
+ retryCountRef.current = 0;
2508
+ } else {
2509
+ setError("User profile not found");
2510
+ setUserProfile(null);
2511
+ setExtendedData({});
2512
+ }
2513
+ }
2514
+ } catch (err) {
2515
+ if (currentRequestId === requestIdRef.current && mountedRef.current) {
2516
+ const error2 = err;
2517
+ if (error2.name === "AbortError") {
2518
+ return;
2519
+ }
2520
+ const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
2521
+ if (shouldRetry) {
2522
+ retryCountRef.current++;
2523
+ setTimeout(() => {
2524
+ if (mountedRef.current) {
2525
+ refreshProfile();
2526
+ }
2527
+ }, 1e3 * retryCountRef.current);
2528
+ } else {
2529
+ setError("Failed to load user profile");
2530
+ setUserProfile(null);
2531
+ setExtendedData({});
2532
+ }
2533
+ }
2534
+ } finally {
2535
+ if (currentRequestId === requestIdRef.current && mountedRef.current) {
2536
+ setLoading(false);
2537
+ }
2538
+ if (abortControllerRef.current === abortController) {
2539
+ abortControllerRef.current = null;
2747
2540
  }
2748
- return {
2749
- accessToken: tokenData.accessToken,
2750
- refreshToken: tokenData.refreshToken,
2751
- expiresAt: tokenData.expiresAt,
2752
- refreshExpiresAt: tokenData.refreshExpiresAt
2753
- };
2754
- } catch (error) {
2755
- console.error("Crudify: Failed to retrieve tokens", error);
2756
- _TokenStorage.clearTokens();
2757
- return null;
2758
2541
  }
2759
- }
2760
- /**
2761
- * Limpiar tokens almacenados
2762
- */
2763
- static clearTokens() {
2764
- const storage = _TokenStorage.getStorage();
2765
- if (!storage) return;
2766
- try {
2767
- storage.removeItem(_TokenStorage.TOKEN_KEY);
2768
- console.debug("Crudify: Tokens cleared from storage");
2769
- } catch (error) {
2770
- console.error("Crudify: Failed to clear tokens", error);
2542
+ }, [retryOnError, maxRetries]);
2543
+ useEffect8(() => {
2544
+ if (autoFetch) {
2545
+ refreshProfile();
2771
2546
  }
2772
- }
2773
- /**
2774
- * Verificar si hay tokens válidos guardados
2775
- */
2776
- static hasValidTokens() {
2777
- const tokens = _TokenStorage.getTokens();
2778
- return tokens !== null;
2779
- }
2780
- /**
2781
- * Obtener información de expiración
2782
- */
2783
- static getExpirationInfo() {
2784
- const tokens = _TokenStorage.getTokens();
2785
- if (!tokens) return null;
2786
- const now = Date.now();
2787
- return {
2788
- accessExpired: now >= tokens.expiresAt,
2789
- refreshExpired: now >= tokens.refreshExpiresAt,
2790
- accessExpiresIn: Math.max(0, tokens.expiresAt - now),
2791
- refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
2547
+ }, [autoFetch, refreshProfile]);
2548
+ useEffect8(() => {
2549
+ mountedRef.current = true;
2550
+ return () => {
2551
+ mountedRef.current = false;
2552
+ if (abortControllerRef.current) {
2553
+ abortControllerRef.current.abort();
2554
+ abortControllerRef.current = null;
2555
+ }
2792
2556
  };
2793
- }
2794
- /**
2795
- * Actualizar solo el access token (después de refresh)
2796
- */
2797
- static updateAccessToken(newAccessToken, newExpiresAt) {
2798
- const existingTokens = _TokenStorage.getTokens();
2799
- if (!existingTokens) {
2800
- console.warn("Crudify: Cannot update access token, no existing tokens found");
2801
- return;
2802
- }
2803
- _TokenStorage.saveTokens({
2804
- ...existingTokens,
2805
- accessToken: newAccessToken,
2806
- expiresAt: newExpiresAt
2807
- });
2808
- }
2557
+ }, []);
2558
+ return {
2559
+ userProfile,
2560
+ loading,
2561
+ error,
2562
+ extendedData,
2563
+ refreshProfile,
2564
+ clearProfile
2565
+ };
2809
2566
  };
2810
- _TokenStorage.TOKEN_KEY = "crudify_tokens";
2811
- _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
2812
- _TokenStorage.storageType = "localStorage";
2813
- var TokenStorage = _TokenStorage;
2814
2567
 
2815
- // src/core/SessionManager.ts
2816
- var SessionManager = class _SessionManager {
2817
- constructor() {
2818
- this.config = {};
2819
- this.initialized = false;
2568
+ // src/components/UserProfile/UserProfileDisplay.tsx
2569
+ import { useState as useState8 } from "react";
2570
+ import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2571
+ var UserProfileDisplay = ({
2572
+ showExtendedData = true,
2573
+ showProfileCard = true,
2574
+ autoRefresh = true
2575
+ }) => {
2576
+ const { userProfile, loading, error, extendedData, refreshProfile } = useUserProfile({
2577
+ autoFetch: autoRefresh,
2578
+ retryOnError: true,
2579
+ maxRetries: 3
2580
+ });
2581
+ const [showAllFields, setShowAllFields] = useState8(false);
2582
+ if (loading) {
2583
+ return /* @__PURE__ */ jsxs8(Box7, { display: "flex", justifyContent: "center", alignItems: "center", p: 3, children: [
2584
+ /* @__PURE__ */ jsx11(CircularProgress6, {}),
2585
+ /* @__PURE__ */ jsx11(Typography7, { variant: "body2", sx: { ml: 2 }, children: "Cargando perfil de usuario..." })
2586
+ ] });
2820
2587
  }
2821
- static getInstance() {
2822
- if (!_SessionManager.instance) {
2823
- _SessionManager.instance = new _SessionManager();
2824
- }
2825
- return _SessionManager.instance;
2588
+ if (error) {
2589
+ return /* @__PURE__ */ jsxs8(
2590
+ Alert6,
2591
+ {
2592
+ severity: "error",
2593
+ action: /* @__PURE__ */ jsx11(IconButton, { color: "inherit", size: "small", onClick: refreshProfile, children: /* @__PURE__ */ jsx11(Typography7, { variant: "caption", children: "Reintentar" }) }),
2594
+ children: [
2595
+ "Error al cargar el perfil: ",
2596
+ error
2597
+ ]
2598
+ }
2599
+ );
2826
2600
  }
2827
- /**
2828
- * Inicializar el SessionManager
2829
- */
2830
- async initialize(config = {}) {
2831
- if (this.initialized) {
2832
- console.warn("SessionManager: Already initialized");
2833
- return;
2834
- }
2835
- this.config = {
2836
- storageType: "localStorage",
2837
- autoRestore: true,
2838
- enableLogging: false,
2839
- ...config
2840
- };
2841
- TokenStorage.setStorageType(this.config.storageType || "localStorage");
2842
- if (this.config.enableLogging) {
2843
- }
2844
- if (this.config.autoRestore) {
2845
- await this.restoreSession();
2846
- }
2847
- this.initialized = true;
2848
- this.log("SessionManager initialized successfully");
2849
- }
2850
- /**
2851
- * Login con persistencia automática
2852
- */
2853
- async login(email, password) {
2854
- try {
2855
- this.log("Attempting login...");
2856
- const response = await crudify4.login(email, password);
2857
- if (!response.success) {
2858
- this.log("Login failed:", response.errors);
2859
- return {
2860
- success: false,
2861
- error: this.formatError(response.errors)
2862
- };
2863
- }
2864
- const tokens = {
2865
- accessToken: response.data.token,
2866
- refreshToken: response.data.refreshToken,
2867
- expiresAt: response.data.expiresAt,
2868
- refreshExpiresAt: response.data.refreshExpiresAt
2869
- };
2870
- TokenStorage.saveTokens(tokens);
2871
- this.log("Login successful, tokens saved");
2872
- this.config.onLoginSuccess?.(tokens);
2873
- return {
2874
- success: true,
2875
- tokens
2876
- };
2877
- } catch (error) {
2878
- this.log("Login error:", error);
2879
- return {
2880
- success: false,
2881
- error: error instanceof Error ? error.message : "Unknown error"
2882
- };
2883
- }
2884
- }
2885
- /**
2886
- * Logout con limpieza de tokens
2887
- */
2888
- async logout() {
2889
- try {
2890
- this.log("Logging out...");
2891
- await crudify4.logout();
2892
- TokenStorage.clearTokens();
2893
- this.log("Logout successful");
2894
- this.config.onLogout?.();
2895
- } catch (error) {
2896
- this.log("Logout error:", error);
2897
- TokenStorage.clearTokens();
2898
- }
2601
+ if (!userProfile) {
2602
+ return /* @__PURE__ */ jsx11(Alert6, { severity: "warning", children: "No se encontr\xF3 informaci\xF3n del usuario" });
2899
2603
  }
2900
- /**
2901
- * Restaurar sesión desde storage
2902
- */
2903
- async restoreSession() {
2604
+ const displayData = extendedData?.displayData || {};
2605
+ const totalFields = extendedData?.totalFields || 0;
2606
+ const formatDate = (dateString) => {
2607
+ if (!dateString) return "No disponible";
2904
2608
  try {
2905
- this.log("Attempting to restore session...");
2906
- const savedTokens = TokenStorage.getTokens();
2907
- if (!savedTokens) {
2908
- this.log("No valid tokens found in storage");
2909
- return false;
2910
- }
2911
- crudify4.setTokens({
2912
- accessToken: savedTokens.accessToken,
2913
- refreshToken: savedTokens.refreshToken,
2914
- expiresAt: savedTokens.expiresAt,
2915
- refreshExpiresAt: savedTokens.refreshExpiresAt
2609
+ return new Date(dateString).toLocaleString("es-ES", {
2610
+ year: "numeric",
2611
+ month: "short",
2612
+ day: "numeric",
2613
+ hour: "2-digit",
2614
+ minute: "2-digit"
2916
2615
  });
2917
- this.log("Session restored successfully");
2918
- this.config.onSessionRestored?.(savedTokens);
2919
- return true;
2920
- } catch (error) {
2921
- this.log("Session restore error:", error);
2922
- TokenStorage.clearTokens();
2923
- return false;
2924
- }
2925
- }
2926
- /**
2927
- * Verificar si el usuario está autenticado
2928
- */
2929
- isAuthenticated() {
2930
- return crudify4.isLogin() || TokenStorage.hasValidTokens();
2931
- }
2932
- /**
2933
- * Obtener información de tokens actuales
2934
- */
2935
- getTokenInfo() {
2936
- const crudifyTokens = crudify4.getTokenData();
2937
- const storageInfo = TokenStorage.getExpirationInfo();
2938
- return {
2939
- isLoggedIn: this.isAuthenticated(),
2940
- crudifyTokens,
2941
- storageInfo,
2942
- hasValidTokens: TokenStorage.hasValidTokens()
2943
- };
2944
- }
2945
- /**
2946
- * Refrescar tokens manualmente
2947
- */
2948
- async refreshTokens() {
2949
- try {
2950
- this.log("Manually refreshing tokens...");
2951
- const response = await crudify4.refreshAccessToken();
2952
- if (!response.success) {
2953
- this.log("Token refresh failed:", response.errors);
2954
- TokenStorage.clearTokens();
2955
- this.config.onSessionExpired?.();
2956
- return false;
2957
- }
2958
- const newTokens = {
2959
- accessToken: response.data.token,
2960
- refreshToken: response.data.refreshToken,
2961
- expiresAt: response.data.expiresAt,
2962
- refreshExpiresAt: response.data.refreshExpiresAt
2963
- };
2964
- TokenStorage.saveTokens(newTokens);
2965
- this.log("Tokens refreshed and saved successfully");
2966
- return true;
2967
- } catch (error) {
2968
- this.log("Token refresh error:", error);
2969
- TokenStorage.clearTokens();
2970
- this.config.onSessionExpired?.();
2971
- return false;
2616
+ } catch {
2617
+ return dateString;
2972
2618
  }
2973
- }
2974
- /**
2975
- * Configurar interceptor de respuesta para manejo automático de errores
2976
- */
2977
- setupResponseInterceptor() {
2978
- crudify4.setResponseInterceptor(async (response) => {
2979
- if (response.errors) {
2980
- const hasAuthError = response.errors.some(
2981
- (error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
2982
- );
2983
- if (hasAuthError && TokenStorage.hasValidTokens()) {
2984
- this.log("Auth error detected, attempting token refresh...");
2985
- const refreshSuccess = await this.refreshTokens();
2986
- if (!refreshSuccess) {
2987
- this.log("Session expired, triggering callback");
2988
- this.config.onSessionExpired?.();
2619
+ };
2620
+ const renderFieldValue = (key, value) => {
2621
+ if (value === null || value === void 0) return "No disponible";
2622
+ if (typeof value === "boolean") return value ? "S\xED" : "No";
2623
+ if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "Ninguno";
2624
+ if (typeof value === "object") return JSON.stringify(value, null, 2);
2625
+ return String(value);
2626
+ };
2627
+ const basicFields = [
2628
+ { key: "id", label: "ID", icon: /* @__PURE__ */ jsx11(Badge, {}) },
2629
+ { key: "email", label: "Email", icon: /* @__PURE__ */ jsx11(Email, {}) },
2630
+ { key: "username", label: "Usuario", icon: /* @__PURE__ */ jsx11(Person, {}) },
2631
+ { key: "fullName", label: "Nombre completo", icon: /* @__PURE__ */ jsx11(AccountCircle, {}) },
2632
+ { key: "role", label: "Rol", icon: /* @__PURE__ */ jsx11(Security, {}) }
2633
+ ];
2634
+ const extendedFields = [
2635
+ { key: "firstName", label: "Nombre" },
2636
+ { key: "lastName", label: "Apellido" },
2637
+ { key: "isActive", label: "Activo" },
2638
+ { key: "lastLogin", label: "\xDAltimo login" },
2639
+ { key: "createdAt", label: "Creado" },
2640
+ { key: "updatedAt", label: "Actualizado" }
2641
+ ];
2642
+ const knownFields = [...basicFields.map((f) => f.key), ...extendedFields.map((f) => f.key), "permissions"];
2643
+ const customFields = Object.keys(displayData).filter((key) => !knownFields.includes(key)).map((key) => ({ key, label: key }));
2644
+ return /* @__PURE__ */ jsxs8(Box7, { children: [
2645
+ showProfileCard && /* @__PURE__ */ jsx11(Card, { sx: { mb: 2 }, children: /* @__PURE__ */ jsxs8(CardContent, { children: [
2646
+ /* @__PURE__ */ jsxs8(Box7, { display: "flex", alignItems: "center", mb: 2, children: [
2647
+ /* @__PURE__ */ jsx11(
2648
+ Avatar,
2649
+ {
2650
+ src: displayData.avatar,
2651
+ sx: { width: 56, height: 56, mr: 2 },
2652
+ children: displayData.fullName?.[0] || displayData.username?.[0] || displayData.email?.[0]
2989
2653
  }
2990
- }
2991
- }
2992
- return response;
2993
- });
2994
- this.log("Response interceptor configured");
2995
- }
2996
- /**
2997
- * Limpiar sesión completamente
2998
- */
2999
- clearSession() {
3000
- TokenStorage.clearTokens();
3001
- crudify4.logout();
3002
- this.log("Session cleared completely");
3003
- }
3004
- // Métodos privados
3005
- log(message, ...args) {
3006
- if (this.config.enableLogging) {
3007
- console.log(`[SessionManager] ${message}`, ...args);
3008
- }
3009
- }
3010
- formatError(errors) {
3011
- if (!errors) return "Unknown error";
3012
- if (typeof errors === "string") return errors;
3013
- if (typeof errors === "object") {
3014
- const errorMessages = Object.values(errors).flat();
3015
- return errorMessages.join(", ");
3016
- }
3017
- return "Authentication failed";
3018
- }
2654
+ ),
2655
+ /* @__PURE__ */ jsxs8(Box7, { children: [
2656
+ /* @__PURE__ */ jsx11(Typography7, { variant: "h6", children: displayData.fullName || displayData.username || displayData.email }),
2657
+ /* @__PURE__ */ jsx11(Typography7, { variant: "body2", color: "text.secondary", children: displayData.role || "Usuario" }),
2658
+ displayData.isActive !== void 0 && /* @__PURE__ */ jsx11(
2659
+ Chip,
2660
+ {
2661
+ label: displayData.isActive ? "Activo" : "Inactivo",
2662
+ color: displayData.isActive ? "success" : "error",
2663
+ size: "small",
2664
+ sx: { mt: 0.5 }
2665
+ }
2666
+ )
2667
+ ] })
2668
+ ] }),
2669
+ /* @__PURE__ */ jsx11(Box7, { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))", gap: 2, children: basicFields.map(
2670
+ ({ key, label, icon }) => displayData[key] ? /* @__PURE__ */ jsxs8(Box7, { display: "flex", alignItems: "center", children: [
2671
+ /* @__PURE__ */ jsx11(Box7, { sx: { mr: 1, color: "text.secondary" }, children: icon }),
2672
+ /* @__PURE__ */ jsxs8(Box7, { children: [
2673
+ /* @__PURE__ */ jsx11(Typography7, { variant: "caption", color: "text.secondary", children: label }),
2674
+ /* @__PURE__ */ jsx11(Typography7, { variant: "body2", children: renderFieldValue(key, displayData[key]) })
2675
+ ] })
2676
+ ] }, key) : null
2677
+ ) }),
2678
+ displayData.permissions && Array.isArray(displayData.permissions) && displayData.permissions.length > 0 && /* @__PURE__ */ jsxs8(Box7, { mt: 2, children: [
2679
+ /* @__PURE__ */ jsx11(Typography7, { variant: "caption", color: "text.secondary", display: "block", children: "Permisos" }),
2680
+ /* @__PURE__ */ jsxs8(Box7, { display: "flex", flexWrap: "wrap", gap: 0.5, mt: 0.5, children: [
2681
+ displayData.permissions.slice(0, 5).map((permission, index) => /* @__PURE__ */ jsx11(Chip, { label: permission, size: "small", variant: "outlined" }, index)),
2682
+ displayData.permissions.length > 5 && /* @__PURE__ */ jsx11(Chip, { label: `+${displayData.permissions.length - 5} m\xE1s`, size: "small" })
2683
+ ] })
2684
+ ] })
2685
+ ] }) }),
2686
+ showExtendedData && /* @__PURE__ */ jsx11(Card, { children: /* @__PURE__ */ jsxs8(CardContent, { children: [
2687
+ /* @__PURE__ */ jsxs8(Box7, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 2, children: [
2688
+ /* @__PURE__ */ jsxs8(Typography7, { variant: "h6", display: "flex", alignItems: "center", children: [
2689
+ /* @__PURE__ */ jsx11(Info, { sx: { mr: 1 } }),
2690
+ "Informaci\xF3n Detallada"
2691
+ ] }),
2692
+ /* @__PURE__ */ jsx11(Chip, { label: `${totalFields} campos totales`, size: "small" })
2693
+ ] }),
2694
+ /* @__PURE__ */ jsxs8(List, { dense: true, children: [
2695
+ extendedFields.map(({ key, label }) => displayData[key] !== void 0 && /* @__PURE__ */ jsxs8(ListItem, { divider: true, children: [
2696
+ /* @__PURE__ */ jsx11(ListItemIcon, { children: /* @__PURE__ */ jsx11(Schedule, { fontSize: "small" }) }),
2697
+ /* @__PURE__ */ jsx11(
2698
+ ListItemText,
2699
+ {
2700
+ primary: label,
2701
+ secondary: key.includes("At") || key.includes("Login") ? formatDate(displayData[key]) : renderFieldValue(key, displayData[key])
2702
+ }
2703
+ )
2704
+ ] }, key)),
2705
+ customFields.length > 0 && /* @__PURE__ */ jsxs8(Fragment7, { children: [
2706
+ /* @__PURE__ */ jsx11(Divider, { sx: { my: 1 } }),
2707
+ /* @__PURE__ */ jsx11(ListItem, { children: /* @__PURE__ */ jsx11(
2708
+ ListItemText,
2709
+ {
2710
+ primary: /* @__PURE__ */ jsxs8(Box7, { display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2711
+ /* @__PURE__ */ jsxs8(Typography7, { variant: "subtitle2", children: [
2712
+ "Campos Personalizados (",
2713
+ customFields.length,
2714
+ ")"
2715
+ ] }),
2716
+ /* @__PURE__ */ jsx11(IconButton, { size: "small", onClick: () => setShowAllFields(!showAllFields), children: showAllFields ? /* @__PURE__ */ jsx11(ExpandLess, {}) : /* @__PURE__ */ jsx11(ExpandMore, {}) })
2717
+ ] })
2718
+ }
2719
+ ) }),
2720
+ /* @__PURE__ */ jsx11(Collapse, { in: showAllFields, children: customFields.map(({ key, label }) => /* @__PURE__ */ jsx11(ListItem, { sx: { pl: 4 }, children: /* @__PURE__ */ jsx11(
2721
+ ListItemText,
2722
+ {
2723
+ primary: label,
2724
+ secondary: renderFieldValue(key, displayData[key])
2725
+ }
2726
+ ) }, key)) })
2727
+ ] })
2728
+ ] }),
2729
+ /* @__PURE__ */ jsxs8(Box7, { mt: 2, display: "flex", justifyContent: "space-between", alignItems: "center", children: [
2730
+ /* @__PURE__ */ jsxs8(Typography7, { variant: "caption", color: "text.secondary", children: [
2731
+ "\xDAltima actualizaci\xF3n: ",
2732
+ formatDate(displayData.updatedAt)
2733
+ ] }),
2734
+ /* @__PURE__ */ jsx11(IconButton, { size: "small", onClick: refreshProfile, disabled: loading, children: /* @__PURE__ */ jsx11(Typography7, { variant: "caption", children: "Actualizar" }) })
2735
+ ] })
2736
+ ] }) })
2737
+ ] });
3019
2738
  };
2739
+ var UserProfileDisplay_default = UserProfileDisplay;
3020
2740
 
3021
- // src/hooks/useSession.ts
3022
- import { useState as useState9, useEffect as useEffect9, useCallback as useCallback2 } from "react";
3023
- function useSession(options = {}) {
3024
- const [state, setState] = useState9({
3025
- isAuthenticated: false,
3026
- isLoading: true,
3027
- isInitialized: false,
3028
- tokens: null,
3029
- error: null
3030
- });
3031
- const sessionManager = SessionManager.getInstance();
3032
- const initialize = useCallback2(async () => {
3033
- try {
3034
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
3035
- const config = {
3036
- autoRestore: options.autoRestore ?? true,
3037
- enableLogging: options.enableLogging ?? false,
3038
- onSessionExpired: () => {
3039
- setState((prev) => ({
3040
- ...prev,
3041
- isAuthenticated: false,
3042
- tokens: null,
3043
- error: "Session expired"
3044
- }));
3045
- options.onSessionExpired?.();
3046
- },
3047
- onSessionRestored: (tokens) => {
3048
- setState((prev) => ({
3049
- ...prev,
3050
- isAuthenticated: true,
3051
- tokens,
3052
- error: null
3053
- }));
3054
- options.onSessionRestored?.(tokens);
3055
- },
3056
- onLoginSuccess: (tokens) => {
3057
- setState((prev) => ({
3058
- ...prev,
3059
- isAuthenticated: true,
3060
- tokens,
3061
- error: null
3062
- }));
3063
- },
3064
- onLogout: () => {
3065
- setState((prev) => ({
3066
- ...prev,
3067
- isAuthenticated: false,
3068
- tokens: null,
3069
- error: null
3070
- }));
3071
- }
3072
- };
3073
- await sessionManager.initialize(config);
3074
- sessionManager.setupResponseInterceptor();
3075
- const isAuth = sessionManager.isAuthenticated();
3076
- const tokenInfo = sessionManager.getTokenInfo();
3077
- setState((prev) => ({
3078
- ...prev,
3079
- isAuthenticated: isAuth,
3080
- isInitialized: true,
3081
- isLoading: false,
3082
- tokens: tokenInfo.crudifyTokens.accessToken ? {
3083
- accessToken: tokenInfo.crudifyTokens.accessToken,
3084
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
3085
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
3086
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
3087
- } : null
3088
- }));
3089
- } catch (error) {
3090
- setState((prev) => ({
3091
- ...prev,
3092
- isLoading: false,
3093
- isInitialized: true,
3094
- error: error instanceof Error ? error.message : "Initialization failed"
3095
- }));
3096
- }
3097
- }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
3098
- const login = useCallback2(async (email, password) => {
3099
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
3100
- try {
3101
- const result = await sessionManager.login(email, password);
3102
- if (result.success && result.tokens) {
3103
- setState((prev) => ({
3104
- ...prev,
3105
- isAuthenticated: true,
3106
- tokens: result.tokens,
3107
- isLoading: false,
3108
- error: null
3109
- }));
3110
- } else {
3111
- setState((prev) => ({
3112
- ...prev,
3113
- isAuthenticated: false,
3114
- tokens: null,
3115
- isLoading: false,
3116
- error: result.error || "Login failed"
3117
- }));
3118
- }
3119
- return result;
3120
- } catch (error) {
3121
- const errorMsg = error instanceof Error ? error.message : "Login failed";
3122
- setState((prev) => ({
3123
- ...prev,
3124
- isAuthenticated: false,
3125
- tokens: null,
3126
- isLoading: false,
3127
- error: errorMsg
3128
- }));
3129
- return {
3130
- success: false,
3131
- error: errorMsg
3132
- };
3133
- }
3134
- }, [sessionManager]);
3135
- const logout = useCallback2(async () => {
3136
- setState((prev) => ({ ...prev, isLoading: true }));
3137
- try {
3138
- await sessionManager.logout();
3139
- setState((prev) => ({
3140
- ...prev,
3141
- isAuthenticated: false,
3142
- tokens: null,
3143
- isLoading: false,
3144
- error: null
3145
- }));
3146
- } catch (error) {
3147
- setState((prev) => ({
3148
- ...prev,
3149
- isAuthenticated: false,
3150
- tokens: null,
3151
- isLoading: false,
3152
- error: error instanceof Error ? error.message : "Logout error"
3153
- }));
2741
+ // src/components/PublicPolicies/Policies.tsx
2742
+ import { useRef as useRef4 } from "react";
2743
+ import { useTranslation as useTranslation4 } from "react-i18next";
2744
+ import {
2745
+ Box as Box10,
2746
+ Typography as Typography10,
2747
+ Button as Button7,
2748
+ Stack as Stack3,
2749
+ Alert as Alert7,
2750
+ Divider as Divider3
2751
+ } from "@mui/material";
2752
+ import { Add } from "@mui/icons-material";
2753
+
2754
+ // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
2755
+ import { forwardRef } from "react";
2756
+ import { useTranslation as useTranslation3 } from "react-i18next";
2757
+ import {
2758
+ Box as Box9,
2759
+ FormControl,
2760
+ InputLabel,
2761
+ Select,
2762
+ MenuItem,
2763
+ IconButton as IconButton2,
2764
+ Typography as Typography9,
2765
+ FormHelperText as FormHelperText2,
2766
+ Stack as Stack2,
2767
+ Paper,
2768
+ Divider as Divider2,
2769
+ Button as Button6
2770
+ } from "@mui/material";
2771
+ import { Delete, SelectAll as SelectAll2, ClearAll as ClearAll2 } from "@mui/icons-material";
2772
+
2773
+ // src/components/PublicPolicies/FieldSelector/FieldSelector.tsx
2774
+ import { useState as useState9, useEffect as useEffect9, useRef as useRef3 } from "react";
2775
+ import { useTranslation as useTranslation2 } from "react-i18next";
2776
+ import {
2777
+ Box as Box8,
2778
+ Typography as Typography8,
2779
+ Button as Button5,
2780
+ Stack,
2781
+ FormHelperText,
2782
+ ToggleButton,
2783
+ ToggleButtonGroup
2784
+ } from "@mui/material";
2785
+ import {
2786
+ CheckCircle,
2787
+ Cancel,
2788
+ SelectAll,
2789
+ ClearAll
2790
+ } from "@mui/icons-material";
2791
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2792
+ var FieldSelector = ({
2793
+ value,
2794
+ onChange,
2795
+ availableFields,
2796
+ error,
2797
+ disabled = false
2798
+ }) => {
2799
+ const { t } = useTranslation2();
2800
+ const [mode, setMode] = useState9("custom");
2801
+ const isUpdatingRef = useRef3(false);
2802
+ useEffect9(() => {
2803
+ const current = value || { allow: [], owner_allow: [], deny: [] };
2804
+ const all = new Set(availableFields);
2805
+ const allow = (current.allow || []).filter((f) => all.has(f));
2806
+ const owner = (current.owner_allow || []).filter((f) => all.has(f));
2807
+ const deny = (current.deny || []).filter((f) => all.has(f));
2808
+ availableFields.forEach((f) => {
2809
+ if (!allow.includes(f) && !owner.includes(f) && !deny.includes(f)) deny.push(f);
2810
+ });
2811
+ const normalized = { allow, owner_allow: owner, deny };
2812
+ if (JSON.stringify(normalized) !== JSON.stringify(current)) {
2813
+ onChange(normalized);
3154
2814
  }
3155
- }, [sessionManager]);
3156
- const refreshTokens = useCallback2(async () => {
3157
- try {
3158
- const success = await sessionManager.refreshTokens();
3159
- if (success) {
3160
- const tokenInfo = sessionManager.getTokenInfo();
3161
- setState((prev) => ({
3162
- ...prev,
3163
- tokens: tokenInfo.crudifyTokens.accessToken ? {
3164
- accessToken: tokenInfo.crudifyTokens.accessToken,
3165
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
3166
- expiresAt: tokenInfo.crudifyTokens.expiresAt,
3167
- refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
3168
- } : null,
3169
- error: null
3170
- }));
3171
- } else {
3172
- setState((prev) => ({
3173
- ...prev,
3174
- isAuthenticated: false,
3175
- tokens: null,
3176
- error: "Token refresh failed"
3177
- }));
3178
- }
3179
- return success;
3180
- } catch (error) {
3181
- setState((prev) => ({
3182
- ...prev,
3183
- isAuthenticated: false,
3184
- tokens: null,
3185
- error: error instanceof Error ? error.message : "Token refresh failed"
3186
- }));
3187
- return false;
2815
+ if (allow.length === availableFields.length) setMode("all");
2816
+ else if (deny.length === availableFields.length) setMode("none");
2817
+ else setMode("custom");
2818
+ }, [availableFields, value]);
2819
+ const setAllAllow = () => {
2820
+ isUpdatingRef.current = true;
2821
+ onChange({ allow: [...availableFields], owner_allow: [], deny: [] });
2822
+ setMode("all");
2823
+ setTimeout(() => {
2824
+ isUpdatingRef.current = false;
2825
+ }, 0);
2826
+ };
2827
+ const setAllDeny = () => {
2828
+ isUpdatingRef.current = true;
2829
+ onChange({ allow: [], owner_allow: [], deny: [...availableFields] });
2830
+ setMode("none");
2831
+ setTimeout(() => {
2832
+ isUpdatingRef.current = false;
2833
+ }, 0);
2834
+ };
2835
+ const getFieldState = (fieldName) => {
2836
+ if (value?.allow?.includes(fieldName)) return "allow";
2837
+ if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
2838
+ return "deny";
2839
+ };
2840
+ const setFieldState = (fieldName, state) => {
2841
+ isUpdatingRef.current = true;
2842
+ const allow = new Set(value?.allow || []);
2843
+ const owner = new Set(value?.owner_allow || []);
2844
+ const deny = new Set(value?.deny || []);
2845
+ allow.delete(fieldName);
2846
+ owner.delete(fieldName);
2847
+ deny.delete(fieldName);
2848
+ if (state === "allow") allow.add(fieldName);
2849
+ if (state === "owner_allow") owner.add(fieldName);
2850
+ if (state === "deny") deny.add(fieldName);
2851
+ onChange({ allow: Array.from(allow), owner_allow: Array.from(owner), deny: Array.from(deny) });
2852
+ setMode("custom");
2853
+ setTimeout(() => {
2854
+ isUpdatingRef.current = false;
2855
+ }, 0);
2856
+ };
2857
+ if (availableFields.length === 0) {
2858
+ return /* @__PURE__ */ jsxs9(Box8, { children: [
2859
+ /* @__PURE__ */ jsx12(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
2860
+ /* @__PURE__ */ jsx12(Typography8, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: t("modules.form.publicPolicies.fields.conditions.noFieldsAvailable") }),
2861
+ error && /* @__PURE__ */ jsx12(FormHelperText, { error: true, sx: { mt: 1 }, children: error })
2862
+ ] });
2863
+ }
2864
+ return /* @__PURE__ */ jsxs9(Box8, { children: [
2865
+ /* @__PURE__ */ jsx12(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
2866
+ /* @__PURE__ */ jsxs9(Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
2867
+ /* @__PURE__ */ jsx12(
2868
+ Button5,
2869
+ {
2870
+ variant: mode === "all" ? "contained" : "outlined",
2871
+ startIcon: /* @__PURE__ */ jsx12(SelectAll, {}),
2872
+ onClick: setAllAllow,
2873
+ disabled,
2874
+ size: "small",
2875
+ sx: {
2876
+ minWidth: 120,
2877
+ ...mode === "all" && {
2878
+ backgroundColor: "#16a34a",
2879
+ "&:hover": { backgroundColor: "#15803d" }
2880
+ }
2881
+ },
2882
+ children: t("modules.form.publicPolicies.fields.conditions.allFields")
2883
+ }
2884
+ ),
2885
+ /* @__PURE__ */ jsx12(
2886
+ Button5,
2887
+ {
2888
+ variant: mode === "none" ? "contained" : "outlined",
2889
+ startIcon: /* @__PURE__ */ jsx12(ClearAll, {}),
2890
+ onClick: setAllDeny,
2891
+ disabled,
2892
+ size: "small",
2893
+ sx: {
2894
+ minWidth: 120,
2895
+ ...mode === "none" && {
2896
+ backgroundColor: "#cf222e",
2897
+ "&:hover": { backgroundColor: "#bc1f2c" }
2898
+ }
2899
+ },
2900
+ children: t("modules.form.publicPolicies.fields.conditions.noFields")
2901
+ }
2902
+ )
2903
+ ] }),
2904
+ /* @__PURE__ */ jsxs9(Box8, { sx: { p: 2, border: "1px solid #d1d9e0", borderRadius: 1, backgroundColor: "#f6f8fa" }, children: [
2905
+ /* @__PURE__ */ jsx12(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.help") }),
2906
+ /* @__PURE__ */ jsx12(Stack, { spacing: 1, children: availableFields.map((fieldName) => {
2907
+ const fieldState = getFieldState(fieldName);
2908
+ return /* @__PURE__ */ jsxs9(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
2909
+ /* @__PURE__ */ jsx12(Typography8, { variant: "body2", sx: { minWidth: 100, fontFamily: "monospace" }, children: fieldName }),
2910
+ /* @__PURE__ */ jsxs9(ToggleButtonGroup, { value: fieldState, exclusive: true, size: "small", children: [
2911
+ /* @__PURE__ */ jsxs9(
2912
+ ToggleButton,
2913
+ {
2914
+ value: "allow",
2915
+ onClick: () => setFieldState(fieldName, "allow"),
2916
+ disabled,
2917
+ sx: {
2918
+ px: 2,
2919
+ color: fieldState === "allow" ? "#ffffff" : "#6b7280",
2920
+ backgroundColor: fieldState === "allow" ? "#16a34a" : "#f3f4f6",
2921
+ borderColor: fieldState === "allow" ? "#16a34a" : "#d1d5db",
2922
+ "&:hover": {
2923
+ backgroundColor: fieldState === "allow" ? "#15803d" : "#e5e7eb",
2924
+ borderColor: fieldState === "allow" ? "#15803d" : "#9ca3af"
2925
+ },
2926
+ "&.Mui-selected": {
2927
+ backgroundColor: "#16a34a",
2928
+ color: "#ffffff",
2929
+ "&:hover": {
2930
+ backgroundColor: "#15803d"
2931
+ }
2932
+ }
2933
+ },
2934
+ children: [
2935
+ /* @__PURE__ */ jsx12(CheckCircle, { sx: { fontSize: 16, mr: 0.5 } }),
2936
+ t("modules.form.publicPolicies.fields.conditions.states.allow")
2937
+ ]
2938
+ }
2939
+ ),
2940
+ /* @__PURE__ */ jsx12(
2941
+ ToggleButton,
2942
+ {
2943
+ value: "owner_allow",
2944
+ onClick: () => setFieldState(fieldName, "owner_allow"),
2945
+ disabled,
2946
+ sx: {
2947
+ px: 2,
2948
+ color: fieldState === "owner_allow" ? "#ffffff" : "#6b7280",
2949
+ backgroundColor: fieldState === "owner_allow" ? "#0ea5e9" : "#f3f4f6",
2950
+ borderColor: fieldState === "owner_allow" ? "#0ea5e9" : "#d1d5db",
2951
+ "&:hover": {
2952
+ backgroundColor: fieldState === "owner_allow" ? "#0284c7" : "#e5e7eb",
2953
+ borderColor: fieldState === "owner_allow" ? "#0284c7" : "#9ca3af"
2954
+ },
2955
+ "&.Mui-selected": {
2956
+ backgroundColor: "#0ea5e9",
2957
+ color: "#ffffff",
2958
+ "&:hover": {
2959
+ backgroundColor: "#0284c7"
2960
+ }
2961
+ }
2962
+ },
2963
+ children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
2964
+ }
2965
+ ),
2966
+ /* @__PURE__ */ jsxs9(
2967
+ ToggleButton,
2968
+ {
2969
+ value: "deny",
2970
+ onClick: () => setFieldState(fieldName, "deny"),
2971
+ disabled,
2972
+ sx: {
2973
+ px: 2,
2974
+ color: fieldState === "deny" ? "#ffffff" : "#6b7280",
2975
+ backgroundColor: fieldState === "deny" ? "#dc2626" : "#f3f4f6",
2976
+ borderColor: fieldState === "deny" ? "#dc2626" : "#d1d5db",
2977
+ "&:hover": {
2978
+ backgroundColor: fieldState === "deny" ? "#b91c1c" : "#e5e7eb",
2979
+ borderColor: fieldState === "deny" ? "#b91c1c" : "#9ca3af"
2980
+ },
2981
+ "&.Mui-selected": {
2982
+ backgroundColor: "#dc2626",
2983
+ color: "#ffffff",
2984
+ "&:hover": {
2985
+ backgroundColor: "#b91c1c"
2986
+ }
2987
+ }
2988
+ },
2989
+ children: [
2990
+ /* @__PURE__ */ jsx12(Cancel, { sx: { fontSize: 16, mr: 0.5 } }),
2991
+ t("modules.form.publicPolicies.fields.conditions.states.deny")
2992
+ ]
2993
+ }
2994
+ )
2995
+ ] })
2996
+ ] }, fieldName);
2997
+ }) })
2998
+ ] }),
2999
+ error && /* @__PURE__ */ jsx12(FormHelperText, { error: true, sx: { mt: 1 }, children: error })
3000
+ ] });
3001
+ };
3002
+ var FieldSelector_default = FieldSelector;
3003
+
3004
+ // src/components/PublicPolicies/constants.ts
3005
+ var POLICY_ACTIONS = ["create", "read", "update", "delete"];
3006
+ var PREFERRED_POLICY_ORDER = [
3007
+ "create",
3008
+ "read",
3009
+ "update",
3010
+ "delete"
3011
+ ];
3012
+
3013
+ // src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
3014
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3015
+ var PolicyItem = forwardRef(({
3016
+ policy,
3017
+ onChange,
3018
+ onRemove,
3019
+ availableFields,
3020
+ isSubmitting = false,
3021
+ usedActions,
3022
+ error
3023
+ }, ref) => {
3024
+ const { t } = useTranslation3();
3025
+ const takenActions = new Set(Array.from(usedActions || []));
3026
+ takenActions.delete(policy.action);
3027
+ const actionOptions = POLICY_ACTIONS.map((a) => ({
3028
+ value: a,
3029
+ label: t(`modules.form.publicPolicies.fields.action.options.${a}`)
3030
+ }));
3031
+ return /* @__PURE__ */ jsxs10(
3032
+ Paper,
3033
+ {
3034
+ ref,
3035
+ sx: {
3036
+ p: 3,
3037
+ border: "1px solid #d1d9e0",
3038
+ borderRadius: 2,
3039
+ position: "relative",
3040
+ backgroundColor: "#ffffff"
3041
+ },
3042
+ children: [
3043
+ /* @__PURE__ */ jsxs10(Box9, { sx: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", mb: 3 }, children: [
3044
+ /* @__PURE__ */ jsx13(
3045
+ Typography9,
3046
+ {
3047
+ variant: "subtitle1",
3048
+ sx: {
3049
+ fontWeight: 600,
3050
+ color: "#111418",
3051
+ fontSize: "1rem"
3052
+ },
3053
+ children: t("modules.form.publicPolicies.policyTitle")
3054
+ }
3055
+ ),
3056
+ /* @__PURE__ */ jsx13(
3057
+ IconButton2,
3058
+ {
3059
+ onClick: onRemove,
3060
+ size: "small",
3061
+ disabled: isSubmitting,
3062
+ "aria-label": t("modules.form.publicPolicies.removePolicy"),
3063
+ sx: {
3064
+ color: "#656d76",
3065
+ "&:hover": {
3066
+ color: "#cf222e",
3067
+ backgroundColor: "rgba(207, 34, 46, 0.1)"
3068
+ }
3069
+ },
3070
+ children: /* @__PURE__ */ jsx13(Delete, {})
3071
+ }
3072
+ )
3073
+ ] }),
3074
+ /* @__PURE__ */ jsxs10(Stack2, { spacing: 3, children: [
3075
+ /* @__PURE__ */ jsx13(Stack2, { direction: { xs: "column", md: "row" }, spacing: 2, children: /* @__PURE__ */ jsx13(Box9, { sx: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxs10(FormControl, { fullWidth: true, children: [
3076
+ /* @__PURE__ */ jsx13(InputLabel, { children: t("modules.form.publicPolicies.fields.action.label") }),
3077
+ /* @__PURE__ */ jsx13(
3078
+ Select,
3079
+ {
3080
+ value: policy.action,
3081
+ label: t("modules.form.publicPolicies.fields.action.label"),
3082
+ disabled: isSubmitting,
3083
+ onChange: (e) => {
3084
+ const newAction = e.target.value;
3085
+ const next = { ...policy, action: newAction };
3086
+ if (newAction === "delete") {
3087
+ next.permission = "deny";
3088
+ delete next.fields;
3089
+ } else {
3090
+ next.fields = { allow: [], owner_allow: [], deny: availableFields };
3091
+ delete next.permission;
3092
+ }
3093
+ onChange(next);
3094
+ },
3095
+ sx: {
3096
+ backgroundColor: "#ffffff",
3097
+ "&:hover .MuiOutlinedInput-notchedOutline": {
3098
+ borderColor: "#8c959f"
3099
+ },
3100
+ "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
3101
+ borderColor: "#0969da",
3102
+ borderWidth: 2
3103
+ }
3104
+ },
3105
+ children: actionOptions.map((option) => {
3106
+ const disabledOption = takenActions.has(option.value);
3107
+ return /* @__PURE__ */ jsx13(MenuItem, { value: option.value, disabled: disabledOption, children: option.label }, option.value);
3108
+ })
3109
+ }
3110
+ ),
3111
+ error && /* @__PURE__ */ jsx13(FormHelperText2, { error: true, children: error })
3112
+ ] }) }) }),
3113
+ policy.action === "delete" ? /* @__PURE__ */ jsxs10(Box9, { children: [
3114
+ /* @__PURE__ */ jsx13(Typography9, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
3115
+ /* @__PURE__ */ jsxs10(Stack2, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
3116
+ /* @__PURE__ */ jsx13(
3117
+ Button6,
3118
+ {
3119
+ variant: policy.permission === "*" ? "contained" : "outlined",
3120
+ startIcon: /* @__PURE__ */ jsx13(SelectAll2, {}),
3121
+ onClick: () => onChange({ ...policy, permission: "*" }),
3122
+ disabled: isSubmitting,
3123
+ size: "small",
3124
+ sx: {
3125
+ minWidth: 140,
3126
+ whiteSpace: "nowrap",
3127
+ ...policy.permission === "*" && {
3128
+ backgroundColor: "#16a34a",
3129
+ "&:hover": { backgroundColor: "#15803d" }
3130
+ }
3131
+ },
3132
+ children: t("modules.form.publicPolicies.fields.conditions.allFields")
3133
+ }
3134
+ ),
3135
+ /* @__PURE__ */ jsx13(
3136
+ Button6,
3137
+ {
3138
+ variant: policy.permission === "owner" ? "contained" : "outlined",
3139
+ onClick: () => onChange({ ...policy, permission: "owner" }),
3140
+ disabled: isSubmitting,
3141
+ size: "small",
3142
+ sx: {
3143
+ minWidth: 140,
3144
+ whiteSpace: "nowrap",
3145
+ ...policy.permission === "owner" && {
3146
+ backgroundColor: "#0ea5e9",
3147
+ "&:hover": { backgroundColor: "#0284c7" }
3148
+ }
3149
+ },
3150
+ children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
3151
+ }
3152
+ ),
3153
+ /* @__PURE__ */ jsx13(
3154
+ Button6,
3155
+ {
3156
+ variant: policy.permission === "deny" ? "contained" : "outlined",
3157
+ startIcon: /* @__PURE__ */ jsx13(ClearAll2, {}),
3158
+ onClick: () => onChange({ ...policy, permission: "deny" }),
3159
+ disabled: isSubmitting,
3160
+ size: "small",
3161
+ sx: {
3162
+ minWidth: 140,
3163
+ whiteSpace: "nowrap",
3164
+ ...policy.permission === "deny" && {
3165
+ backgroundColor: "#cf222e",
3166
+ "&:hover": { backgroundColor: "#bc1f2c" }
3167
+ }
3168
+ },
3169
+ children: t("modules.form.publicPolicies.fields.conditions.noFields")
3170
+ }
3171
+ )
3172
+ ] })
3173
+ ] }) : /* @__PURE__ */ jsx13(
3174
+ FieldSelector_default,
3175
+ {
3176
+ value: policy.fields || { allow: [], owner_allow: [], deny: [] },
3177
+ onChange: (nextFields) => onChange({ ...policy, fields: nextFields }),
3178
+ availableFields,
3179
+ disabled: isSubmitting
3180
+ }
3181
+ ),
3182
+ /* @__PURE__ */ jsx13(Paper, { variant: "outlined", sx: { p: 2, backgroundColor: "#f9fafb" }, children: policy.action === "delete" ? /* @__PURE__ */ jsxs10(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3183
+ /* @__PURE__ */ jsxs10(Box9, { component: "span", sx: {
3184
+ color: policy.permission === "*" ? "#16a34a" : policy.permission === "owner" ? "#0ea5e9" : "#dc2626"
3185
+ }, children: [
3186
+ t("modules.form.publicPolicies.fields.conditions.states.allow"),
3187
+ ":"
3188
+ ] }),
3189
+ " ",
3190
+ policy.permission || "-"
3191
+ ] }) : /* @__PURE__ */ jsxs10(Stack2, { spacing: 0.5, divider: /* @__PURE__ */ jsx13(Divider2, { sx: { borderColor: "#e5e7eb" } }), children: [
3192
+ /* @__PURE__ */ jsxs10(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3193
+ /* @__PURE__ */ jsxs10(Box9, { component: "span", sx: { color: "#16a34a" }, children: [
3194
+ t("modules.form.publicPolicies.fields.conditions.states.allow"),
3195
+ ":"
3196
+ ] }),
3197
+ " ",
3198
+ (policy?.fields?.allow || []).join(", ") || "-"
3199
+ ] }),
3200
+ /* @__PURE__ */ jsxs10(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3201
+ /* @__PURE__ */ jsxs10(Box9, { component: "span", sx: { color: "#0ea5e9" }, children: [
3202
+ t("modules.form.publicPolicies.fields.conditions.states.ownerAllow"),
3203
+ ":"
3204
+ ] }),
3205
+ " ",
3206
+ (policy?.fields?.owner_allow || []).join(", ") || "-"
3207
+ ] }),
3208
+ /* @__PURE__ */ jsxs10(Typography9, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
3209
+ /* @__PURE__ */ jsxs10(Box9, { component: "span", sx: { color: "#dc2626" }, children: [
3210
+ t("modules.form.publicPolicies.fields.conditions.states.deny"),
3211
+ ":"
3212
+ ] }),
3213
+ " ",
3214
+ (policy?.fields?.deny || []).join(", ") || "-"
3215
+ ] })
3216
+ ] }) })
3217
+ ] })
3218
+ ]
3188
3219
  }
3189
- }, [sessionManager]);
3190
- const clearError = useCallback2(() => {
3191
- setState((prev) => ({ ...prev, error: null }));
3192
- }, []);
3193
- const getTokenInfo = useCallback2(() => {
3194
- return sessionManager.getTokenInfo();
3195
- }, [sessionManager]);
3196
- useEffect9(() => {
3197
- initialize();
3198
- }, [initialize]);
3199
- return {
3200
- // Estado
3201
- ...state,
3202
- // Acciones
3203
- login,
3204
- logout,
3205
- refreshTokens,
3206
- clearError,
3207
- getTokenInfo,
3208
- // Utilidades
3209
- isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
3210
- // 5 minutos
3211
- expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
3212
- refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
3213
- };
3214
- }
3220
+ );
3221
+ });
3222
+ var PolicyItem_default = PolicyItem;
3215
3223
 
3216
- // src/providers/SessionProvider.tsx
3217
- import { createContext as createContext4, useContext as useContext4, useMemo as useMemo3 } from "react";
3224
+ // src/components/PublicPolicies/Policies.tsx
3218
3225
  import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
3219
- var SessionContext = createContext4(void 0);
3220
- function SessionProvider({ children, options = {} }) {
3221
- const sessionHook = useSession(options);
3222
- const sessionData = useMemo3(() => {
3223
- if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
3224
- return null;
3226
+ var generateId = () => {
3227
+ const c = globalThis?.crypto;
3228
+ if (c && typeof c.randomUUID === "function") return c.randomUUID();
3229
+ return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
3230
+ };
3231
+ var Policies = ({
3232
+ policies,
3233
+ onChange,
3234
+ availableFields,
3235
+ errors,
3236
+ isSubmitting = false
3237
+ }) => {
3238
+ const { t } = useTranslation4();
3239
+ const policyRefs = useRef4({});
3240
+ const takenActions = new Set((policies || []).map((p) => p.action).filter(Boolean));
3241
+ const remainingActions = PREFERRED_POLICY_ORDER.filter((a) => !takenActions.has(a));
3242
+ const canAddPolicy = remainingActions.length > 0;
3243
+ const addPolicy = () => {
3244
+ const defaultAction = remainingActions[0] || "create";
3245
+ const newPolicy = {
3246
+ id: generateId(),
3247
+ action: defaultAction
3248
+ };
3249
+ if (defaultAction === "delete") {
3250
+ newPolicy.permission = "deny";
3251
+ } else {
3252
+ newPolicy.fields = {
3253
+ allow: [],
3254
+ owner_allow: [],
3255
+ deny: availableFields
3256
+ };
3225
3257
  }
3226
- try {
3227
- const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
3228
- if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
3229
- const result = {
3230
- _id: decoded.sub,
3231
- email: decoded.email,
3232
- subscriberKey: decoded.subscriber
3233
- };
3234
- Object.keys(decoded).forEach((key) => {
3235
- if (!["sub", "email", "subscriber"].includes(key)) {
3236
- result[key] = decoded[key];
3237
- }
3238
- });
3239
- return result;
3258
+ const next = [...policies || [], newPolicy];
3259
+ onChange(next);
3260
+ setTimeout(() => {
3261
+ const newIndex = next.length - 1;
3262
+ const el = policyRefs.current[newIndex];
3263
+ if (el) {
3264
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
3240
3265
  }
3241
- } catch (error) {
3242
- console.error("Error decoding JWT token for sessionData:", error);
3243
- }
3244
- return null;
3245
- }, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
3246
- const contextValue = {
3247
- ...sessionHook,
3248
- sessionData
3266
+ }, 100);
3249
3267
  };
3250
- return /* @__PURE__ */ jsx14(SessionContext.Provider, { value: contextValue, children });
3251
- }
3252
- function useSessionContext() {
3253
- const context = useContext4(SessionContext);
3254
- if (context === void 0) {
3255
- throw new Error("useSessionContext must be used within a SessionProvider");
3256
- }
3257
- return context;
3258
- }
3259
- function ProtectedRoute({
3260
- children,
3261
- fallback = /* @__PURE__ */ jsx14("div", { children: "Please log in to access this content" }),
3262
- redirectTo
3263
- }) {
3264
- const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
3265
- if (!isInitialized || isLoading) {
3266
- return /* @__PURE__ */ jsx14("div", { children: "Loading..." });
3267
- }
3268
- if (!isAuthenticated) {
3269
- if (redirectTo) {
3270
- redirectTo();
3271
- return null;
3272
- }
3273
- return /* @__PURE__ */ jsx14(Fragment8, { children: fallback });
3274
- }
3275
- return /* @__PURE__ */ jsx14(Fragment8, { children });
3276
- }
3277
- function SessionDebugInfo() {
3278
- const session = useSessionContext();
3279
- if (!session.isInitialized) {
3280
- return /* @__PURE__ */ jsx14("div", { children: "Session not initialized" });
3281
- }
3282
- return /* @__PURE__ */ jsxs11("div", { style: {
3283
- padding: "10px",
3284
- margin: "10px",
3285
- border: "1px solid #ccc",
3286
- borderRadius: "4px",
3287
- fontSize: "12px",
3288
- fontFamily: "monospace"
3289
- }, children: [
3290
- /* @__PURE__ */ jsx14("h4", { children: "Session Debug Info" }),
3291
- /* @__PURE__ */ jsxs11("div", { children: [
3292
- /* @__PURE__ */ jsx14("strong", { children: "Authenticated:" }),
3293
- " ",
3294
- session.isAuthenticated ? "Yes" : "No"
3295
- ] }),
3296
- /* @__PURE__ */ jsxs11("div", { children: [
3297
- /* @__PURE__ */ jsx14("strong", { children: "Loading:" }),
3298
- " ",
3299
- session.isLoading ? "Yes" : "No"
3300
- ] }),
3301
- /* @__PURE__ */ jsxs11("div", { children: [
3302
- /* @__PURE__ */ jsx14("strong", { children: "Error:" }),
3303
- " ",
3304
- session.error || "None"
3305
- ] }),
3306
- session.tokens && /* @__PURE__ */ jsxs11(Fragment8, { children: [
3307
- /* @__PURE__ */ jsxs11("div", { children: [
3308
- /* @__PURE__ */ jsx14("strong", { children: "Access Token:" }),
3309
- " ",
3310
- session.tokens.accessToken.substring(0, 20),
3311
- "..."
3312
- ] }),
3313
- /* @__PURE__ */ jsxs11("div", { children: [
3314
- /* @__PURE__ */ jsx14("strong", { children: "Refresh Token:" }),
3315
- " ",
3316
- session.tokens.refreshToken.substring(0, 20),
3317
- "..."
3318
- ] }),
3319
- /* @__PURE__ */ jsxs11("div", { children: [
3320
- /* @__PURE__ */ jsx14("strong", { children: "Access Expires In:" }),
3321
- " ",
3322
- Math.round(session.expiresIn / 1e3 / 60),
3323
- " minutes"
3324
- ] }),
3325
- /* @__PURE__ */ jsxs11("div", { children: [
3326
- /* @__PURE__ */ jsx14("strong", { children: "Refresh Expires In:" }),
3327
- " ",
3328
- Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
3329
- " hours"
3330
- ] }),
3331
- /* @__PURE__ */ jsxs11("div", { children: [
3332
- /* @__PURE__ */ jsx14("strong", { children: "Expiring Soon:" }),
3333
- " ",
3334
- session.isExpiringSoon ? "Yes" : "No"
3268
+ const removePolicy = (index) => {
3269
+ const next = [...policies];
3270
+ next.splice(index, 1);
3271
+ onChange(next);
3272
+ };
3273
+ const arrayError = (() => {
3274
+ if (!errors) return null;
3275
+ if (typeof errors === "string") return errors;
3276
+ const msg = errors._error;
3277
+ return typeof msg === "string" ? msg : null;
3278
+ })();
3279
+ const usedActions = new Set((policies || []).map((p) => p.action));
3280
+ return /* @__PURE__ */ jsxs11(Fragment8, { children: [
3281
+ /* @__PURE__ */ jsx14(Divider3, { sx: { borderColor: "#e0e4e7" } }),
3282
+ /* @__PURE__ */ jsxs11(Box10, { children: [
3283
+ /* @__PURE__ */ jsx14(Box10, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3, children: /* @__PURE__ */ jsxs11(Box10, { children: [
3284
+ /* @__PURE__ */ jsx14(
3285
+ Typography10,
3286
+ {
3287
+ variant: "h6",
3288
+ sx: {
3289
+ fontWeight: 600,
3290
+ color: "#111418",
3291
+ mb: 1
3292
+ },
3293
+ children: t("modules.form.publicPolicies.title")
3294
+ }
3295
+ ),
3296
+ /* @__PURE__ */ jsx14(
3297
+ Typography10,
3298
+ {
3299
+ variant: "body2",
3300
+ color: "text.secondary",
3301
+ sx: { fontSize: "0.875rem" },
3302
+ children: t("modules.form.publicPolicies.description")
3303
+ }
3304
+ )
3305
+ ] }) }),
3306
+ arrayError && /* @__PURE__ */ jsx14(Alert7, { severity: "error", sx: { mb: 3 }, children: arrayError }),
3307
+ /* @__PURE__ */ jsxs11(Stack3, { spacing: 3, children: [
3308
+ (policies || []).length === 0 ? /* @__PURE__ */ jsx14(Alert7, { severity: "info", children: t("modules.form.publicPolicies.noPolicies") }) : policies.map((policy, index) => /* @__PURE__ */ jsx14(
3309
+ PolicyItem_default,
3310
+ {
3311
+ ref: (el) => {
3312
+ policyRefs.current[index] = el;
3313
+ },
3314
+ policy,
3315
+ onChange: (nextPolicy) => {
3316
+ const next = [...policies];
3317
+ next[index] = nextPolicy;
3318
+ onChange(next);
3319
+ },
3320
+ onRemove: () => removePolicy(index),
3321
+ availableFields,
3322
+ isSubmitting,
3323
+ usedActions,
3324
+ error: typeof errors === "object" && errors && policy.id in errors ? errors[policy.id] : void 0
3325
+ },
3326
+ policy.id
3327
+ )),
3328
+ canAddPolicy && /* @__PURE__ */ jsx14(Box10, { children: /* @__PURE__ */ jsx14(
3329
+ Button7,
3330
+ {
3331
+ type: "button",
3332
+ variant: "outlined",
3333
+ startIcon: /* @__PURE__ */ jsx14(Add, {}),
3334
+ onClick: addPolicy,
3335
+ disabled: isSubmitting,
3336
+ sx: {
3337
+ borderColor: "#d0d7de",
3338
+ color: "#656d76",
3339
+ "&:hover": {
3340
+ borderColor: "#8c959f",
3341
+ backgroundColor: "transparent"
3342
+ }
3343
+ },
3344
+ children: t("modules.form.publicPolicies.addPolicy")
3345
+ }
3346
+ ) })
3335
3347
  ] })
3336
3348
  ] })
3337
3349
  ] });
3338
- }
3350
+ };
3351
+ var Policies_default = Policies;
3339
3352
 
3340
3353
  // src/components/LoginComponent.tsx
3341
3354
  import { useState as useState10 } from "react";
@@ -3492,7 +3505,7 @@ function SessionStatus() {
3492
3505
 
3493
3506
  // src/hooks/useUserData.ts
3494
3507
  import { useState as useState11, useEffect as useEffect10, useCallback as useCallback3, useRef as useRef5 } from "react";
3495
- import crudify5 from "@nocios/crudify-browser";
3508
+ import crudify4 from "@nocios/crudify-browser";
3496
3509
  var useUserData = (options = {}) => {
3497
3510
  const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
3498
3511
  const { isAuthenticated, isInitialized, sessionData, tokens } = useSessionContext();
@@ -3542,7 +3555,7 @@ var useUserData = (options = {}) => {
3542
3555
  setError(null);
3543
3556
  }
3544
3557
  console.log("\u{1F464} useUserData - Fetching profile data from database");
3545
- const response = await crudify5.readItems("users", {
3558
+ const response = await crudify4.readItems("users", {
3546
3559
  filter: { email: userEmail },
3547
3560
  pagination: { limit: 1 }
3548
3561
  });
@@ -3732,7 +3745,7 @@ var useAuth = () => {
3732
3745
 
3733
3746
  // src/hooks/useData.ts
3734
3747
  import { useCallback as useCallback5 } from "react";
3735
- import crudify6 from "@nocios/crudify-browser";
3748
+ import crudify5 from "@nocios/crudify-browser";
3736
3749
  var useData = () => {
3737
3750
  const {
3738
3751
  isInitialized,
@@ -3765,27 +3778,27 @@ var useData = () => {
3765
3778
  }, [isReady]);
3766
3779
  const readItems = useCallback5(async (moduleKey, filter, options) => {
3767
3780
  await ensureReady();
3768
- return await crudify6.readItems(moduleKey, filter || {}, options);
3781
+ return await crudify5.readItems(moduleKey, filter || {}, options);
3769
3782
  }, [ensureReady]);
3770
3783
  const readItem = useCallback5(async (moduleKey, filter, options) => {
3771
3784
  await ensureReady();
3772
- return await crudify6.readItem(moduleKey, filter, options);
3785
+ return await crudify5.readItem(moduleKey, filter, options);
3773
3786
  }, [ensureReady]);
3774
3787
  const createItem = useCallback5(async (moduleKey, data, options) => {
3775
3788
  await ensureReady();
3776
- return await crudify6.createItem(moduleKey, data, options);
3789
+ return await crudify5.createItem(moduleKey, data, options);
3777
3790
  }, [ensureReady]);
3778
3791
  const updateItem = useCallback5(async (moduleKey, data, options) => {
3779
3792
  await ensureReady();
3780
- return await crudify6.updateItem(moduleKey, data, options);
3793
+ return await crudify5.updateItem(moduleKey, data, options);
3781
3794
  }, [ensureReady]);
3782
3795
  const deleteItem = useCallback5(async (moduleKey, id, options) => {
3783
3796
  await ensureReady();
3784
- return await crudify6.deleteItem(moduleKey, id, options);
3797
+ return await crudify5.deleteItem(moduleKey, id, options);
3785
3798
  }, [ensureReady]);
3786
3799
  const transaction = useCallback5(async (operations, options) => {
3787
3800
  await ensureReady();
3788
- return await crudify6.transaction(operations, options);
3801
+ return await crudify5.transaction(operations, options);
3789
3802
  }, [ensureReady]);
3790
3803
  const login = useCallback5(async (email, password) => {
3791
3804
  try {