@eintrek/erp-shell 0.1.21 → 0.1.22
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.js
CHANGED
|
@@ -711,8 +711,15 @@ function getActiveSubModule(pathname, modules) {
|
|
|
711
711
|
}
|
|
712
712
|
return null;
|
|
713
713
|
}
|
|
714
|
-
/** Prepend `code` (org code) to a relative URL so `/sales` → `/O25.../sales`.
|
|
714
|
+
/** Prepend `code` (org code) to a relative URL so `/sales` → `/O25.../sales`.
|
|
715
|
+
* Absolute `http(s)://` URLs are left intact; optional `{code}` placeholder is replaced.
|
|
716
|
+
*/
|
|
715
717
|
function buildUrlWithCode(code, url) {
|
|
718
|
+
if (/^https?:\/\//i.test(url)) {
|
|
719
|
+
if (!code)
|
|
720
|
+
return url.split("{code}").join("");
|
|
721
|
+
return url.split("{code}").join(code);
|
|
722
|
+
}
|
|
716
723
|
if (!code)
|
|
717
724
|
return url;
|
|
718
725
|
const cleanUrl = url.startsWith("/") ? url.slice(1) : url;
|
|
@@ -859,7 +866,7 @@ function NavUser({ organization, avatarSrc, profileHref, selectOrganizationHref
|
|
|
859
866
|
{ code: "zh", label: "中文" },
|
|
860
867
|
{ code: "ja", label: "日本語" },
|
|
861
868
|
].map(({ code, label }) => (jsxRuntime.jsxs("button", { onClick: () => handleLanguageChange(code), className: "flex w-full items-center gap-3 px-3 py-2 text-sm text-sidebar-foreground hover:bg-sidebar-accent rounded-md transition-colors", children: [jsxRuntime.jsx("span", { className: "flex-1 text-left", children: label }), organization?.language === code && (jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-primary" }))] }, code))) }))] }), profileHref && (jsxRuntime.jsxs("button", { onClick: handleProfile, className: "flex w-full items-center gap-3 px-3 py-2.5 text-sm text-sidebar-foreground hover:bg-sidebar-accent rounded-md transition-colors", children: [jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "flex-1 text-left", children: "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E2A\u0E48\u0E27\u0E19\u0E15\u0E31\u0E27" })] })), jsxRuntime.jsxs("button", { onClick: handleSelectOrganization, className: "flex w-full items-center gap-3 px-3 py-2.5 text-sm text-sidebar-foreground hover:bg-sidebar-accent rounded-md transition-colors", children: [jsxRuntime.jsx(lucideReact.Building2, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "flex-1 text-left", children: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E18\u0E38\u0E23\u0E01\u0E34\u0E08" })] }), jsxRuntime.jsx("button", { onClick: handleSignOut, disabled: isSigningOut, className: "flex w-full items-center gap-3 px-3 py-2.5 text-sm text-sidebar-foreground hover:bg-sidebar-accent rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed mt-1", children: isSigningOut ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }), jsxRuntime.jsx("span", { className: "flex-1 text-left", children: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A..." })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(lucideReact.LogOut, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "flex-1 text-left", children: "\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A" })] })) })] })] })) : null;
|
|
862
|
-
return (jsxRuntime.jsx("div", { className: "p-2", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsxs("button", { ref: buttonRef, onClick: () => setIsOpen(!isOpen), className: "flex w-full items-center gap-2 p-2 rounded-md transition-colors", children: [jsxRuntime.jsxs(erpTheme.Avatar, { className: "h-8 w-8 rounded-lg", children: [jsxRuntime.jsx(erpTheme.AvatarImage, { src: user.avatar, alt: user.name }), jsxRuntime.jsx(erpTheme.AvatarFallback, { className: "rounded-lg bg-[#E4525F] text-sidebar-primary-foreground w-8 h-8", children: getInitials(user.name) })] }), jsxRuntime.jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [jsxRuntime.jsx("span", { className: "truncate font-medium", title: user.name, children: user.name }), jsxRuntime.jsx("span", { className: "truncate text-xs text-sidebar-foreground/70", title: user.email, children: user.email })] }), jsxRuntime.jsx(lucideReact.ChevronUp, { className: `ml-auto size-4 transition-transform ${isOpen ? "rotate-180" : ""}` })] }), typeof window !== "undefined" &&
|
|
869
|
+
return (jsxRuntime.jsx("div", { className: "p-2", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsxs("button", { ref: buttonRef, onClick: () => setIsOpen(!isOpen), className: "flex w-full items-center gap-2 p-2 rounded-md transition-colors", children: [jsxRuntime.jsxs(erpTheme.Avatar, { className: "h-8 w-8 rounded-lg", children: [user.avatar ? (jsxRuntime.jsx(erpTheme.AvatarImage, { src: user.avatar, alt: user.name })) : null, jsxRuntime.jsx(erpTheme.AvatarFallback, { className: "rounded-lg bg-[#E4525F] text-sidebar-primary-foreground w-8 h-8", children: getInitials(user.name) })] }), jsxRuntime.jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [jsxRuntime.jsx("span", { className: "truncate font-medium", title: user.name, children: user.name }), jsxRuntime.jsx("span", { className: "truncate text-xs text-sidebar-foreground/70", title: user.email, children: user.email })] }), jsxRuntime.jsx(lucideReact.ChevronUp, { className: `ml-auto size-4 transition-transform ${isOpen ? "rotate-180" : ""}` })] }), typeof window !== "undefined" &&
|
|
863
870
|
reactDom.createPortal(dropdownContent, document.body)] }) }));
|
|
864
871
|
}
|
|
865
872
|
|
|
@@ -938,6 +945,17 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, })
|
|
|
938
945
|
}) }) }));
|
|
939
946
|
}
|
|
940
947
|
|
|
948
|
+
function OrgMark({ logoUrl, size = "md", }) {
|
|
949
|
+
const [failed, setFailed] = React.useState(false);
|
|
950
|
+
const box = size === "sm"
|
|
951
|
+
? "flex size-6 items-center justify-center rounded-md border overflow-hidden bg-background"
|
|
952
|
+
: "flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground overflow-hidden";
|
|
953
|
+
const icon = size === "sm" ? "size-3.5 shrink-0" : "size-4";
|
|
954
|
+
if (logoUrl && !failed) {
|
|
955
|
+
return (jsxRuntime.jsx("div", { className: erpTheme.cn(box, size === "md" && "bg-white"), children: jsxRuntime.jsx("img", { src: logoUrl, alt: "", className: "size-full object-contain p-0.5", onError: () => setFailed(true) }) }));
|
|
956
|
+
}
|
|
957
|
+
return (jsxRuntime.jsx("div", { className: box, children: jsxRuntime.jsx(lucideReact.Building2, { className: icon }) }));
|
|
958
|
+
}
|
|
941
959
|
function OrganizationSwitcher({ activeOrganization, isContextLoading = false, organizations, isLoadingOrgs = false, setOrganizationCookie, registerOrganizationHref = "/register-organization", className, }) {
|
|
942
960
|
const { isMobile } = useSidebarToggle();
|
|
943
961
|
const router = navigation.useRouter();
|
|
@@ -983,10 +1001,10 @@ function OrganizationSwitcher({ activeOrganization, isContextLoading = false, or
|
|
|
983
1001
|
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" })] }) }) }));
|
|
984
1002
|
}
|
|
985
1003
|
if (organizations.length <= 1) {
|
|
986
|
-
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(
|
|
1004
|
+
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(OrgMark, { logoUrl: activeOrganization?.logoUrl }), jsxRuntime.jsx("span", { className: "truncate font-semibold text-sm min-w-0 flex-1", children: activeOrganization?.name || "ไม่มีองค์กร" })] }) }) }));
|
|
987
1005
|
}
|
|
988
|
-
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(
|
|
989
|
-
"bg-accent"), children: [jsxRuntime.jsx(
|
|
1006
|
+
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(OrgMark, { logoUrl: activeOrganization?.logoUrl }), 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) &&
|
|
1007
|
+
"bg-accent"), children: [jsxRuntime.jsx(OrgMark, { logoUrl: org.logoUrl, size: "sm" }), 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" })] })] })] }) }) }));
|
|
990
1008
|
}
|
|
991
1009
|
|
|
992
1010
|
function SidebarHeader({ children, className }) {
|
|
@@ -1438,7 +1456,9 @@ function SessionBackedProfileCacheSeeder({ queryKey, mapper, }) {
|
|
|
1438
1456
|
if (mapped) {
|
|
1439
1457
|
const existing = queryClient.getQueryData(queryKey);
|
|
1440
1458
|
if (!existing) {
|
|
1441
|
-
|
|
1459
|
+
// updatedAt: 0 → immediately stale so observers still GET /myprofile
|
|
1460
|
+
// for fields the JWT seed omits (avatar/signature paths).
|
|
1461
|
+
queryClient.setQueryData(queryKey, mapped, { updatedAt: 0 });
|
|
1442
1462
|
}
|
|
1443
1463
|
else {
|
|
1444
1464
|
// Only overwrite when the mapped id changed — we don't know T's shape
|
|
@@ -1446,7 +1466,7 @@ function SessionBackedProfileCacheSeeder({ queryKey, mapper, }) {
|
|
|
1446
1466
|
const existingId = existing?.id;
|
|
1447
1467
|
const mappedId = mapped?.id;
|
|
1448
1468
|
if (existingId !== mappedId) {
|
|
1449
|
-
queryClient.setQueryData(queryKey, mapped);
|
|
1469
|
+
queryClient.setQueryData(queryKey, mapped, { updatedAt: 0 });
|
|
1450
1470
|
}
|
|
1451
1471
|
}
|
|
1452
1472
|
}
|