@eintrek/erp-shell 0.1.37 → 0.1.39
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.d.ts +2 -0
- package/dist/index.esm.js +124 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +125 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/plan-features.d.ts +25 -0
- package/dist/navigation/app-registry.d.ts +19 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export { TapMenu } from "./navigation/tap-menu";
|
|
|
14
14
|
export { NavTools } from "./navigation/nav-tools";
|
|
15
15
|
export { AppBreadcrumb } from "./navigation/app-breadcrumb";
|
|
16
16
|
export { NavUser, type NavUserProps, type NavUserSystemLink } from "./navigation/nav-user";
|
|
17
|
+
export { buildSystemLinks, type BuildSystemLinksOptions, type ErpAppId, } from "./navigation/app-registry";
|
|
18
|
+
export { PLAN_FEATURES, hasPlanFeature, type PlanFeatureKey, } from "./lib/plan-features";
|
|
17
19
|
export { NavMain, type NavMainProps } from "./navigation/nav-main";
|
|
18
20
|
export { OrganizationSwitcher, type OrganizationSwitcherProps, type OrganizationLike, } from "./navigation/organization-switcher";
|
|
19
21
|
export { SidebarHeader } from "./navigation/sidebar-header";
|
package/dist/index.esm.js
CHANGED
|
@@ -5,7 +5,7 @@ import { useSession, signOut } from 'next-auth/react';
|
|
|
5
5
|
import { useQueryClient, MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
6
6
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
7
7
|
import { cn, Button, Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbSeparator, BreadcrumbPage, Avatar, AvatarImage, AvatarFallback, Collapsible, CollapsibleTrigger, CollapsibleContent, Badge, Skeleton, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator, Card, CardHeader, CardContent } from '@eintrek/erp-theme';
|
|
8
|
-
import { PanelLeftClose, Menu, ChevronRight, Building2, Palette, ChevronUp, Sun, Moon, Monitor, Globe, User, LayoutGrid, ExternalLink, Loader2, LogOut, ChevronDown, ChevronsUpDown, Plus, Ban, Home, Headset, ContactRound, UserPlus } from 'lucide-react';
|
|
8
|
+
import { PanelLeftClose, Menu, ChevronRight, Building2, Palette, ChevronUp, Sun, Moon, Monitor, Globe, User, LayoutGrid, ExternalLink, Loader2, LogOut, Calculator, Warehouse, FolderKanban, Users, ChevronDown, ChevronsUpDown, Plus, Ban, Home, Headset, ContactRound, UserPlus } from 'lucide-react';
|
|
9
9
|
import { create } from 'zustand';
|
|
10
10
|
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
11
11
|
import { useRouter, usePathname, useParams } from 'next/navigation';
|
|
@@ -902,6 +902,115 @@ function NavUser({ organization, avatarSrc, profileHref, selectOrganizationHref
|
|
|
902
902
|
createPortal(dropdownContent, document.body)] }) }));
|
|
903
903
|
}
|
|
904
904
|
|
|
905
|
+
/**
|
|
906
|
+
* Plan feature keys (billable entitlements). Mirror of platform-apis plan.go.
|
|
907
|
+
*
|
|
908
|
+
* This lives in the shell because every app gates on the same keys, and five
|
|
909
|
+
* private copies of the same list drift: the app-switcher list did exactly
|
|
910
|
+
* that before it moved here.
|
|
911
|
+
*/
|
|
912
|
+
const PLAN_FEATURES = {
|
|
913
|
+
ORG_CHART: "org_chart",
|
|
914
|
+
APPROVAL_WORKFLOW: "approval_workflow",
|
|
915
|
+
API_ACCESS: "api_access",
|
|
916
|
+
SSO: "sso",
|
|
917
|
+
BASIC_ACCOUNTING_HR: "basic_accounting_hr",
|
|
918
|
+
MODULE_PLATFORM: "module.platform",
|
|
919
|
+
MODULE_HR: "module.hr",
|
|
920
|
+
MODULE_ACCOUNTING: "module.accounting",
|
|
921
|
+
MODULE_SALES: "module.sales",
|
|
922
|
+
MODULE_PURCHASING: "module.purchasing",
|
|
923
|
+
MODULE_INVENTORY: "module.inventory",
|
|
924
|
+
MODULE_PROJECT: "module.project",
|
|
925
|
+
MODULE_SECRETARIAT: "module.secretariat",
|
|
926
|
+
};
|
|
927
|
+
/** True when plan features include key (with legacy basic_accounting_hr alias). */
|
|
928
|
+
function hasPlanFeature(features, feature) {
|
|
929
|
+
if (!features?.length)
|
|
930
|
+
return false;
|
|
931
|
+
if (features.includes(feature))
|
|
932
|
+
return true;
|
|
933
|
+
if ((feature === PLAN_FEATURES.MODULE_HR ||
|
|
934
|
+
feature === PLAN_FEATURES.MODULE_ACCOUNTING) &&
|
|
935
|
+
features.includes(PLAN_FEATURES.BASIC_ACCOUNTING_HR)) {
|
|
936
|
+
return true;
|
|
937
|
+
}
|
|
938
|
+
if (feature === PLAN_FEATURES.BASIC_ACCOUNTING_HR &&
|
|
939
|
+
features.includes(PLAN_FEATURES.MODULE_HR) &&
|
|
940
|
+
features.includes(PLAN_FEATURES.MODULE_ACCOUNTING)) {
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function normaliseBase(value, fallback) {
|
|
947
|
+
return (value ?? fallback).replace(/\/$/, "");
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* One list, in display order, for the whole suite.
|
|
951
|
+
*
|
|
952
|
+
* It used to be copied into every app's own nav-user.tsx, which is how Invenx
|
|
953
|
+
* shipped without a link to Plannex: five copies, one of them edited by hand.
|
|
954
|
+
* Adding the sixth app is now a change here plus a version bump.
|
|
955
|
+
*/
|
|
956
|
+
const APPS = [
|
|
957
|
+
{
|
|
958
|
+
id: "platform",
|
|
959
|
+
label: "แพลตฟอร์ม",
|
|
960
|
+
icon: jsx(Building2, { className: "h-4 w-4 shrink-0" }),
|
|
961
|
+
feature: null,
|
|
962
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_PLATFORM_URL, "https://platform.antniti.com"),
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
id: "accounx",
|
|
966
|
+
label: "Accounx",
|
|
967
|
+
icon: jsx(Calculator, { className: "h-4 w-4 shrink-0" }),
|
|
968
|
+
feature: PLAN_FEATURES.MODULE_ACCOUNTING,
|
|
969
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_ACCOUNTING_URL, "https://accounx.antniti.com"),
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
id: "invenx",
|
|
973
|
+
label: "Invenx",
|
|
974
|
+
icon: jsx(Warehouse, { className: "h-4 w-4 shrink-0" }),
|
|
975
|
+
feature: PLAN_FEATURES.MODULE_INVENTORY,
|
|
976
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_INVENX_URL, "https://invenx.antniti.com"),
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
id: "plannex",
|
|
980
|
+
label: "Plannex",
|
|
981
|
+
icon: jsx(FolderKanban, { className: "h-4 w-4 shrink-0" }),
|
|
982
|
+
feature: PLAN_FEATURES.MODULE_PROJECT,
|
|
983
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_PLANNEX_URL, "https://plannex.antniti.com"),
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
id: "peoplx",
|
|
987
|
+
label: "Peoplx",
|
|
988
|
+
icon: jsx(Users, { className: "h-4 w-4 shrink-0" }),
|
|
989
|
+
feature: PLAN_FEATURES.MODULE_HR,
|
|
990
|
+
baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_HR_URL, "https://peoplx.antniti.com"),
|
|
991
|
+
},
|
|
992
|
+
];
|
|
993
|
+
/**
|
|
994
|
+
* Builds the cross-app link list for <NavUser systemLinks>.
|
|
995
|
+
*
|
|
996
|
+
* The current app is always present even when the org's plan no longer covers
|
|
997
|
+
* it — the user is looking at it, so hiding the link would only make the menu
|
|
998
|
+
* disagree with the screen.
|
|
999
|
+
*/
|
|
1000
|
+
function buildSystemLinks({ orgCode, activeApp, features, }) {
|
|
1001
|
+
if (!orgCode)
|
|
1002
|
+
return [];
|
|
1003
|
+
return APPS.filter(app => app.id === activeApp ||
|
|
1004
|
+
app.feature === null ||
|
|
1005
|
+
hasPlanFeature(features, app.feature)).map(app => ({
|
|
1006
|
+
label: app.label,
|
|
1007
|
+
icon: app.icon,
|
|
1008
|
+
// Same-app link stays relative so it never leaves the current origin.
|
|
1009
|
+
href: app.id === activeApp ? `/${orgCode}` : `${app.baseUrl()}/${orgCode}`,
|
|
1010
|
+
...(app.id === activeApp ? { active: true } : {}),
|
|
1011
|
+
}));
|
|
1012
|
+
}
|
|
1013
|
+
|
|
905
1014
|
// Helper function to check if pathname matches a URL pattern
|
|
906
1015
|
// This prevents false matches like /reports/sales matching /sales
|
|
907
1016
|
// Handles paths with or without [code] prefix
|
|
@@ -1889,7 +1998,19 @@ instance.interceptors.request.use(async (config) => {
|
|
|
1889
1998
|
if (token) {
|
|
1890
1999
|
config.headers.Authorization = `Bearer ${token}`;
|
|
1891
2000
|
}
|
|
1892
|
-
|
|
2001
|
+
// localStorage first, cookie second.
|
|
2002
|
+
//
|
|
2003
|
+
// Both are written by the same state machine, but not at the same moment:
|
|
2004
|
+
// setOrganizationId writes localStorage synchronously and then awaits a
|
|
2005
|
+
// server action for the cookie. Preferring the cookie meant every request
|
|
2006
|
+
// fired during that round trip carried the previous organisation — while
|
|
2007
|
+
// the query params, built from React state, already carried the new one.
|
|
2008
|
+
//
|
|
2009
|
+
// The backend scopes by this header and ignores organization_id in the
|
|
2010
|
+
// query, so those requests asked for organisation A and were handed B, and
|
|
2011
|
+
// the answer landed in the cache under A's key. No amount of cache clearing
|
|
2012
|
+
// reaches that: the entry is wrong, not stale.
|
|
2013
|
+
const organizationId = getOrganizationId() || getOrgFromCookie();
|
|
1893
2014
|
if (organizationId) {
|
|
1894
2015
|
config.headers["X-Organization-ID"] = organizationId;
|
|
1895
2016
|
}
|
|
@@ -1985,5 +2106,5 @@ const getAxiosErrorMessage = (error) => {
|
|
|
1985
2106
|
return String(error);
|
|
1986
2107
|
};
|
|
1987
2108
|
|
|
1988
|
-
export { AccessDenied, ApiError, AppBreadcrumb, AppLayoutShell, AppSidebar, EMPLOYEE_RECORD_OK_EVENT, EMPLOYEE_RECORD_REQUIRED, EMPLOYEE_RECORD_REQUIRED_EVENT, EmployeeRequiredGate, FeatureFlagsProvider, HeaderBackground, NavMain, NavTools, NavUser, OrganizationSwitcher, PermissionGateShell, PermissionProvider, PermissionRulesProvider, ReactQueryProvider, SessionBackedProfileCacheSeeder, SessionRefreshTrigger, SidebarContent, SidebarFooter, SidebarHeader, SidebarProvider, SidebarTrigger, TapMenu, ThemeProvider, instance as axiosInstance, buildUrlWithCode, canAccessNavPermissionRoute, clearAccessTokenCache, clearOrganizationId, decodeJWT, filterNavigationModulesByPermission, filterNavigationToolsByPermission, getAccessToken, getActiveModule, getActiveSubModule, getAxiosErrorMessage, getOrganizationId, getQueryClientConfig, getRequiredChildGroups, isLikelyTransientNetworkError, isPathActive, normalizePathnameForPermissionRules, resolveUiRoutePermission, runGlobalRequestPrecheck, runWithTransientRetry, setOrganizationId, toApiError, unwrapApiResponse, updateOrganizationId, useClearOrgOnUserChange, useFeatureFlag, useFeatureFlags, useInvalidateQueriesOnOrgChange, useKeycloakRoles, useOrganizationIdState, usePermissionRules, useSessionRefresh, useSidebar, useSidebarToggle };
|
|
2109
|
+
export { AccessDenied, ApiError, AppBreadcrumb, AppLayoutShell, AppSidebar, EMPLOYEE_RECORD_OK_EVENT, EMPLOYEE_RECORD_REQUIRED, EMPLOYEE_RECORD_REQUIRED_EVENT, EmployeeRequiredGate, FeatureFlagsProvider, HeaderBackground, NavMain, NavTools, NavUser, OrganizationSwitcher, PLAN_FEATURES, PermissionGateShell, PermissionProvider, PermissionRulesProvider, ReactQueryProvider, SessionBackedProfileCacheSeeder, SessionRefreshTrigger, SidebarContent, SidebarFooter, SidebarHeader, SidebarProvider, SidebarTrigger, TapMenu, ThemeProvider, instance as axiosInstance, buildSystemLinks, buildUrlWithCode, canAccessNavPermissionRoute, clearAccessTokenCache, clearOrganizationId, decodeJWT, filterNavigationModulesByPermission, filterNavigationToolsByPermission, getAccessToken, getActiveModule, getActiveSubModule, getAxiosErrorMessage, getOrganizationId, getQueryClientConfig, getRequiredChildGroups, hasPlanFeature, isLikelyTransientNetworkError, isPathActive, normalizePathnameForPermissionRules, resolveUiRoutePermission, runGlobalRequestPrecheck, runWithTransientRetry, setOrganizationId, toApiError, unwrapApiResponse, updateOrganizationId, useClearOrgOnUserChange, useFeatureFlag, useFeatureFlags, useInvalidateQueriesOnOrgChange, useKeycloakRoles, useOrganizationIdState, usePermissionRules, useSessionRefresh, useSidebar, useSidebarToggle };
|
|
1989
2110
|
//# sourceMappingURL=index.esm.js.map
|