@eintrek/erp-shell 0.1.49 → 0.1.51

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 CHANGED
@@ -958,18 +958,35 @@ const PLAN_FEATURES = {
958
958
  MODULE_INVENTORY: "module.inventory",
959
959
  MODULE_PROJECT: "module.project",
960
960
  MODULE_SECRETARIAT: "module.secretariat",
961
+ /** AI pack (paid or trial): AI calls on AntNiti's key while credits remain. */
962
+ AI: "ai",
961
963
  };
962
- /** True when plan features include key (with legacy basic_accounting_hr alias). */
964
+ /** Keys the Accounx add-on carries with it (same alias as org_effective_features). */
965
+ const ACCOUNTING_SUB_KEYS = [
966
+ PLAN_FEATURES.MODULE_SALES,
967
+ PLAN_FEATURES.MODULE_PURCHASING,
968
+ PLAN_FEATURES.MODULE_SECRETARIAT,
969
+ ];
970
+ /**
971
+ * True when plan features include key. Aliases, mirroring the backend:
972
+ * legacy basic_accounting_hr → module.hr + module.accounting (+ its sub-keys);
973
+ * module.accounting → module.sales, module.purchasing, module.secretariat.
974
+ */
963
975
  function hasPlanFeature(features, feature) {
964
976
  if (!features?.length)
965
977
  return false;
966
978
  if (features.includes(feature))
967
979
  return true;
968
980
  if ((feature === PLAN_FEATURES.MODULE_HR ||
969
- feature === PLAN_FEATURES.MODULE_ACCOUNTING) &&
981
+ feature === PLAN_FEATURES.MODULE_ACCOUNTING ||
982
+ ACCOUNTING_SUB_KEYS.includes(feature)) &&
970
983
  features.includes(PLAN_FEATURES.BASIC_ACCOUNTING_HR)) {
971
984
  return true;
972
985
  }
986
+ if (ACCOUNTING_SUB_KEYS.includes(feature) &&
987
+ features.includes(PLAN_FEATURES.MODULE_ACCOUNTING)) {
988
+ return true;
989
+ }
973
990
  if (feature === PLAN_FEATURES.BASIC_ACCOUNTING_HR &&
974
991
  features.includes(PLAN_FEATURES.MODULE_HR) &&
975
992
  features.includes(PLAN_FEATURES.MODULE_ACCOUNTING)) {
@@ -993,35 +1010,36 @@ const APPS = [
993
1010
  id: "platform",
994
1011
  label: "แพลตฟอร์ม",
995
1012
  icon: jsx(Building2, { className: "h-4 w-4 shrink-0" }),
996
- feature: null,
1013
+ features: null,
997
1014
  baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_PLATFORM_URL, "https://platform.antniti.com"),
998
1015
  },
999
1016
  {
1000
1017
  id: "accounx",
1001
1018
  label: "Accounx",
1002
1019
  icon: jsx(Calculator, { className: "h-4 w-4 shrink-0" }),
1003
- feature: PLAN_FEATURES.MODULE_ACCOUNTING,
1020
+ features: [PLAN_FEATURES.MODULE_ACCOUNTING],
1004
1021
  baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_ACCOUNTING_URL, "https://accounx.antniti.com"),
1005
1022
  },
1006
1023
  {
1007
1024
  id: "invenx",
1008
1025
  label: "Invenx",
1009
1026
  icon: jsx(Warehouse, { className: "h-4 w-4 shrink-0" }),
1010
- feature: PLAN_FEATURES.MODULE_INVENTORY,
1027
+ features: [PLAN_FEATURES.MODULE_INVENTORY],
1011
1028
  baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_INVENX_URL, "https://invenx.antniti.com"),
1012
1029
  },
1013
1030
  {
1014
1031
  id: "plannex",
1015
1032
  label: "Plannex",
1016
1033
  icon: jsx(FolderKanban, { className: "h-4 w-4 shrink-0" }),
1017
- feature: PLAN_FEATURES.MODULE_PROJECT,
1034
+ // Tasks, day-logs and work records are free with HR; projects need the add-on.
1035
+ features: [PLAN_FEATURES.MODULE_HR, PLAN_FEATURES.MODULE_PROJECT],
1018
1036
  baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_PLANNEX_URL, "https://plannex.antniti.com"),
1019
1037
  },
1020
1038
  {
1021
1039
  id: "peoplx",
1022
1040
  label: "Peoplx",
1023
1041
  icon: jsx(Users, { className: "h-4 w-4 shrink-0" }),
1024
- feature: PLAN_FEATURES.MODULE_HR,
1042
+ features: [PLAN_FEATURES.MODULE_HR],
1025
1043
  baseUrl: () => normaliseBase(process.env.NEXT_PUBLIC_HR_URL, "https://peoplx.antniti.com"),
1026
1044
  },
1027
1045
  ];
@@ -1036,8 +1054,8 @@ function buildSystemLinks({ orgCode, activeApp, features, }) {
1036
1054
  if (!orgCode)
1037
1055
  return [];
1038
1056
  return APPS.filter(app => app.id === activeApp ||
1039
- app.feature === null ||
1040
- hasPlanFeature(features, app.feature)).map(app => ({
1057
+ app.features === null ||
1058
+ app.features.some(key => hasPlanFeature(features, key))).map(app => ({
1041
1059
  label: app.label,
1042
1060
  icon: app.icon,
1043
1061
  // Same-app link stays relative so it never leaves the current origin.
@@ -1071,7 +1089,7 @@ function samePage(pathname, url) {
1071
1089
  const strip = (p) => (p.length > 1 ? p.replace(/\/+$/, "") : p);
1072
1090
  return strip(pathname) === strip(url);
1073
1091
  }
1074
- function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, chrome = "brand", }) {
1092
+ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, chrome = "brand", highlightActiveModule = false, }) {
1075
1093
  const workspace = chrome === "workspace";
1076
1094
  const params = useParams();
1077
1095
  const pathname = usePathname();
@@ -1103,8 +1121,9 @@ function NavMain({ items, orgCode, closeOnNavigation = false, approvalCounts, ch
1103
1121
  isPathActive(pathname, subPage.url)));
1104
1122
  // Parent only active when path matches its URL exactly AND no child
1105
1123
  // is active (so parent+child don't both light up).
1106
- const isItemActive = (workspace ? samePage(pathname, itemUrl) : pathname === itemUrl) &&
1107
- !hasActiveSubItem;
1124
+ const isItemActive = (highlightActiveModule && !item.subModules?.length && !!item.isActive) ||
1125
+ ((workspace ? samePage(pathname, itemUrl) : pathname === itemUrl) &&
1126
+ !hasActiveSubItem);
1108
1127
  return { itemUrl, activeSubItemUrl, hasActiveSubItem, isItemActive };
1109
1128
  });
1110
1129
  // A group opens when its page becomes current and otherwise stays as the
@@ -1263,7 +1282,7 @@ function SidebarHeader({ children, className }) {
1263
1282
  return jsx("div", { className: cn("px-2 py-3", className), children: children });
1264
1283
  }
1265
1284
 
1266
- function AppSidebar({ modules, tools, activeModule, orgCode, approvalCounts, closeOnNavigation = false, header, footer, bottom, chrome = "brand", className, }) {
1285
+ function AppSidebar({ modules, tools, activeModule, orgCode, approvalCounts, closeOnNavigation = false, highlightActiveModule = false, header, footer, bottom, chrome = "brand", className, }) {
1267
1286
  const { open } = useSidebar();
1268
1287
  const modulesWithActiveState = React.useMemo(() => modules.map(m => ({
1269
1288
  ...m,
@@ -1274,7 +1293,7 @@ function AppSidebar({ modules, tools, activeModule, orgCode, approvalCounts, clo
1274
1293
  if (chrome === "workspace") {
1275
1294
  return (jsxs("div", { className: cn("flex h-screen w-[244px] shrink-0 flex-col overflow-hidden border-r border-sidebar-border bg-sidebar text-sidebar-foreground",
1276
1295
  // As a drawer (≤1024px) it floats over the page and needs the lift.
1277
- "max-[1024px]:shadow-2xl", className), children: [header ? jsx("div", { className: "shrink-0 px-[18px] pt-8 pb-6", children: header }) : null, jsxs(SidebarContent, { className: "flex-1 overflow-y-auto px-[18px]", children: [jsx(NavMain, { items: modulesWithActiveState, orgCode: orgCode, approvalCounts: approvalCounts, closeOnNavigation: closeOnNavigation, chrome: "workspace" }), jsx(NavTools, { tools: tools, closeOnNavigation: closeOnNavigation })] }), bottom ? jsx("div", { className: "shrink-0 px-[18px] pt-6", children: bottom }) : null, jsx("div", { className: "shrink-0 px-[18px] pb-3", children: footer })] }));
1296
+ "max-[1024px]:shadow-2xl", className), children: [header ? jsx("div", { className: "shrink-0 px-[18px] pt-8 pb-6", children: header }) : null, jsxs(SidebarContent, { className: "flex-1 overflow-y-auto px-[18px]", children: [jsx(NavMain, { items: modulesWithActiveState, orgCode: orgCode, approvalCounts: approvalCounts, closeOnNavigation: closeOnNavigation, chrome: "workspace", highlightActiveModule: highlightActiveModule }), jsx(NavTools, { tools: tools, closeOnNavigation: closeOnNavigation })] }), bottom ? jsx("div", { className: "shrink-0 px-[18px] pt-6", children: bottom }) : null, jsx("div", { className: "shrink-0 px-[18px] pb-3", children: footer })] }));
1278
1297
  }
1279
1298
  return (jsxs("div", { className: cn("bg-sidebar shrink-0 flex flex-col overflow-hidden shadow-2xl h-screen w-[var(--sidebar-width-mobile)]", "!w-76 xl:rounded-b-4xl xl:rounded-tl-4xl xl:m-5 xl:h-[calc(100vh-2.5rem)]", className), children: [jsx(SidebarHeader, { children: header }), jsxs(SidebarContent, { className: "pl-2 pr-2 flex-1 overflow-y-auto", children: [jsx(NavMain, { items: modulesWithActiveState, orgCode: orgCode, approvalCounts: approvalCounts, closeOnNavigation: closeOnNavigation }), jsx(NavTools, { tools: tools, closeOnNavigation: closeOnNavigation })] }), jsx(SidebarFooter, { className: "pl-2 pr-2", children: footer })] }));
1280
1299
  }