@eintrek/erp-shell 0.1.15 → 0.1.17
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 +24 -6
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +24 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -959,9 +959,9 @@ function OrganizationSwitcher({ activeOrganization, isContextLoading = false, or
|
|
|
959
959
|
return (jsxRuntime.jsx(SidebarMenu, { className: className, children: jsxRuntime.jsx(SidebarMenuItem, { children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2", children: [jsxRuntime.jsx(erpTheme.Skeleton, { className: "size-8 rounded-lg" }), jsxRuntime.jsx(erpTheme.Skeleton, { className: "h-4 w-24" })] }) }) }));
|
|
960
960
|
}
|
|
961
961
|
if (organizations.length <= 1) {
|
|
962
|
-
return (jsxRuntime.jsx(SidebarMenu, { className: className, children: jsxRuntime.jsx(SidebarMenuItem, { children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2", children: [jsxRuntime.jsx("div", { className: "flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground", children: jsxRuntime.jsx(lucideReact.Building2, { className: "size-4" }) }), jsxRuntime.jsx("span", { className: "truncate font-semibold text-sm", children: activeOrganization?.name || "ไม่มีองค์กร" })] }) }) }));
|
|
962
|
+
return (jsxRuntime.jsx(SidebarMenu, { className: className, children: jsxRuntime.jsx(SidebarMenuItem, { children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2", children: [jsxRuntime.jsx("div", { className: "flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground", children: jsxRuntime.jsx(lucideReact.Building2, { className: "size-4" }) }), jsxRuntime.jsx("span", { className: "truncate font-semibold text-sm min-w-0 flex-1", children: activeOrganization?.name || "ไม่มีองค์กร" })] }) }) }));
|
|
963
963
|
}
|
|
964
|
-
return (jsxRuntime.jsx(SidebarMenu, { className: className, children: jsxRuntime.jsx(SidebarMenuItem, { children: jsxRuntime.jsxs(erpTheme.DropdownMenu, { children: [jsxRuntime.jsx(erpTheme.DropdownMenuTrigger, { asChild: true, children: jsxRuntime.jsxs(SidebarMenuButton, { size: "lg", className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground", children: [jsxRuntime.jsx("div", { className: "flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground", children: jsxRuntime.jsx(lucideReact.Building2, { className: "size-4" }) }), jsxRuntime.jsx("span", { className: "truncate font-semibold text-sm flex-1 text-left", children: activeOrganization?.name || "เลือกองค์กร" }), isPending ? (jsxRuntime.jsx(lucideReact.Loader2, { className: "ml-auto size-4 animate-spin" })) : (jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-auto size-4" }))] }) }), jsxRuntime.jsxs(erpTheme.DropdownMenuContent, { className: "w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg", align: "start", side: isMobile ? "bottom" : "right", sideOffset: 4, children: [jsxRuntime.jsx(erpTheme.DropdownMenuLabel, { className: "text-xs text-muted-foreground", children: "\u0E2D\u0E07\u0E04\u0E4C\u0E01\u0E23" }), organizations.map(org => (jsxRuntime.jsxs(erpTheme.DropdownMenuItem, { onClick: () => handleOrganizationChange(org), disabled: isPending, className: erpTheme.cn("gap-2 p-2 cursor-pointer", String(activeOrganization?.id) === String(org.id) &&
|
|
964
|
+
return (jsxRuntime.jsx(SidebarMenu, { className: className, children: jsxRuntime.jsx(SidebarMenuItem, { children: jsxRuntime.jsxs(erpTheme.DropdownMenu, { children: [jsxRuntime.jsx(erpTheme.DropdownMenuTrigger, { asChild: true, children: jsxRuntime.jsxs(SidebarMenuButton, { size: "lg", className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground", children: [jsxRuntime.jsx("div", { className: "flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground", children: jsxRuntime.jsx(lucideReact.Building2, { className: "size-4" }) }), jsxRuntime.jsx("span", { className: "truncate font-semibold text-sm flex-1 min-w-0 text-left", children: activeOrganization?.name || "เลือกองค์กร" }), isPending ? (jsxRuntime.jsx(lucideReact.Loader2, { className: "ml-auto size-4 animate-spin" })) : (jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-auto size-4" }))] }) }), jsxRuntime.jsxs(erpTheme.DropdownMenuContent, { className: "w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg", align: "start", side: isMobile ? "bottom" : "right", sideOffset: 4, children: [jsxRuntime.jsx(erpTheme.DropdownMenuLabel, { className: "text-xs text-muted-foreground", children: "\u0E2D\u0E07\u0E04\u0E4C\u0E01\u0E23" }), organizations.map(org => (jsxRuntime.jsxs(erpTheme.DropdownMenuItem, { onClick: () => handleOrganizationChange(org), disabled: isPending, className: erpTheme.cn("gap-2 p-2 cursor-pointer", String(activeOrganization?.id) === String(org.id) &&
|
|
965
965
|
"bg-accent"), children: [jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border", children: jsxRuntime.jsx(lucideReact.Building2, { className: "size-3.5 shrink-0" }) }), jsxRuntime.jsx("span", { className: "truncate", children: org.name })] }, org.id))), jsxRuntime.jsx(erpTheme.DropdownMenuSeparator, {}), jsxRuntime.jsxs(erpTheme.DropdownMenuItem, { className: "gap-2 p-2 cursor-pointer", onClick: () => router.push(registerOrganizationHref), children: [jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border bg-transparent", children: jsxRuntime.jsx(lucideReact.Plus, { className: "size-4" }) }), jsxRuntime.jsx("span", { className: "text-muted-foreground font-medium", children: "\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E2D\u0E07\u0E04\u0E4C\u0E01\u0E23" })] })] })] }) }) }));
|
|
966
966
|
}
|
|
967
967
|
|
|
@@ -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) {
|