@eintrek/erp-shell 0.1.16 → 0.1.18
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.esm.js +23 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +23 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -999,6 +999,16 @@ function AppLayoutShell({ children, sidebar, loadingComponent, breadcrumb, permi
|
|
|
999
999
|
const params = navigation.useParams();
|
|
1000
1000
|
const code = params?.code;
|
|
1001
1001
|
const extendedSession = session;
|
|
1002
|
+
// Track once-authenticated so a transient accessToken drop during the
|
|
1003
|
+
// periodic session refresh (SessionRefreshTrigger every 4 min) doesn't
|
|
1004
|
+
// blank the whole page. The initial-load gate below still handles cold
|
|
1005
|
+
// start; once we've seen a real token we render children optimistically
|
|
1006
|
+
// and let the API layer surface a real 401 if the token actually died.
|
|
1007
|
+
const hasSeenAccessTokenRef = React.useRef(false);
|
|
1008
|
+
React.useEffect(() => {
|
|
1009
|
+
if (extendedSession?.accessToken)
|
|
1010
|
+
hasSeenAccessTokenRef.current = true;
|
|
1011
|
+
}, [extendedSession?.accessToken]);
|
|
1002
1012
|
// Find the org from the URL `[code]` so we can detect a context mismatch
|
|
1003
1013
|
// (the user bookmarked a different org than the cookie remembers).
|
|
1004
1014
|
const orgFromCode = React__namespace.useMemo(() => {
|
|
@@ -1041,9 +1051,15 @@ function AppLayoutShell({ children, sidebar, loadingComponent, breadcrumb, permi
|
|
|
1041
1051
|
if (status === "loading" && !session) {
|
|
1042
1052
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent });
|
|
1043
1053
|
}
|
|
1044
|
-
// Session loaded but no accessToken
|
|
1045
|
-
//
|
|
1046
|
-
|
|
1054
|
+
// Session loaded but no accessToken AND we've never seen one → real auth
|
|
1055
|
+
// failure (token refresh gave nothing back on cold start), bounce through
|
|
1056
|
+
// signin. If we HAVE seen one before, the drop is almost certainly the
|
|
1057
|
+
// in-flight periodic refresh (SessionRefreshTrigger). Don't redirect on
|
|
1058
|
+
// that transient — the JWT callback will settle in a moment and API
|
|
1059
|
+
// calls will keep working with the still-valid cookie.
|
|
1060
|
+
if (status === "authenticated" &&
|
|
1061
|
+
!extendedSession?.accessToken &&
|
|
1062
|
+
!hasSeenAccessTokenRef.current) {
|
|
1047
1063
|
if (typeof window !== "undefined") {
|
|
1048
1064
|
const url = new URL(signInUrl, window.location.origin);
|
|
1049
1065
|
url.searchParams.set("error", "NoAccessToken");
|
|
@@ -1052,7 +1068,9 @@ function AppLayoutShell({ children, sidebar, loadingComponent, breadcrumb, permi
|
|
|
1052
1068
|
}
|
|
1053
1069
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent });
|
|
1054
1070
|
}
|
|
1055
|
-
|
|
1071
|
+
// Only blank the page when we've never seen a token — otherwise the
|
|
1072
|
+
// periodic session refresh would visibly flash the loader every 4 min.
|
|
1073
|
+
if (!extendedSession?.accessToken && !hasSeenAccessTokenRef.current) {
|
|
1056
1074
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent });
|
|
1057
1075
|
}
|
|
1058
1076
|
if (!code) {
|
|
@@ -1064,7 +1082,7 @@ function AppLayoutShell({ children, sidebar, loadingComponent, breadcrumb, permi
|
|
|
1064
1082
|
const contentMargin = open && !isSidebarModalLayout ? "ml-[21.5rem]" : "";
|
|
1065
1083
|
const needsLeftGutter = !(open && !isSidebarModalLayout);
|
|
1066
1084
|
const wrap = permissionProvider ?? ((c) => c);
|
|
1067
|
-
return (jsxRuntime.jsxs("div", { className: "flex min-h-screen w-full bg-background", children: [open && (jsxRuntime.jsx("div", { className: "fixed left-0 top-0 z-50 h-screen", children: sidebar })), open && isSidebarModalLayout && (jsxRuntime.jsx("button", { type: "button", "aria-label": "\u0E1B\u0E34\u0E14\u0E40\u0E21\u0E19\u0E39", className: "fixed inset-0 z-40 bg-black/50", onClick: () => setOpen(false) })), jsxRuntime.jsx("div", { className: cx("relative flex min-w-0 flex-1 flex-col transition-all", contentMargin), children: jsxRuntime.jsxs("main", { className: "flex flex-1 flex-col min-h-screen gap-4", children: [jsxRuntime.jsxs("div", { className: "sticky top-0 z-30 shrink-0 w-full", children: [jsxRuntime.jsx(HeaderBackground, {}), jsxRuntime.jsxs("header", { className: "relative shrink-0 gap-2 py-4 h-auto min-h-[123.5px] w-full z-10", children: [jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 px-3 sm:px-4 lg:px-6", children: [jsxRuntime.jsx(SidebarTrigger, { className: "shrink-0 text-white hover:bg-white/10" }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: breadcrumb })] }), jsxRuntime.jsx("div", { id: "header-title" })] })] }), jsxRuntime.jsx(React.Suspense, { fallback: jsxRuntime.jsx("div", { className: "relative z-10 min-h-[calc(100vh-8rem)]", children: jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: jsxRuntime.jsxs("div", { className: "space-y-4 text-center", children: [jsxRuntime.jsx("div", { className: "mx-auto h-8 w-8 animate-spin rounded-full border-b-2 border-primary" }), jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E42\u0E2B\u0E25\u0E14..." })] }) }) }), children: jsxRuntime.jsx("div", { className: cx("relative z-10 pr-6
|
|
1085
|
+
return (jsxRuntime.jsxs("div", { className: "flex min-h-screen w-full bg-background", children: [open && (jsxRuntime.jsx("div", { className: "fixed left-0 top-0 z-50 h-screen", children: sidebar })), open && isSidebarModalLayout && (jsxRuntime.jsx("button", { type: "button", "aria-label": "\u0E1B\u0E34\u0E14\u0E40\u0E21\u0E19\u0E39", className: "fixed inset-0 z-40 bg-black/50", onClick: () => setOpen(false) })), jsxRuntime.jsx("div", { className: cx("relative flex min-w-0 flex-1 flex-col transition-all", contentMargin), children: jsxRuntime.jsxs("main", { className: "flex flex-1 flex-col min-h-screen gap-4", children: [jsxRuntime.jsxs("div", { className: "sticky top-0 z-30 shrink-0 w-full", children: [jsxRuntime.jsx(HeaderBackground, {}), jsxRuntime.jsxs("header", { className: "relative shrink-0 gap-2 py-4 h-auto min-h-[123.5px] w-full z-10", children: [jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 px-3 sm:px-4 lg:px-6", children: [jsxRuntime.jsx(SidebarTrigger, { className: "shrink-0 text-white hover:bg-white/10" }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: breadcrumb })] }), jsxRuntime.jsx("div", { id: "header-title" })] })] }), jsxRuntime.jsx(React.Suspense, { fallback: jsxRuntime.jsx("div", { className: "relative z-10 min-h-[calc(100vh-8rem)]", children: jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: jsxRuntime.jsxs("div", { className: "space-y-4 text-center", children: [jsxRuntime.jsx("div", { className: "mx-auto h-8 w-8 animate-spin rounded-full border-b-2 border-primary" }), jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E42\u0E2B\u0E25\u0E14..." })] }) }) }), children: jsxRuntime.jsx("div", { className: cx("relative z-10 pr-6", needsLeftGutter && "pl-6"), children: wrap(children) }, `org-${organizationId ?? "no-org"}`) })] }) })] }));
|
|
1068
1086
|
}
|
|
1069
1087
|
/** Local tiny classnames helper — avoids pulling clsx/tailwind-merge into
|
|
1070
1088
|
* the shell just for the layout file. Falsy values are skipped. */
|