diff --git a/dist/index.js b/dist/index.js index 8983813..599f4b8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,55 +1,55 @@ -import { jsxs as I, jsx as a } from "react/jsx-runtime"; -import { useState as B, useRef as z, useEffect as C, useCallback as E, createContext as G, useMemo as R, useContext as Z } from "react"; -import { HStack as k, IconButton as D, Button as V, Input as W, Text as S } from "@chakra-ui/react"; -import { IoChevronForwardOutline as O, IoChevronBackOutline as q } from "react-icons/io5"; -import P from "keycloak-js"; -import { useQuery as ee } from "@tanstack/react-query"; -import te from "axios"; -const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => String(e).replace(/\d/g, (t) => "۰۱۲۳۴۵۶۷۸۹"[Number(t)]), K = (e) => String(e).replace(/[۰-۹]/g, (r) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(r))), Ce = ({ +import { jsxs as B, jsx as a, Fragment as Z } from "react/jsx-runtime"; +import { useState as v, useRef as N, useEffect as C, useCallback as E, createContext as $, useMemo as z, useContext as P } from "react"; +import { HStack as I, IconButton as D, Button as L, Input as U, Text as S, Spinner as ee } from "@chakra-ui/react"; +import { IoChevronForwardOutline as g, IoChevronBackOutline as O } from "react-icons/io5"; +import te from "keycloak-js"; +import { useQuery as ne } from "@tanstack/react-query"; +import re from "axios"; +const Ee = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => String(e).replace(/\d/g, (t) => "۰۱۲۳۴۵۶۷۸۹"[Number(t)]), K = (e) => String(e).replace(/[۰-۹]/g, (n) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(n))), Ke = ({ currentPage: e, totalPages: t, - totalCount: r, - onPageChange: l + totalCount: n, + onPageChange: s }) => { - const [c, i] = B(p(e)), [u, o] = B(!1), [f, s] = B(null), w = z(null), y = [.../* @__PURE__ */ new Set([1, e, t])].filter( - (n) => n >= 1 && n <= t + const [c, l] = v(p(e)), [i, o] = v(!1), [f, u] = v(null), w = N(null), y = [.../* @__PURE__ */ new Set([1, e, t])].filter( + (r) => r >= 1 && r <= t ); C(() => { if (f !== null) { - e === f && (s(null), o(!1), i(p(e))); + e === f && (u(null), o(!1), l(p(e))); return; } - u || i(p(e)); - }, [e, u, f]), C(() => { - if (!u || !c || f !== null) return; - const n = parseInt(K(c), 10); - if (isNaN(n)) return; + i || l(p(e)); + }, [e, i, f]), C(() => { + if (!i || !c || f !== null) return; + const r = parseInt(K(c), 10); + if (isNaN(r)) return; const h = setTimeout(() => { var b; - const m = Math.min(Math.max(n, 1), t); - m !== e ? (s(m), i(p(m)), l(m)) : (o(!1), i(p(e))), (b = w.current) == null || b.blur(); + const m = Math.min(Math.max(r, 1), t); + m !== e ? (u(m), l(p(m)), s(m)) : (o(!1), l(p(e))), (b = w.current) == null || b.blur(); }, 1e3); return () => clearTimeout(h); }, [ c, - u, + i, f, t, e, - l + s ]); - const v = () => { + const A = () => { var m, b; - const n = parseInt(K(c), 10); - if (isNaN(n)) { - i(p(e)), o(!1), s(null), (m = w.current) == null || m.blur(); + const r = parseInt(K(c), 10); + if (isNaN(r)) { + l(p(e)), o(!1), u(null), (m = w.current) == null || m.blur(); return; } - const h = Math.min(Math.max(n, 1), t); - h !== e ? (s(h), i(p(h)), l(h)) : (i(p(e)), o(!1), s(null)), (b = w.current) == null || b.blur(); + const h = Math.min(Math.max(r, 1), t); + h !== e ? (u(h), l(p(h)), s(h)) : (l(p(e)), o(!1), u(null)), (b = w.current) == null || b.blur(); }; - return t === 0 || !r ? null : /* @__PURE__ */ I( - k, + return t === 0 || !n ? null : /* @__PURE__ */ B( + I, { justifyContent: "space-around", backgroundColor: "white", @@ -60,7 +60,7 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S borderColor: "blue.200", w: "100%", children: [ - /* @__PURE__ */ I(k, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + /* @__PURE__ */ B(I, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ /* @__PURE__ */ a( D, { @@ -68,25 +68,25 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => l(e - 1), + onClick: () => s(e - 1), isDisabled: e === 1, - icon: /* @__PURE__ */ a(O, {}), + icon: /* @__PURE__ */ a(g, {}), "aria-label": "صفحه قبلی" } ), - y.map((n) => /* @__PURE__ */ a( - V, + y.map((r) => /* @__PURE__ */ a( + L, { size: "md", px: 2, - bg: e === n ? "#4B49AC" : "#e6e6f1", - color: e === n ? "#e6e6f1" : "#4B49AC", - _hover: { bg: e === n ? "#4B49AC" : "#cbcbe8" }, - onClick: () => l(n), + bg: e === r ? "#4B49AC" : "#e6e6f1", + color: e === r ? "#e6e6f1" : "#4B49AC", + _hover: { bg: e === r ? "#4B49AC" : "#cbcbe8" }, + onClick: () => s(r), variant: "soft", - children: p(n) + children: p(r) }, - n + r )), /* @__PURE__ */ a( D, @@ -95,14 +95,14 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => l(e + 1), + onClick: () => s(e + 1), isDisabled: e === t, - icon: /* @__PURE__ */ a(q, {}), + icon: /* @__PURE__ */ a(O, {}), "aria-label": "صفحه بعدی" } ), /* @__PURE__ */ a( - W, + U, { ref: w, type: "text", @@ -111,17 +111,17 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S w: "56px", value: c, onFocus: () => { - o(!0), s(null), i(""); + o(!0), u(null), l(""); }, - onChange: (n) => { - const h = n.target.value, m = K(h).replace(/\D/g, ""); - i(p(m)); + onChange: (r) => { + const h = r.target.value, m = K(h).replace(/\D/g, ""); + l(p(m)); }, onBlur: () => { - c || (i(p(e)), o(!1), s(null)); + c || (l(p(e)), o(!1), u(null)); }, - onKeyDown: (n) => { - n.key === "Enter" && v(); + onKeyDown: (r) => { + r.key === "Enter" && A(); }, textAlign: "center", color: "#1D2939", @@ -131,58 +131,58 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S } ) ] }), - /* @__PURE__ */ I(k, { spacing: 2, children: [ + /* @__PURE__ */ B(I, { spacing: 2, children: [ /* @__PURE__ */ a(S, { w: "auto", fontWeight: "bold", whiteSpace: "nowrap", children: "تعداد کل:" }), - /* @__PURE__ */ a(S, { children: p(r) }) + /* @__PURE__ */ a(S, { children: p(n) }) ] }) ] } ); -}, ke = ({ +}, De = ({ currentPage: e, totalPages: t, - totalCount: r, - onPageChange: l + totalCount: n, + onPageChange: s }) => { - const [c, i] = B(p(e)), [u, o] = B(!1), [f, s] = B(null), w = z(null), y = Array.from( + const [c, l] = v(p(e)), [i, o] = v(!1), [f, u] = v(null), w = N(null), y = Array.from( /* @__PURE__ */ new Set([1, e, e + 1, t]) - ).filter((n) => n >= 1 && n <= t).sort((n, h) => n - h); + ).filter((r) => r >= 1 && r <= t).sort((r, h) => r - h); C(() => { if (f !== null) { - e === f && (s(null), o(!1), i(p(e))); + e === f && (u(null), o(!1), l(p(e))); return; } - u || i(p(e)); - }, [e, u, f]), C(() => { - if (!u || !c || f !== null) return; - const n = parseInt(K(c), 10); - if (isNaN(n)) return; + i || l(p(e)); + }, [e, i, f]), C(() => { + if (!i || !c || f !== null) return; + const r = parseInt(K(c), 10); + if (isNaN(r)) return; const h = setTimeout(() => { var b; - const m = Math.min(Math.max(n, 1), t); - m !== e ? (s(m), i(p(m)), l(m)) : (o(!1), i(p(e))), (b = w.current) == null || b.blur(); + const m = Math.min(Math.max(r, 1), t); + m !== e ? (u(m), l(p(m)), s(m)) : (o(!1), l(p(e))), (b = w.current) == null || b.blur(); }, 1e3); return () => clearTimeout(h); }, [ c, - u, + i, f, t, e, - l + s ]); - const v = () => { + const A = () => { var m, b; - const n = parseInt(K(c), 10); - if (isNaN(n)) { - i(p(e)), o(!1), s(null), (m = w.current) == null || m.blur(); + const r = parseInt(K(c), 10); + if (isNaN(r)) { + l(p(e)), o(!1), u(null), (m = w.current) == null || m.blur(); return; } - const h = Math.min(Math.max(n, 1), t); - h !== e ? (s(h), i(p(h)), l(h)) : (i(p(e)), o(!1), s(null)), (b = w.current) == null || b.blur(); + const h = Math.min(Math.max(r, 1), t); + h !== e ? (u(h), l(p(h)), s(h)) : (l(p(e)), o(!1), u(null)), (b = w.current) == null || b.blur(); }; - return t === 0 || !r ? null : /* @__PURE__ */ I( - k, + return t === 0 || !n ? null : /* @__PURE__ */ B( + I, { justifyContent: "space-around", backgroundColor: "white", @@ -193,13 +193,13 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S borderColor: "blue.200", w: "100%", children: [ - /* @__PURE__ */ I(k, { spacing: 2, whiteSpace: "nowrap", children: [ + /* @__PURE__ */ B(I, { spacing: 2, whiteSpace: "nowrap", children: [ /* @__PURE__ */ a(S, { fontWeight: "bold", children: "صفحه" }), /* @__PURE__ */ a(S, { children: p(e) }), /* @__PURE__ */ a(S, { fontWeight: "bold", children: "از" }), /* @__PURE__ */ a(S, { children: p(t) }) ] }), - /* @__PURE__ */ I(k, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + /* @__PURE__ */ B(I, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ /* @__PURE__ */ a( D, { @@ -207,24 +207,24 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => l(e - 1), + onClick: () => s(e - 1), isDisabled: e === 1, - icon: /* @__PURE__ */ a(O, {}), + icon: /* @__PURE__ */ a(g, {}), "aria-label": "صفحه قبلی" } ), - y.map((n) => /* @__PURE__ */ a( - V, + y.map((r) => /* @__PURE__ */ a( + L, { size: "md", - bg: e === n ? "#4B49AC" : "#e6e6f1", - color: e === n ? "#e6e6f1" : "#4B49AC", - _hover: { bg: e === n ? "#4B49AC" : "#cbcbe8" }, - onClick: () => l(n), + bg: e === r ? "#4B49AC" : "#e6e6f1", + color: e === r ? "#e6e6f1" : "#4B49AC", + _hover: { bg: e === r ? "#4B49AC" : "#cbcbe8" }, + onClick: () => s(r), variant: "soft", - children: p(n) + children: p(r) }, - n + r )), /* @__PURE__ */ a( D, @@ -233,14 +233,14 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => l(e + 1), + onClick: () => s(e + 1), isDisabled: e === t, - icon: /* @__PURE__ */ a(q, {}), + icon: /* @__PURE__ */ a(O, {}), "aria-label": "صفحه بعدی" } ), /* @__PURE__ */ a( - W, + U, { ref: w, type: "text", @@ -249,17 +249,17 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S w: "100px", value: c, onFocus: () => { - o(!0), s(null), i(""); + o(!0), u(null), l(""); }, - onChange: (n) => { - const h = n.target.value, m = K(h).replace(/\D/g, ""); - i(p(m)); + onChange: (r) => { + const h = r.target.value, m = K(h).replace(/\D/g, ""); + l(p(m)); }, onBlur: () => { - c || (i(p(e)), o(!1), s(null)); + c || (l(p(e)), o(!1), u(null)); }, - onKeyDown: (n) => { - n.key === "Enter" && v(); + onKeyDown: (r) => { + r.key === "Enter" && A(); }, textAlign: "center", color: "#1D2939", @@ -269,69 +269,69 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S } ) ] }), - /* @__PURE__ */ I(k, { spacing: 2, whiteSpace: "nowrap", children: [ + /* @__PURE__ */ B(I, { spacing: 2, whiteSpace: "nowrap", children: [ /* @__PURE__ */ a(S, { fontWeight: "bold", children: "تعداد کل:" }), - /* @__PURE__ */ a(S, { children: p(r) }) + /* @__PURE__ */ a(S, { children: p(n) }) ] }) ] } ); -}, Se = ({ +}, Ne = ({ currentPage: e, totalPages: t, - totalCount: r, - onPageChange: l + totalCount: n, + onPageChange: s }) => { - const [c, i] = B(""), [u, o] = B(!1), [f, s] = B(null), w = z(null), y = f ?? e, v = E( + const [c, l] = v(""), [i, o] = v(!1), [f, u] = v(null), w = N(null), y = f ?? e, A = E( (x) => { - const A = Math.min(Math.max(x, 1), t); - o(!1), i(""), s(null), A !== e && l(A); + const k = Math.min(Math.max(x, 1), t); + o(!1), l(""), u(null), k !== e && s(k); }, - [e, t, l] - ), n = E(() => { + [e, t, s] + ), r = E(() => { if (!c) { - o(!1), i(""), s(null); + o(!1), l(""), u(null); return; } const x = parseInt(K(c), 10); if (isNaN(x)) { - o(!1), i(""), s(null); + o(!1), l(""), u(null); return; } - const A = Math.min(Math.max(x, 1), t); - o(!1), i(""), A !== e ? (s(A), l(A)) : s(null); - }, [c, e, t, l]); + const k = Math.min(Math.max(x, 1), t); + o(!1), l(""), k !== e ? (u(k), s(k)) : u(null); + }, [c, e, t, s]); C(() => { var x; - u && ((x = w.current) == null || x.focus()); - }, [u]), C(() => { - f !== null && e === f && s(null); + i && ((x = w.current) == null || x.focus()); + }, [i]), C(() => { + f !== null && e === f && u(null); }, [e, f]), C(() => { - if (!u || !c) return; + if (!i || !c) return; const x = setTimeout(() => { - n(); + r(); }, 1e3); return () => clearTimeout(x); - }, [c, u, n]); + }, [c, i, r]); const h = () => { - s(null), i(""), o(!0); - }, m = (x, A = !1) => /* @__PURE__ */ a( - V, + u(null), l(""), o(!0); + }, m = (x, k = !1) => /* @__PURE__ */ a( + L, { size: "md", - bg: A ? "#4B49AC" : "#e6e6f1", - color: A ? "#e6e6f1" : "#4B49AC", - _hover: { bg: A ? "#4B49AC" : "#cbcbe8" }, - onClick: A ? h : () => v(x), + bg: k ? "#4B49AC" : "#e6e6f1", + color: k ? "#e6e6f1" : "#4B49AC", + _hover: { bg: k ? "#4B49AC" : "#cbcbe8" }, + onClick: k ? h : () => A(x), variant: "soft", children: p(x) }, x ); - if (t === 0 || !r) return null; - const b = t > 1 && y !== 1, _ = t > 1 && y !== t; + if (t === 0 || !n) return null; + const b = t > 1 && y !== 1, F = t > 1 && y !== t; return /* @__PURE__ */ a( - k, + I, { justifyContent: "center", backgroundColor: "white", @@ -341,7 +341,7 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S border: "1px", borderColor: "blue.200", w: "100%", - children: /* @__PURE__ */ I(k, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + children: /* @__PURE__ */ B(I, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ /* @__PURE__ */ a( D, { @@ -349,15 +349,15 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => v(y - 1), + onClick: () => A(y - 1), isDisabled: y === 1, - icon: /* @__PURE__ */ a(O, {}), + icon: /* @__PURE__ */ a(g, {}), "aria-label": "صفحه قبلی" } ), b && m(1), - u ? /* @__PURE__ */ a( - W, + i ? /* @__PURE__ */ a( + U, { ref: w, type: "text", @@ -366,14 +366,14 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S w: "48px", value: c, onChange: (x) => { - const A = x.target.value, X = K(A).replace(/\D/g, ""); - i(p(X)); + const k = x.target.value, X = K(k).replace(/\D/g, ""); + l(p(X)); }, onBlur: () => { - c ? n() : (i(""), o(!1), s(null)); + c ? r() : (l(""), o(!1), u(null)); }, onKeyDown: (x) => { - x.key === "Enter" && n(), x.key === "Escape" && (i(""), o(!1), s(null)); + x.key === "Enter" && r(), x.key === "Escape" && (l(""), o(!1), u(null)); }, textAlign: "center", color: "#1D2939", @@ -382,7 +382,7 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S dir: "ltr" } ) : m(y, !0), - _ && m(t), + F && m(t), /* @__PURE__ */ a( D, { @@ -390,9 +390,9 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => v(y + 1), + onClick: () => A(y + 1), isDisabled: y === t, - icon: /* @__PURE__ */ a(q, {}), + icon: /* @__PURE__ */ a(O, {}), "aria-label": "صفحه بعدی" } ) @@ -400,92 +400,92 @@ const Be = (e) => new Intl.NumberFormat("fa-IR").format(Number(e)), p = (e) => S } ); }; -let j = null, d = null, F = null, L = !1; -const ne = G(null), re = ({ url: e, realm: t, clientId: r }) => (d || (d = new P({ +let R = null, d = null, V = null, j = !1; +const ie = $(null), oe = ({ url: e, realm: t, clientId: n }) => (d || (d = new te({ url: e, realm: t, - clientId: r -})), d), ie = (e) => (j = e, j), oe = () => L, $ = () => !!(d != null && d.authenticated), N = () => (d == null ? void 0 : d.token) ?? null, U = async (e = 30) => d ? d.updateToken(e) : !1, J = (e) => d == null ? void 0 : d.logout(e), Ie = (e) => d == null ? void 0 : d.login(e), Q = ({ config: e, initOptions: t = {} } = {}) => { - const r = e ?? j; - if (!(r != null && r.url) || !(r != null && r.realm) || !(r != null && r.clientId)) + clientId: n +})), d), se = (e) => (R = e, R), le = () => j, G = () => !!(d != null && d.authenticated), T = () => (d == null ? void 0 : d.token) ?? null, q = async (e = 30) => d ? d.updateToken(e) : !1, H = (e) => d == null ? void 0 : d.logout(e), Te = (e) => d == null ? void 0 : d.login(e), J = ({ config: e, initOptions: t = {} } = {}) => { + const n = e ?? R; + if (!(n != null && n.url) || !(n != null && n.realm) || !(n != null && n.clientId)) throw new Error("Keycloak config is required."); - ie(r); - const l = re(r); - return F || (F = l.init({ + se(n); + const s = oe(n); + return V || (V = s.init({ onLoad: "login-required", checkLoginIframe: !1, flow: "implicit", ...t - }).then((c) => (L = !0, c)).catch((c) => { - throw L = !0, c; - })), F; -}, Ee = ({ + }).then((c) => (j = !0, c)).catch((c) => { + throw j = !0, c; + })), V; +}, ce = ({ children: e, config: t, - initOptions: r, - loading: l = null + initOptions: n, + loading: s = null }) => { - const [c, i] = B(!1), [u, o] = B(!1), [f, s] = B(null), w = z(!1), y = E(() => { - d && (o(!!d.authenticated), s(d.token ?? null)); + const [c, l] = v(!1), [i, o] = v(!1), [f, u] = v(null), w = N(!1), y = E(() => { + d && (o(!!d.authenticated), u(d.token ?? null)); }, []); - C(() => (w.current = !0, Q({ config: t, initOptions: r }).then((b) => { - w.current && (o(!!b), s((d == null ? void 0 : d.token) ?? null), i(!0)); + C(() => (w.current = !0, J({ config: t, initOptions: n }).then((b) => { + w.current && (o(!!b), u((d == null ? void 0 : d.token) ?? null), l(!0)); }).catch(() => { - w.current && (o(!1), s(null), i(!0)); + w.current && (o(!1), u(null), l(!0)); }), () => { w.current = !1; - }), [t, r]); - const v = E(() => d == null ? void 0 : d.login(), []), n = E((b) => d == null ? void 0 : d.logout(b), []), h = E( + }), [t, n]); + const A = E(() => d == null ? void 0 : d.login(), []), r = E((b) => d == null ? void 0 : d.logout(b), []), h = E( async (b = 30) => { if (!d) return !1; - const _ = await d.updateToken(b); - return y(), _; + const F = await d.updateToken(b); + return y(), F; }, [y] - ), m = R( + ), m = z( () => ({ initialized: c, - authenticated: u, + authenticated: i, token: f, - login: v, - logout: n, + login: A, + logout: r, updateToken: h }), - [c, u, f, v, n, h] + [c, i, f, A, r, h] ); - return c ? /* @__PURE__ */ a(ne.Provider, { value: m, children: e }) : l; -}, Y = G(null), M = "permissions", se = (e) => (e == null ? void 0 : e.storageKey) || M, Ke = ({ + return c ? /* @__PURE__ */ a(ie.Provider, { value: m, children: e }) : s; +}, Q = $(null), M = "permissions", ue = (e) => (e == null ? void 0 : e.storageKey) || M, ze = ({ user: e = null, children: t, - config: r, - loading: l = /* @__PURE__ */ a("div", { children: "Loading permissions..." }), + config: n, + loading: s = /* @__PURE__ */ a("div", { children: "Loading permissions..." }), errorFallback: c = /* @__PURE__ */ a("div", { children: "Error loading permissions" }) }) => { - const i = se(r), [u, o] = B( - () => le(i) - ), { data: f, isLoading: s, error: w } = fe(r), y = f ?? u; + const l = ue(n), [i, o] = v( + () => ae(l) + ), { data: f, isLoading: u, error: w } = me(n), y = f ?? i; C(() => { - f && (ce(i, f), o(f)); - }, [f, i]); - const v = R( - () => ue(y), + f && (de(l, f), o(f)); + }, [f, l]); + const A = z( + () => fe(y), [y] - ), n = E( - (b = "") => ae(v, b), - [v] - ), h = E((b = "") => !n(b), [n]), m = R( + ), r = E( + (b = "") => pe(A, b), + [A] + ), h = E((b = "") => !r(b), [r]), m = z( () => ({ user: e, - can: n, + can: r, cannot: h, permissions: y, - isLoading: s, + isLoading: u, error: w }), - [e, n, h, y, s, w] + [e, r, h, y, u, w] ); - return w && !y ? c : s && !y ? l : /* @__PURE__ */ a(Y.Provider, { value: m, children: t }); -}, le = (e = M) => { + return w && !y ? c : u && !y ? s : /* @__PURE__ */ a(Q.Provider, { value: m, children: t }); +}, ae = (e = M) => { if (!(typeof window > "u")) try { const t = localStorage.getItem(e); @@ -493,156 +493,221 @@ const ne = G(null), re = ({ url: e, realm: t, clientId: r }) => (d || (d = new P } catch { return; } -}, ce = (e = M, t) => { +}, de = (e = M, t) => { if (!(typeof window > "u")) try { localStorage.setItem(e, JSON.stringify(t)); } catch { } -}, De = (e = M) => { +}, _e = (e = M) => { if (!(typeof window > "u")) try { localStorage.removeItem(e); } catch { } -}, ue = (e) => e ? new Set(e.map((t) => t.name)) : /* @__PURE__ */ new Set(), ae = (e, t = "") => { +}, fe = (e) => e ? new Set(e.map((t) => t.name)) : /* @__PURE__ */ new Set(), pe = (e, t = "") => { if (!t) return !1; - if (e.has(t) || [...e].some((l) => l.startsWith(t))) return !0; - let r = t; - for (; r.includes(":"); ) - if (r = r.slice(0, r.lastIndexOf(":")), e.has(`${r}:*`)) return !0; + if (e.has(t) || [...e].some((s) => s.startsWith(t))) return !0; + let n = t; + for (; n.includes(":"); ) + if (n = n.slice(0, n.lastIndexOf(":")), e.has(`${n}:*`)) return !0; return !1; -}, H = { +}, Y = { all: ["permissions"], - list: (e) => [...H.all, e] -}, de = async (e) => { + list: (e) => [...Y.all, e] +}, he = async (e) => { if (!(e != null && e.url) || !(e != null && e.clientId)) throw new Error("Permission config requires url and clientId."); - const t = N(), r = new URL(e.url); - r.searchParams.set("client_id", e.clientId); - const l = await fetch(r.toString(), { + const t = T(), n = new URL(e.url); + n.searchParams.set("client_id", e.clientId); + const s = await fetch(n.toString(), { method: "GET", headers: { ...t ? { Authorization: `Bearer ${t}` } : {} } }); - if (!l.ok) + if (!s.ok) throw new Error("Failed to load permissions"); - return l.json(); -}, g = () => { - const e = Z(Y); + return s.json(); +}, W = () => { + const e = P(Q); if (!e) throw new Error("usePermission must be used within PermissionProvider"); return e; -}, fe = (e) => ee({ - queryKey: H.list(e == null ? void 0 : e.clientId), - queryFn: () => de(e), - enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && $(), +}, me = (e) => ne({ + queryKey: Y.list(e == null ? void 0 : e.clientId), + queryFn: () => he(e), + enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && G(), staleTime: 1 / 0, refetchOnWindowFocus: !1, refetchOnReconnect: !1 -}), Ne = ({ +}), Me = ({ perm: e, children: t, - fallback: r = /* @__PURE__ */ a("div", { children: "You are not allowed to do this" }) + fallback: n = /* @__PURE__ */ a("div", { children: "You are not allowed to do this" }) }) => { - const { can: l } = g(); - return l(e) ? t : r; -}, Te = ({ children: e }) => { - const { can: t, permissions: r } = g(); - return r && t("admin") ? e : null; -}, ze = ({ children: e }) => { - const { can: t, isLoading: r } = g(); + const { can: s } = W(); + return s(e) ? t : n; +}, Fe = ({ children: e }) => { + const { can: t, permissions: n } = W(); + return n && t("admin") ? e : null; +}, Ve = ({ children: e }) => { + const { can: t, isLoading: n } = W(); return C(() => { - r || t("panel_access") || J(); - }, [r, t]), e; + n || t("panel_access") || H(); + }, [n, t]), e; }; -let T = null; -const pe = (e) => { - const { api: t } = e, r = te.create({ +let _ = null; +const be = (e) => { + const { api: t } = e, n = re.create({ baseURL: t.baseUrl - }), l = async () => { - (!oe() || !$()) && await Q(); - }, c = async (u) => { - await l(); - let o = N(); + }), s = async () => { + (!le() || !G()) && await J(); + }, c = async (i) => { + await s(); + let o = T(); if (o) { try { - await U(5), o = N(); + await q(5), o = T(); } catch { } - u.headers = { - ...u.headers, + i.headers = { + ...i.headers, Authorization: `Bearer ${o}` }; } - return u; - }, i = async (u) => { + return i; + }, l = async (i) => { var f; - const o = u.config; - if (((f = u == null ? void 0 : u.response) == null ? void 0 : f.status) === 401 && !(o != null && o._retry)) { + const o = i.config; + if (((f = i == null ? void 0 : i.response) == null ? void 0 : f.status) === 401 && !(o != null && o._retry)) { o._retry = !0; try { - await U(30); - const s = N(); + await q(30); + const u = T(); return o.headers = { ...o.headers, - Authorization: `Bearer ${s}` - }, r(o); + Authorization: `Bearer ${u}` + }, n(o); } catch { - J({ redirectUri: window.location.origin }); + H({ redirectUri: window.location.origin }); } } - return Promise.reject(u); + return Promise.reject(i); }; - return r.interceptors.request.use(c), r.interceptors.response.use( - (u) => u, - i + return n.interceptors.request.use(c), n.interceptors.response.use( + (i) => i, + l ), { - api: r + api: n }; -}, Me = (e) => (T = pe(e), T), he = () => { - if (!T) +}, we = (e) => (_ = be(e), _), ye = () => { + if (!_) throw new Error("api is not configured. Call configureApi(config) first."); - return T.api; -}, _e = new Proxy( + return _.api; +}, Re = new Proxy( {}, { get(e, t) { - return he()[t]; + return ye()[t]; } } ); +function xe() { + const [e, t] = v(!1), n = N(null); + return C(() => { + if (process.env.NODE_ENV !== "production") return; + let s; + const c = async () => { + const i = await fetch(`/version.json?t=${Date.now()}`, { + cache: "no-store" + }); + if (!i.ok) + throw new Error(`Failed to fetch version: ${i.status}`); + const o = await i.json(); + return String(o.version); + }; + return (async () => { + try { + n.current = await c(), s = setInterval(async () => { + try { + const i = await c(); + n.current && i !== n.current && (t(!0), clearInterval(s)); + } catch (i) { + console.error("Update check failed:", i); + } + }, 3e4); + } catch (i) { + console.error("Initial version fetch failed:", i); + } + })(), () => { + s && clearInterval(s); + }; + }, []), e ? /* @__PURE__ */ a( + "div", + { + style: { + position: "fixed", + bottom: "16px", + right: "16px", + background: "#111", + color: "#fff", + padding: "12px 16px", + borderRadius: "8px", + zIndex: 9999, + cursor: "pointer" + }, + onClick: () => window.location.reload(), + children: "نسخه جدید سامانه در دسترس است" + } + ) : null; +} +function je({ + children: e, + config: t, + loading: n = /* @__PURE__ */ a(ee, {}), + updateChecker: s = !0, + updateCheckerProps: c +}) { + return z(() => { + we(t); + }, [t]), /* @__PURE__ */ B(Z, { children: [ + s && /* @__PURE__ */ a(xe, { ...c }), + /* @__PURE__ */ a(ce, { config: t.keycloak, loading: n, children: e }) + ] }); +} export { - Te as AdminGuard, - Ne as Can, - Ee as KeycloakProvider, - Ce as LightPagination, - ke as Pagination, - ze as PanelAccessGuard, - Ke as PermissionProvider, - Se as SimplePagination, - _e as api, - ae as checkPermission, - De as clearCachedPermissions, - Me as configureApi, - pe as createApi, - ue as createPermissionSet, - he as getApi, - le as getCachedPermissions, - N as getKeycloakToken, - de as getPermissions, - Q as initKeycloak, - $ as isKeycloakAuthenticated, - oe as isKeycloakInitialized, - Ie as loginKeycloak, - J as logoutKeycloak, - H as permissionKeys, - ce as setCachedPermissions, + Fe as AdminGuard, + Me as Can, + ce as KeycloakProvider, + Ke as LightPagination, + De as Pagination, + Ve as PanelAccessGuard, + ze as PermissionProvider, + Ne as SimplePagination, + je as UiKitProvider, + xe as UpdateChecker, + Re as api, + pe as checkPermission, + _e as clearCachedPermissions, + we as configureApi, + be as createApi, + fe as createPermissionSet, + ye as getApi, + ae as getCachedPermissions, + T as getKeycloakToken, + he as getPermissions, + J as initKeycloak, + G as isKeycloakAuthenticated, + le as isKeycloakInitialized, + Te as loginKeycloak, + H as logoutKeycloak, + Y as permissionKeys, + de as setCachedPermissions, K as toEnDigits, p as toFaDigits, - Be as toFaNumber, - U as updateKeycloakToken, - g as usePermission, - fe as usePermissionsQuery + Ee as toFaNumber, + q as updateKeycloakToken, + W as usePermission, + me as usePermissionsQuery }; diff --git a/src/components/UpdateChecker.jsx b/src/components/UpdateChecker.jsx new file mode 100644 index 0000000..80cb397 --- /dev/null +++ b/src/components/UpdateChecker.jsx @@ -0,0 +1,78 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; + +export function UpdateChecker() { + const [hasUpdate, setHasUpdate] = useState(false); + const currentVersionRef = useRef(null); + + useEffect(() => { + if (process.env.NODE_ENV !== "production") return; + + let intervalId; + + const fetchVersion = async () => { + const res = await fetch(`/version.json?t=${Date.now()}`, { + cache: "no-store", + }); + + if (!res.ok) { + throw new Error(`Failed to fetch version: ${res.status}`); + } + + const data = await res.json(); + return String(data.version); + }; + + const init = async () => { + try { + currentVersionRef.current = await fetchVersion(); + + intervalId = setInterval(async () => { + try { + const latestVersion = await fetchVersion(); + + if ( + currentVersionRef.current && + latestVersion !== currentVersionRef.current + ) { + setHasUpdate(true); + clearInterval(intervalId); + } + } catch (err) { + console.error("Update check failed:", err); + } + }, 30000); + } catch (err) { + console.error("Initial version fetch failed:", err); + } + }; + + init(); + + return () => { + if (intervalId) clearInterval(intervalId); + }; + }, []); + + if (!hasUpdate) return null; + + return ( +
window.location.reload()} + > + نسخه جدید سامانه در دسترس است +
+ ); +} diff --git a/src/core/UiKitProvider.jsx b/src/core/UiKitProvider.jsx new file mode 100644 index 0000000..747bb59 --- /dev/null +++ b/src/core/UiKitProvider.jsx @@ -0,0 +1,27 @@ +import { useMemo } from "react"; +import { Spinner } from "@chakra-ui/react"; +import { KeycloakProvider } from "./keycloak.jsx"; +import { UpdateChecker } from "../components/UpdateChecker.jsx"; +import { configureApi } from "./api.js"; + +export function UiKitProvider({ + children, + config, + loading = , + updateChecker = true, + updateCheckerProps, +}) { + useMemo(() => { + configureApi(config); + }, [config]); + + return ( + <> + {updateChecker && } + + + {children} + + + ); +} diff --git a/src/index.js b/src/index.js index 2e6db63..f0f764e 100644 --- a/src/index.js +++ b/src/index.js @@ -32,3 +32,6 @@ export { } from "./core/permission.jsx"; export { createApi, configureApi, getApi, api } from "./core/api.js"; + +export { UiKitProvider } from "./core/UiKitProvider.jsx"; +export { UpdateChecker } from "./components/UpdateChecker.jsx";