indas-ui 0.1.3 → 0.1.5

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.
Files changed (133) hide show
  1. package/dist/auth.d.ts +1 -0
  2. package/dist/auth.js +5 -0
  3. package/dist/cjs/auth.js +10 -0
  4. package/dist/cjs/components/chat/ai-messages.js +3 -2
  5. package/dist/cjs/components/chat/chat.js +4 -3
  6. package/dist/cjs/components/dashboard/FilterBar.js +31 -8
  7. package/dist/cjs/components/dashboard/charts/Area.js +6 -4
  8. package/dist/cjs/components/dashboard/charts/Bar.js +6 -4
  9. package/dist/cjs/components/dashboard/charts/FlowMap.js +2 -1
  10. package/dist/cjs/components/dashboard/charts/Funnel.js +2 -1
  11. package/dist/cjs/components/dashboard/charts/GeoMap.js +2 -1
  12. package/dist/cjs/components/dashboard/charts/Line.js +5 -3
  13. package/dist/cjs/components/dashboard/charts/Pareto.js +2 -1
  14. package/dist/cjs/components/dashboard/charts/Sankey.js +4 -3
  15. package/dist/cjs/components/dashboard/charts/Sparkline.js +2 -1
  16. package/dist/cjs/components/dashboard/charts/Treemap.js +2 -1
  17. package/dist/cjs/components/dashboard/charts/index.js +7 -1
  18. package/dist/cjs/components/dashboard/kpi/KpiBreakdown.js +3 -2
  19. package/dist/cjs/components/dashboard/kpi/KpiComparison.js +2 -1
  20. package/dist/cjs/components/dashboard/kpi/KpiQuickStats.js +2 -1
  21. package/dist/cjs/components/dashboard/kpi/KpiRating.js +3 -2
  22. package/dist/cjs/components/dashboard/time-range.js +71 -27
  23. package/dist/cjs/components/datagrid/columns/ColumnContextMenu.js +2 -1
  24. package/dist/cjs/components/datagrid/controls/menu/view/CardView.js +2 -1
  25. package/dist/cjs/components/datagrid/controls/menu/view/ChartView.js +2 -1
  26. package/dist/cjs/components/datagrid/utils/grid-helpers.js +6 -5
  27. package/dist/cjs/components/layout/footer.js +2 -1
  28. package/dist/cjs/components/layout/side-panel.js +4 -1
  29. package/dist/cjs/components/layout/sidebar.js +17 -2
  30. package/dist/cjs/components/messaging/messaging-panel-content.js +2 -2
  31. package/dist/cjs/components/ui/display/stats-card.js +2 -1
  32. package/dist/cjs/components/ui/navigation/tabs.js +4 -1
  33. package/dist/cjs/contexts/EmailContext.js +3 -2
  34. package/dist/cjs/contexts/MessagingContext.js +2 -2
  35. package/dist/cjs/contexts/NavigationContext.js +17 -2
  36. package/dist/cjs/contexts/NotificationContext.js +2 -2
  37. package/dist/cjs/contexts/SessionAdapterContext.js +8 -0
  38. package/dist/cjs/hooks/useApproval.js +2 -2
  39. package/dist/cjs/hooks/useBusinessAudit.js +2 -2
  40. package/dist/cjs/hooks/useDraft.js +2 -2
  41. package/dist/cjs/lib/api/utility/menu.js +8 -7
  42. package/dist/cjs/lib/number-format.js +60 -0
  43. package/dist/cjs/lib/utils.js +4 -3
  44. package/dist/cjs/providers.js +3 -3
  45. package/dist/components/auth/index.js +0 -1
  46. package/dist/components/chat/ai-messages.js +3 -2
  47. package/dist/components/chat/chat.js +4 -3
  48. package/dist/components/chat/index.js +0 -1
  49. package/dist/components/dashboard/FilterBar.d.ts +5 -1
  50. package/dist/components/dashboard/FilterBar.js +31 -8
  51. package/dist/components/dashboard/charts/Area.d.ts +5 -1
  52. package/dist/components/dashboard/charts/Area.js +6 -4
  53. package/dist/components/dashboard/charts/Bar.d.ts +5 -1
  54. package/dist/components/dashboard/charts/Bar.js +6 -4
  55. package/dist/components/dashboard/charts/FlowMap.js +2 -1
  56. package/dist/components/dashboard/charts/Funnel.js +2 -1
  57. package/dist/components/dashboard/charts/GeoMap.js +2 -1
  58. package/dist/components/dashboard/charts/Line.d.ts +5 -1
  59. package/dist/components/dashboard/charts/Line.js +5 -3
  60. package/dist/components/dashboard/charts/Pareto.js +2 -1
  61. package/dist/components/dashboard/charts/Sankey.js +4 -3
  62. package/dist/components/dashboard/charts/Sparkline.js +2 -1
  63. package/dist/components/dashboard/charts/Treemap.js +2 -1
  64. package/dist/components/dashboard/charts/index.d.ts +1 -0
  65. package/dist/components/dashboard/charts/index.js +2 -1
  66. package/dist/components/dashboard/index.js +0 -1
  67. package/dist/components/dashboard/kpi/KpiBreakdown.js +3 -2
  68. package/dist/components/dashboard/kpi/KpiComparison.js +2 -1
  69. package/dist/components/dashboard/kpi/KpiQuickStats.js +2 -1
  70. package/dist/components/dashboard/kpi/KpiRating.js +3 -2
  71. package/dist/components/dashboard/kpi/index.js +0 -1
  72. package/dist/components/dashboard/time-range.d.ts +12 -1
  73. package/dist/components/dashboard/time-range.js +71 -27
  74. package/dist/components/datagrid/cells/index.js +0 -1
  75. package/dist/components/datagrid/columns/ColumnContextMenu.js +2 -1
  76. package/dist/components/datagrid/controls/menu/grouping/index.js +0 -1
  77. package/dist/components/datagrid/controls/menu/index.js +0 -1
  78. package/dist/components/datagrid/controls/menu/view/CardView.js +2 -1
  79. package/dist/components/datagrid/controls/menu/view/ChartView.js +2 -1
  80. package/dist/components/datagrid/index.js +0 -1
  81. package/dist/components/datagrid/utils/grid-helpers.d.ts +1 -1
  82. package/dist/components/datagrid/utils/grid-helpers.js +3 -2
  83. package/dist/components/forms/date-picker/index.js +0 -1
  84. package/dist/components/forms/dropdown/index.js +0 -1
  85. package/dist/components/forms/file-attachment/index.js +0 -1
  86. package/dist/components/forms/index.js +0 -1
  87. package/dist/components/forms/remark-input/index.js +0 -1
  88. package/dist/components/index.js +0 -1
  89. package/dist/components/layout/footer.js +2 -1
  90. package/dist/components/layout/index.js +0 -1
  91. package/dist/components/layout/side-panel.js +4 -1
  92. package/dist/components/layout/sidebar.js +17 -2
  93. package/dist/components/master/editable-cells/index.js +0 -1
  94. package/dist/components/master/index.js +0 -1
  95. package/dist/components/messaging/messaging-panel-content.js +2 -2
  96. package/dist/components/modals/index.js +0 -1
  97. package/dist/components/ui/display/stats-card.js +2 -1
  98. package/dist/components/ui/feedback/badge.d.ts +1 -1
  99. package/dist/components/ui/index.js +0 -1
  100. package/dist/components/ui/navigation/tabs.js +4 -1
  101. package/dist/contexts/EmailContext.js +3 -2
  102. package/dist/contexts/MessagingContext.js +2 -2
  103. package/dist/contexts/NavigationContext.js +17 -2
  104. package/dist/contexts/NotificationContext.js +2 -2
  105. package/dist/contexts/SessionAdapterContext.d.ts +5 -0
  106. package/dist/contexts/SessionAdapterContext.js +7 -0
  107. package/dist/hooks/index.js +0 -1
  108. package/dist/hooks/useApproval.js +2 -2
  109. package/dist/hooks/useBusinessAudit.js +2 -2
  110. package/dist/hooks/useDraft.js +2 -2
  111. package/dist/index.js +0 -1
  112. package/dist/lib/api/activity/audit/index.js +0 -1
  113. package/dist/lib/api/activity/email/index.js +0 -1
  114. package/dist/lib/api/activity/index.js +0 -1
  115. package/dist/lib/api/activity/notifications/index.js +0 -1
  116. package/dist/lib/api/activity/remarks/index.js +0 -1
  117. package/dist/lib/api/approval/index.js +0 -1
  118. package/dist/lib/api/auth/index.js +0 -1
  119. package/dist/lib/api/core/index.js +0 -1
  120. package/dist/lib/api/draft/index.js +0 -1
  121. package/dist/lib/api/enquiry/index.js +0 -1
  122. package/dist/lib/api/estimation/index.js +0 -1
  123. package/dist/lib/api/index.js +0 -1
  124. package/dist/lib/api/master/index.js +0 -1
  125. package/dist/lib/api/utility/index.js +0 -1
  126. package/dist/lib/api/utility/menu.d.ts +7 -3
  127. package/dist/lib/api/utility/menu.js +8 -7
  128. package/dist/lib/number-format.d.ts +18 -0
  129. package/dist/lib/number-format.js +54 -0
  130. package/dist/lib/utils.js +4 -3
  131. package/dist/providers.d.ts +0 -1
  132. package/dist/providers.js +2 -2
  133. package/package.json +23 -8
@@ -5,6 +5,7 @@ exports.KpiQuickStats = KpiQuickStats;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const utils_1 = require("../../../lib/utils.js");
7
7
  const kpi_shell_1 = require("./kpi-shell.js");
8
+ const number_format_1 = require("../../../lib/number-format.js");
8
9
  /**
9
10
  * KpiQuickStats - KPI card with grid of icon stats
10
11
  *
@@ -36,6 +37,6 @@ function KpiQuickStats({ title, stats, columns = 2, loading, className }) {
36
37
  };
37
38
  return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl p-5 border border-[rgb(var(--bd-default))] shadow-sm', className), children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))] mb-3", children: title }), (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('grid gap-x-3 gap-y-2', gridClasses[columns]), children: stats.map((stat, index) => {
38
39
  const Icon = stat.icon;
39
- return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(Icon, { className: (0, utils_1.cn)('w-4 h-4', getIconColorClass(stat.iconColor)) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-lg font-bold text-[rgb(var(--fg-default))]", children: typeof stat.value === 'number' ? stat.value.toLocaleString() : stat.value }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-[rgb(var(--fg-muted))]", children: stat.label })] })] }, index));
40
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(Icon, { className: (0, utils_1.cn)('w-4 h-4', getIconColorClass(stat.iconColor)) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-lg font-bold text-[rgb(var(--fg-default))]", children: typeof stat.value === 'number' ? (0, number_format_1.formatNumber)(stat.value) : stat.value }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-[rgb(var(--fg-muted))]", children: stat.label })] })] }, index));
40
41
  }) })] }));
41
42
  }
@@ -5,6 +5,7 @@ exports.KpiRating = KpiRating;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const lucide_react_1 = require("lucide-react");
7
7
  const utils_1 = require("../../../lib/utils.js");
8
+ const number_format_1 = require("../../../lib/number-format.js");
8
9
  /**
9
10
  * KpiRating - KPI card with star rating display
10
11
  *
@@ -30,9 +31,9 @@ function KpiRating({ title, score, maxScore = 5, reviewCount, status, statusType
30
31
  return 'bg-[rgb(var(--color-warning))]';
31
32
  return 'bg-[rgb(var(--color-error))]';
32
33
  };
33
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl p-5 border border-[rgb(var(--bd-default))] shadow-sm relative group', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), tooltip && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-5 h-5 rounded-full bg-[rgb(var(--bg-subtle))] flex items-center justify-center cursor-help hover:bg-[rgb(var(--color-primary))]/10 transition-colors peer", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Info, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "absolute right-0 top-7 w-72 p-3 bg-[rgb(var(--bg-surface))] border border-[rgb(var(--bd-default))] rounded-lg shadow-lg opacity-0 invisible peer-hover:opacity-100 peer-hover:visible transition-all z-10", children: [tooltip.formula && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium text-[rgb(var(--fg-default))] mb-2", children: "Formula:" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-[rgb(var(--bg-subtle))] rounded p-2 mb-3", children: (0, jsx_runtime_1.jsx)("p", { className: "text-[10px] font-mono text-[rgb(var(--fg-muted))]", children: tooltip.formula }) })] })), tooltip.description && ((0, jsx_runtime_1.jsx)("p", { className: "text-[10px] text-[rgb(var(--fg-muted))] mb-3", children: tooltip.description })), tooltip.breakdown && tooltip.breakdown.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-[rgb(var(--bd-default))] pt-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium text-[rgb(var(--fg-default))] mb-2", children: "Rating Breakdown:" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1.5", children: tooltip.breakdown.map((item) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-3", children: item.stars }), (0, jsx_runtime_1.jsx)("svg", { className: "w-3 h-3 text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20", children: (0, jsx_runtime_1.jsx)("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 h-1.5 bg-[rgb(var(--bg-subtle))] rounded-full overflow-hidden", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('h-full rounded-full', getBreakdownBarColor(item.percentage)), style: { width: `${item.percentage}%` } }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-10 text-right", children: item.count.toLocaleString() }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-6 text-right", children: [item.percentage, "%"] })] }, item.stars))) })] }))] })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("p", { className: "text-4xl font-bold text-[rgb(var(--fg-default))]", children: score }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex gap-0.5", children: Array.from({ length: maxScore }, (_, i) => {
34
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('bg-[rgb(var(--bg-surface))] rounded-xl p-5 border border-[rgb(var(--bd-default))] shadow-sm relative group', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-[rgb(var(--fg-muted))]", children: title }), tooltip && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-5 h-5 rounded-full bg-[rgb(var(--bg-subtle))] flex items-center justify-center cursor-help hover:bg-[rgb(var(--color-primary))]/10 transition-colors peer", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Info, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "absolute right-0 top-7 w-72 p-3 bg-[rgb(var(--bg-surface))] border border-[rgb(var(--bd-default))] rounded-lg shadow-lg opacity-0 invisible peer-hover:opacity-100 peer-hover:visible transition-all z-10", children: [tooltip.formula && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium text-[rgb(var(--fg-default))] mb-2", children: "Formula:" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-[rgb(var(--bg-subtle))] rounded p-2 mb-3", children: (0, jsx_runtime_1.jsx)("p", { className: "text-[10px] font-mono text-[rgb(var(--fg-muted))]", children: tooltip.formula }) })] })), tooltip.description && ((0, jsx_runtime_1.jsx)("p", { className: "text-[10px] text-[rgb(var(--fg-muted))] mb-3", children: tooltip.description })), tooltip.breakdown && tooltip.breakdown.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "border-t border-[rgb(var(--bd-default))] pt-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium text-[rgb(var(--fg-default))] mb-2", children: "Rating Breakdown:" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1.5", children: tooltip.breakdown.map((item) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-3", children: item.stars }), (0, jsx_runtime_1.jsx)("svg", { className: "w-3 h-3 text-yellow-400", fill: "currentColor", viewBox: "0 0 20 20", children: (0, jsx_runtime_1.jsx)("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 h-1.5 bg-[rgb(var(--bg-subtle))] rounded-full overflow-hidden", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('h-full rounded-full', getBreakdownBarColor(item.percentage)), style: { width: `${item.percentage}%` } }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-10 text-right", children: (0, number_format_1.formatNumber)(item.count) }), (0, jsx_runtime_1.jsxs)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))] w-6 text-right", children: [item.percentage, "%"] })] }, item.stars))) })] }))] })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("p", { className: "text-4xl font-bold text-[rgb(var(--fg-default))]", children: score }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex gap-0.5", children: Array.from({ length: maxScore }, (_, i) => {
34
35
  const starIndex = i + 1;
35
36
  const isFilled = starIndex <= filledStars || (starIndex === filledStars + 1 && hasPartialStar);
36
37
  return ((0, jsx_runtime_1.jsx)("svg", { className: (0, utils_1.cn)('w-5 h-5 transition-transform hover:scale-110 cursor-pointer', isFilled ? 'text-yellow-400' : 'text-yellow-400/30'), fill: "currentColor", viewBox: "0 0 20 20", children: (0, jsx_runtime_1.jsx)("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }, i));
37
- }) }), reviewCount !== undefined && ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-[rgb(var(--fg-muted))] mt-1", children: [reviewCount.toLocaleString(), " reviews"] }))] }), status && ((0, jsx_runtime_1.jsx)("div", { className: "ml-auto text-right", children: (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('text-xs px-2 py-0.5 rounded-full', getStatusStyles(statusType)), children: status }) }))] }), (change !== undefined || periodLabel) && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between pt-3 mt-3 border-t border-[rgb(var(--bd-default))]", children: [change !== undefined && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [change > 0 ? ((0, jsx_runtime_1.jsx)(lucide_react_1.TrendingUp, { className: "w-3 h-3 text-[rgb(var(--color-success))]" })) : change < 0 ? ((0, jsx_runtime_1.jsx)(lucide_react_1.TrendingDown, { className: "w-3 h-3 text-[rgb(var(--color-error))]" })) : null, (0, jsx_runtime_1.jsxs)("span", { className: (0, utils_1.cn)('text-xs', change > 0 ? 'text-[rgb(var(--color-success))]' : change < 0 ? 'text-[rgb(var(--color-error))]' : 'text-[rgb(var(--fg-muted))]'), children: [change > 0 ? '+' : '', change, " ", changeLabel] })] })), periodLabel && ((0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))]", children: periodLabel }))] }))] }));
38
+ }) }), reviewCount !== undefined && ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-[rgb(var(--fg-muted))] mt-1", children: [(0, number_format_1.formatNumber)(reviewCount), " reviews"] }))] }), status && ((0, jsx_runtime_1.jsx)("div", { className: "ml-auto text-right", children: (0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)('text-xs px-2 py-0.5 rounded-full', getStatusStyles(statusType)), children: status }) }))] }), (change !== undefined || periodLabel) && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between pt-3 mt-3 border-t border-[rgb(var(--bd-default))]", children: [change !== undefined && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [change > 0 ? ((0, jsx_runtime_1.jsx)(lucide_react_1.TrendingUp, { className: "w-3 h-3 text-[rgb(var(--color-success))]" })) : change < 0 ? ((0, jsx_runtime_1.jsx)(lucide_react_1.TrendingDown, { className: "w-3 h-3 text-[rgb(var(--color-error))]" })) : null, (0, jsx_runtime_1.jsxs)("span", { className: (0, utils_1.cn)('text-xs', change > 0 ? 'text-[rgb(var(--color-success))]' : change < 0 ? 'text-[rgb(var(--color-error))]' : 'text-[rgb(var(--fg-muted))]'), children: [change > 0 ? '+' : '', change, " ", changeLabel] })] })), periodLabel && ((0, jsx_runtime_1.jsx)("span", { className: "text-[10px] text-[rgb(var(--fg-muted))]", children: periodLabel }))] }))] }));
38
39
  }
@@ -43,44 +43,77 @@ const fiscalWeekCount = (fyStart) => {
43
43
  return wk;
44
44
  };
45
45
  exports.fiscalWeekCount = fiscalWeekCount;
46
- // "this" anchors to the FY's first period (W1 / Apr / Q1), per fiscal reporting.
47
- const rangeFromSelection = (sel, fyStart) => {
46
+ const startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
47
+ const addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
48
+ // Monday of the week holding `d` (weeks run Monday to Sunday, as the fiscal weeks do).
49
+ const mondayOf = (d) => addDays(d, -((d.getDay() + 6) % 7));
50
+ /**
51
+ * The dates a selection covers.
52
+ *
53
+ * Quick picks (This / Last …) count from `today`: "This week" is the week holding today, "Last
54
+ * month" the calendar month before this one, "This quarter" the fiscal quarter holding today.
55
+ * They used to anchor to the financial year's first period, so "This week" meant Week 1 in April.
56
+ * A "This …" range runs to today, since nothing after today has happened yet.
57
+ *
58
+ * A numbered pick (W27, month "9", Q3, a year "2025") is that period of the financial year
59
+ * starting `fyStart`. Year "all" is all time, from the earliest date a book could hold to today.
60
+ */
61
+ const rangeFromSelection = (sel, fyStart, today = new Date()) => {
62
+ const t = startOfDay(today);
48
63
  const fyOpen = new Date(fyStart, 3, 1);
49
64
  const fyClose = new Date(fyStart + 1, 2, 31);
50
65
  const yearOf = (mo) => (mo >= 3 ? fyStart : fyStart + 1);
51
66
  const monthRange = (mo) => ({ from: new Date(yearOf(mo), mo, 1), to: new Date(yearOf(mo), mo + 1, 0) });
52
67
  const type = sel?.type || 'Month';
53
68
  if (type === 'Day') {
54
- const now = new Date();
55
- const y = now.getFullYear(), m = now.getMonth(), d = now.getDate();
56
69
  const pick = sel?.days?.[0] || 'today';
57
- if (pick === 'yesterday') {
58
- const dt = new Date(y, m, d - 1);
59
- return { from: dt, to: dt };
60
- }
61
- if (pick === 'last7')
62
- return { from: new Date(y, m, d - 6), to: new Date(y, m, d) };
63
- if (pick === 'last14')
64
- return { from: new Date(y, m, d - 13), to: new Date(y, m, d) };
65
- if (pick === 'last30')
66
- return { from: new Date(y, m, d - 29), to: new Date(y, m, d) };
67
- return { from: new Date(y, m, d), to: new Date(y, m, d) };
70
+ if (pick === 'yesterday')
71
+ return { from: addDays(t, -1), to: addDays(t, -1) };
72
+ const span = { last7: 7, last14: 14, last30: 30 }[pick];
73
+ return span ? { from: addDays(t, -(span - 1)), to: t } : { from: t, to: t };
68
74
  }
69
75
  if (type === 'Week') {
70
- const pick = sel?.weeks?.[0] || 'W1';
76
+ const pick = sel?.weeks?.[0] || 'this';
77
+ const monday = mondayOf(t);
78
+ if (pick === 'this')
79
+ return { from: monday, to: t };
80
+ if (pick === 'last')
81
+ return { from: addDays(monday, -7), to: addDays(monday, -1) };
82
+ // "Last 2 weeks" is this week and the one before it, to today.
83
+ const weeks = { last2: 2, last4: 4 }[pick];
84
+ if (weeks)
85
+ return { from: addDays(monday, -7 * (weeks - 1)), to: t };
71
86
  const wk = /^W\d+$/i.test(pick) ? parseInt(pick.slice(1)) : 1;
72
87
  return (0, exports.fiscalWeekRange)(fyStart, wk) || { from: fyOpen, to: fyClose };
73
88
  }
74
89
  if (type === 'Quarter') {
75
- const pick = sel?.quarters?.[0];
76
- const qNum = pick && /^q[1-4]$/i.test(pick) ? parseInt(pick.slice(1)) - 1 : 0;
90
+ const pick = sel?.quarters?.[0] || 'this';
91
+ // The fiscal quarter holding today: Apr–Jun is Q1.
92
+ const qStart = new Date(t.getFullYear(), t.getMonth() - (((t.getMonth() - 3 + 12) % 12) % 3), 1);
93
+ if (pick === 'this')
94
+ return { from: qStart, to: t };
95
+ if (pick === 'last')
96
+ return { from: new Date(qStart.getFullYear(), qStart.getMonth() - 3, 1), to: addDays(qStart, -1) };
97
+ const qNum = /^q[1-4]$/i.test(pick) ? parseInt(pick.slice(1)) - 1 : 0;
77
98
  const startMonth = (3 + qNum * 3) % 12;
78
99
  const sy = yearOf(startMonth);
79
100
  return { from: new Date(sy, startMonth, 1), to: new Date(sy, startMonth + 3, 0) };
80
101
  }
81
- if (type === 'Year')
82
- return { from: fyOpen, to: fyClose };
83
- const picks = (sel?.months || []).filter(s => /^\d{1,2}$/.test(s)).map(s => parseInt(s));
102
+ if (type === 'Year') {
103
+ const pick = sel?.years?.[0] || 'this';
104
+ if (pick === 'all')
105
+ return { from: new Date(1970, 0, 1), to: t };
106
+ if (pick === 'last')
107
+ return { from: new Date(fyStart - 1, 3, 1), to: new Date(fyStart, 2, 31) };
108
+ const fy = /^\d{4}$/.test(pick) ? parseInt(pick) : fyStart;
109
+ return { from: new Date(fy, 3, 1), to: new Date(fy + 1, 2, 31) };
110
+ }
111
+ const months = sel?.months || [];
112
+ if (months.includes('this'))
113
+ return { from: new Date(t.getFullYear(), t.getMonth(), 1), to: t };
114
+ if (months.includes('last'))
115
+ return { from: new Date(t.getFullYear(), t.getMonth() - 1, 1), to: new Date(t.getFullYear(), t.getMonth(), 0) };
116
+ const picks = months.filter(s => /^\d{1,2}$/.test(s)).map(s => parseInt(s));
84
117
  if (picks.length > 0) {
85
118
  const ranges = picks.map(monthRange);
86
119
  return {
@@ -88,7 +121,7 @@ const rangeFromSelection = (sel, fyStart) => {
88
121
  to: ranges.reduce((a, b) => (b.to > a.to ? b : a)).to,
89
122
  };
90
123
  }
91
- return monthRange(3);
124
+ return { from: new Date(t.getFullYear(), t.getMonth(), 1), to: t };
92
125
  };
93
126
  exports.rangeFromSelection = rangeFromSelection;
94
127
  // Header subtitle for the selected period. Week/Day show their day span in brackets;
@@ -106,17 +139,28 @@ const buildContextLabel = (sel, fyStart, dateFrom, dateTo, t) => {
106
139
  return `${pick} (${dayRange})`;
107
140
  }
108
141
  if (!dateFrom && !dateTo && sel?.type === 'Week') {
109
- const w = sel.weeks?.[0];
110
- const wk = w && /^W\d+$/i.test(w) ? w.slice(1) : '1';
142
+ const w = sel.weeks?.[0] || 'this';
143
+ const quick = { this: 'This Week', last: 'Last Week', last2: 'Last 2 Weeks', last4: 'Last 4 Weeks' }[w];
144
+ if (quick)
145
+ return `${t(quick)} (${dayRange})`;
146
+ const wk = /^W\d+$/i.test(w) ? w.slice(1) : '1';
111
147
  return `${t('Week')} ${wk} (${dayRange})`;
112
148
  }
113
149
  if (!dateFrom && !dateTo && sel?.type === 'Quarter') {
114
- const q = sel.quarters?.[0];
115
- const label = q && /^q[1-4]$/i.test(q) ? `Q${q.slice(1)}` : 'Q1';
150
+ const q = sel.quarters?.[0] || 'this';
151
+ const label = q === 'this' ? t('This Quarter') : q === 'last' ? t('Last Quarter') : /^q[1-4]$/i.test(q) ? `Q${q.slice(1)}` : 'Q1';
116
152
  return `${label} (${fmtMon(from)} – ${fmtMon(to)})`;
117
153
  }
118
154
  if (!dateFrom && !dateTo && sel?.type === 'Year') {
119
- return `${t('FY')} ${fyStart}-${fyStart + 1}`;
155
+ const y = sel.years?.[0] || 'this';
156
+ if (y === 'all')
157
+ return t('All Time');
158
+ const fy = y === 'last' ? fyStart - 1 : /^\d{4}$/.test(y) ? parseInt(y) : fyStart;
159
+ return `${t('FY')} ${fy}-${fy + 1}`;
160
+ }
161
+ const m0 = sel?.months?.[0];
162
+ if (!dateFrom && !dateTo && sel?.type === 'Month' && (m0 === 'this' || m0 === 'last')) {
163
+ return `${t(m0 === 'this' ? 'This Month' : 'Last Month')} (${dayRange})`;
120
164
  }
121
165
  const sameMonth = from.getFullYear() === to.getFullYear() && from.getMonth() === to.getMonth();
122
166
  if (sameMonth)
@@ -11,6 +11,7 @@ const ui_2 = require("../../ui/index.js");
11
11
  const ui_3 = require("../../ui/index.js");
12
12
  const ui_4 = require("../../ui/index.js");
13
13
  const ui_5 = require("../../ui/index.js");
14
+ const number_format_1 = require("../../../lib/number-format.js");
14
15
  function ColumnContextMenu({ column, table, data, isVisible, position, onClose, onApplyFilter, }) {
15
16
  const [activeSubmenu, setActiveSubmenu] = (0, react_1.useState)(null);
16
17
  const [quickFilterValue, setQuickFilterValue] = (0, react_1.useState)('');
@@ -319,7 +320,7 @@ function ColumnContextMenu({ column, table, data, isVisible, position, onClose,
319
320
  }, className: "w-full flex items-center gap-2 px-2 py-1 text-left text-xs rounded hover:bg-[rgb(var(--bg-subtle))]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Eye, { className: "h-3.5 w-3.5 text-[rgb(var(--fg-muted))] flex-shrink-0" }), (0, jsx_runtime_1.jsx)("span", { className: "truncate flex-1", children: col.label })] }, col.id))) })] }) }, item.id));
320
321
  }
321
322
  if (item.id === 'column-stats' && columnStats) {
322
- return ((0, jsx_runtime_1.jsxs)("div", { className: "p-2 space-y-1.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium text-[rgb(var(--fg-default))]", children: "Column Statistics" }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Total:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.totalCount.toLocaleString() }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Unique:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.uniqueCount.toLocaleString() }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Null:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.nullCount.toLocaleString() }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Type:" }), (0, jsx_runtime_1.jsx)("div", { className: "text-right", children: (0, jsx_runtime_1.jsx)(ui_5.Badge, { variant: "outline", className: "text-xs h-4", children: columnStats.dataType }) }), columnStats.dataType === 'number' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Min:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.min }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Max:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.max }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Avg:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.avg?.toFixed(2) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Sum:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.sum?.toLocaleString() })] }))] })] }, item.id));
323
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-2 space-y-1.5", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium text-[rgb(var(--fg-default))]", children: "Column Statistics" }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Total:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: (0, number_format_1.formatNumber)(columnStats.totalCount) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Unique:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: (0, number_format_1.formatNumber)(columnStats.uniqueCount) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Null:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: (0, number_format_1.formatNumber)(columnStats.nullCount) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Type:" }), (0, jsx_runtime_1.jsx)("div", { className: "text-right", children: (0, jsx_runtime_1.jsx)(ui_5.Badge, { variant: "outline", className: "text-xs h-4", children: columnStats.dataType }) }), columnStats.dataType === 'number' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Min:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.min }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Max:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.max }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Avg:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: columnStats.avg?.toFixed(2) }), (0, jsx_runtime_1.jsx)("span", { className: "text-[rgb(var(--fg-muted))]", children: "Sum:" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-right", children: (0, number_format_1.formatNumber)(columnStats.sum) })] }))] })] }, item.id));
323
324
  }
324
325
  }
325
326
  const Icon = item.icon;
@@ -10,6 +10,7 @@ const ui_1 = require("../../../../ui/index.js");
10
10
  const SelectionCell_1 = require("../../../cells/SelectionCell.js");
11
11
  const skeleton_1 = require("../../../../ui/feedback/skeleton.js");
12
12
  const LanguageContext_1 = require("../../../../../contexts/LanguageContext.js");
13
+ const number_format_1 = require("../../../../../lib/number-format.js");
13
14
  const sizeConfig = {
14
15
  compact: {
15
16
  grid: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
@@ -131,7 +132,7 @@ function CardView({ data, columns, onRowClick, selectedRows, onRowSelect, isLoad
131
132
  return value ? ((0, jsx_runtime_1.jsx)(ui_1.Badge, { variant: "default", className: "h-4.5 text-[0.6rem] px-1.5 py-0 bg-[rgb(var(--color-success))]/10 text-[rgb(var(--color-success))] border-0 font-medium", children: t('Yes') })) : ((0, jsx_runtime_1.jsx)(ui_1.Badge, { variant: "secondary", className: "h-4.5 text-[0.6rem] px-1.5 py-0 bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-muted))] border-0 font-medium", children: t('No') }));
132
133
  }
133
134
  if (typeof value === 'number')
134
- return value.toLocaleString();
135
+ return (0, number_format_1.formatNumber)(value);
135
136
  return value?.toString() || '—';
136
137
  }, [t]);
137
138
  const getFieldLabel = (0, react_1.useCallback)((column) => {
@@ -48,6 +48,7 @@ const ui_1 = require("../../../../ui/index.js");
48
48
  const ui_2 = require("../../../../ui/index.js");
49
49
  const components_1 = require("../../../../index.js");
50
50
  const ui_3 = require("../../../../ui/index.js");
51
+ const number_format_1 = require("../../../../../lib/number-format.js");
51
52
  const CHART_COLORS = [
52
53
  '#3b82f6', // Blue
53
54
  '#ef4444', // Red
@@ -381,7 +382,7 @@ function DataVisualization({ data, columns, title = "Data Insights" }) {
381
382
  if (data.length === 0) {
382
383
  return ((0, jsx_runtime_1.jsx)(ui_1.Card, { className: "p-8", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center text-gray-500", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.BarChart3, { className: "h-12 w-12 mx-auto mb-4 opacity-50" }), (0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-medium mb-2", children: "No Data Available" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm", children: "Add some data to view visualizations" })] }) }));
383
384
  }
384
- return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6 p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-2xl font-bold tracking-tight", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-gray-600 mt-1", children: ["Visual analysis of ", data.length, " records"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-2", children: [(0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'bar' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('bar'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.BarChart3, { className: "h-4 w-4 mr-2" }), "Bar"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'line' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('line'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.LineChart, { className: "h-4 w-4 mr-2" }), "Line"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'area' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('area'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Activity, { className: "h-4 w-4 mr-2" }), "Area"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'pie' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('pie'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.PieChart, { className: "h-4 w-4 mr-2" }), "Pie"] })] })] }), summaryStats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-blue-600", children: summaryStats.sum.toLocaleString() }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Total" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-green-600", children: summaryStats.avg.toFixed(1) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Average" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-orange-600", children: summaryStats.min.toLocaleString() }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Minimum" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-purple-600", children: summaryStats.max.toLocaleString() }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Maximum" })] }) })] })), (0, jsx_runtime_1.jsxs)(ui_1.Card, { children: [(0, jsx_runtime_1.jsx)(ui_1.CardHeader, { children: (0, jsx_runtime_1.jsx)(ui_1.CardTitle, { className: "text-lg", children: "Chart Configuration" }) }), (0, jsx_runtime_1.jsx)(ui_1.CardContent, { children: (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("label", { className: "text-sm font-medium mb-2 block", children: ["X-Axis (", selectedChart === 'pie' ? 'Category' : 'Categories', ")"] }), (0, jsx_runtime_1.jsx)(components_1.Dropdown, { options: categoricalColumns.map((col) => ({
385
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6 p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-2xl font-bold tracking-tight", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-gray-600 mt-1", children: ["Visual analysis of ", data.length, " records"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-2", children: [(0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'bar' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('bar'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.BarChart3, { className: "h-4 w-4 mr-2" }), "Bar"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'line' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('line'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.LineChart, { className: "h-4 w-4 mr-2" }), "Line"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'area' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('area'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Activity, { className: "h-4 w-4 mr-2" }), "Area"] }), (0, jsx_runtime_1.jsxs)(ui_2.Button, { variant: selectedChart === 'pie' ? 'primary' : 'outline', size: "sm", onClick: () => setSelectedChart('pie'), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.PieChart, { className: "h-4 w-4 mr-2" }), "Pie"] })] })] }), summaryStats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-blue-600", children: (0, number_format_1.formatNumber)(summaryStats.sum) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Total" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-green-600", children: summaryStats.avg.toFixed(1) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Average" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-orange-600", children: (0, number_format_1.formatNumber)(summaryStats.min) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Minimum" })] }) }), (0, jsx_runtime_1.jsx)(ui_1.Card, { children: (0, jsx_runtime_1.jsxs)(ui_1.CardContent, { className: "p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-purple-600", children: (0, number_format_1.formatNumber)(summaryStats.max) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-gray-600", children: "Maximum" })] }) })] })), (0, jsx_runtime_1.jsxs)(ui_1.Card, { children: [(0, jsx_runtime_1.jsx)(ui_1.CardHeader, { children: (0, jsx_runtime_1.jsx)(ui_1.CardTitle, { className: "text-lg", children: "Chart Configuration" }) }), (0, jsx_runtime_1.jsx)(ui_1.CardContent, { children: (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("label", { className: "text-sm font-medium mb-2 block", children: ["X-Axis (", selectedChart === 'pie' ? 'Category' : 'Categories', ")"] }), (0, jsx_runtime_1.jsx)(components_1.Dropdown, { options: categoricalColumns.map((col) => ({
385
386
  value: col.key,
386
387
  label: col.label,
387
388
  })), value: xAxisColumn, onValueChange: (value) => setXAxisColumn(typeof value === 'string' ? value : value[0] || ''), placeholder: "Select column" })] }), selectedChart !== 'pie' && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-sm font-medium mb-2 block", children: "Y-Axis (Values)" }), (0, jsx_runtime_1.jsx)(components_1.Dropdown, { options: numericColumns.map((col) => ({
@@ -1,8 +1,5 @@
1
1
  'use client';
2
2
  "use strict";
3
- /**
4
- * Grid utility functions and helpers
5
- */
6
3
  Object.defineProperty(exports, "__esModule", { value: true });
7
4
  exports.calculatePaginationInfo = calculatePaginationInfo;
8
5
  exports.generatePageNumbers = generatePageNumbers;
@@ -10,6 +7,10 @@ exports.debounce = debounce;
10
7
  exports.getRowId = getRowId;
11
8
  exports.formatNumber = formatNumber;
12
9
  exports.matchesSearch = matchesSearch;
10
+ const number_format_1 = require("../../../lib/number-format.js");
11
+ /**
12
+ * Grid utility functions and helpers
13
+ */
13
14
  /**
14
15
  * Calculate pagination info
15
16
  */
@@ -83,10 +84,10 @@ function getRowId(row, index, getRowIdFn) {
83
84
  return String(index);
84
85
  }
85
86
  /**
86
- * Format large numbers with commas
87
+ * Format large numbers with grouping, in the library's number locale (Indian by default)
87
88
  */
88
89
  function formatNumber(num) {
89
- return num.toLocaleString();
90
+ return (0, number_format_1.formatNumber)(num);
90
91
  }
91
92
  /**
92
93
  * Check if value matches search term
@@ -6,6 +6,7 @@ exports.CompactFooter = CompactFooter;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const utils_1 = require("../../lib/utils.js");
8
8
  const useTranslation_1 = require("../../hooks/useTranslation.js");
9
+ const number_format_1 = require("../../lib/number-format.js");
9
10
  function Footer({ kpis, actions, iconButtons, leftContent, className, sticky = false, compact = false, padding, variant = 'page', gradient = false }) {
10
11
  if (!kpis && !actions && !leftContent && !iconButtons) {
11
12
  return null;
@@ -45,7 +46,7 @@ function Footer({ kpis, actions, iconButtons, leftContent, className, sticky = f
45
46
  padding === 'normal' ? "py-3 sm:py-4" :
46
47
  compact ? "py-1" :
47
48
  isModal ? "py-1.5 sm:py-2" : "py-3 sm:py-4"), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center gap-2 sm:gap-4 w-full sm:w-auto", children: [leftContent, kpis && kpis.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap items-center gap-3 sm:gap-6 md:gap-8", children: kpis.map((kpi) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm", kpi.onClick && "cursor-pointer hover:text-[rgb(var(--color-primary-hover))] transition-colors"), onClick: kpi.onClick, children: [(0, jsx_runtime_1.jsxs)("span", { className: "text-[rgb(var(--fg-muted))] whitespace-nowrap", children: [kpi.label, ":"] }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium text-[rgb(var(--fg-default))]", children: typeof kpi.value === 'number'
48
- ? kpi.value.toLocaleString()
49
+ ? (0, number_format_1.formatNumber)(kpi.value)
49
50
  : kpi.value }), kpi.trend && ((0, jsx_runtime_1.jsxs)("span", { className: (0, utils_1.cn)("text-xs font-medium", kpi.trend.direction === 'up'
50
51
  ? "text-[rgb(var(--color-success))]"
51
52
  : "text-[rgb(var(--color-error))]"), children: [kpi.trend.direction === 'up' ? '↑' : '↓', Math.abs(kpi.trend.value), "%"] }))] }, kpi.id))) }))] }), iconButtons && iconButtons.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap items-center gap-1.5 sm:gap-2", children: iconButtons.map((button) => {
@@ -110,7 +110,10 @@ function SidePanel({ title, icon: Icon, categories, activeItemId, onItemSelect,
110
110
  return (0, jsx_runtime_1.jsx)(ItemIcon, { className: "w-4 h-4 shrink-0 opacity-50" });
111
111
  })(), (0, jsx_runtime_1.jsx)("span", { className: "truncate flex-1", children: item.label }), item.badge !== undefined && item.badge !== 0 && ((0, jsx_runtime_1.jsx)("span", { className: (0, utils_1.cn)("text-xs px-1.5 py-0.5 rounded-full shrink-0 tabular-nums", activeItemId === item.id
112
112
  ? "bg-[rgb(var(--color-primary))] text-white"
113
- : "bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-muted))]"), children: item.badge }))] }), itemContextMenu && ((0, jsx_runtime_1.jsx)("button", { onClick: (e) => handleMenuToggle(e, item.id), className: "absolute right-1.5 top-1/2 -translate-y-1/2 w-6 h-6 rounded-md text-[rgb(var(--fg-muted))]/50 flex items-center justify-center hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-all opacity-0 group-hover:opacity-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreVertical, { className: "w-3.5 h-3.5" }) }))] }, item.id))) }))] }, category.id))))] })) }), footer && !isCollapsed && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("shrink-0 border-t border-[rgb(var(--bd-default))] transition-opacity duration-200", isAnimating ? "opacity-0" : "opacity-100"), children: footer }))] }), menuOpen !== null && itemContextMenu && ((0, jsx_runtime_1.jsx)("div", { ref: menuRef, className: "fixed bg-[rgb(var(--bg-surface))] border border-[rgb(var(--bd-default))] rounded-lg min-w-[170px] shadow-lg overflow-hidden z-[9999]", style: {
113
+ : "bg-[rgb(var(--bg-subtle))] text-[rgb(var(--fg-muted))]"), children: item.badge }))] }), itemContextMenu && (
114
+ // Named for screen readers, and shown on keyboard focus as well as hover:
115
+ // it was an unlabelled button nobody tabbing could see.
116
+ (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: (e) => handleMenuToggle(e, item.id), "aria-label": `More actions for ${item.label}`, "aria-haspopup": "menu", "aria-expanded": menuOpen === item.id, className: "absolute right-1.5 top-1/2 -translate-y-1/2 w-6 h-6 rounded-md text-[rgb(var(--fg-muted))]/50 flex items-center justify-center hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))] transition-all opacity-0 group-hover:opacity-100 focus-visible:opacity-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreVertical, { className: "w-3.5 h-3.5" }) }))] }, item.id))) }))] }, category.id))))] })) }), footer && !isCollapsed && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("shrink-0 border-t border-[rgb(var(--bd-default))] transition-opacity duration-200", isAnimating ? "opacity-0" : "opacity-100"), children: footer }))] }), menuOpen !== null && itemContextMenu && ((0, jsx_runtime_1.jsx)("div", { ref: menuRef, className: "fixed bg-[rgb(var(--bg-surface))] border border-[rgb(var(--bd-default))] rounded-lg min-w-[170px] shadow-lg overflow-hidden z-[9999]", style: {
114
117
  left: `${menuPosition.left}px`,
115
118
  top: `${menuPosition.top}px`,
116
119
  transform: 'translateY(-50%)'
@@ -52,6 +52,7 @@ const utils_2 = require("../../lib/utils.js");
52
52
  const react_dom_1 = require("react-dom");
53
53
  const SidebarContextMenu_1 = require("./SidebarContextMenu.js");
54
54
  const SidebarPreferencesContext_1 = require("../../contexts/SidebarPreferencesContext.js");
55
+ const SessionAdapterContext_1 = require("../../contexts/SessionAdapterContext.js");
55
56
  // Route mapping imported from shared utility: getModuleRoutePath
56
57
  // Routes that support quick-create via sidebar "+" button.
57
58
  // When clicked, navigates to {route}?create=true — the page opens its create modal.
@@ -162,6 +163,14 @@ function DynamicSidebar({ isCollapsed = false, onMenuItemClick, onToggleSidebar,
162
163
  const [expandedSubModules, setExpandedSubModules] = React.useState([]);
163
164
  const [loading, setLoading] = React.useState(true);
164
165
  const [error, setError] = React.useState(null);
166
+ // The menu API needs the signed-in session (company credentials). Read from the session adapter,
167
+ // not next-auth, so the library does not require next-auth; held in a ref so a fresh session
168
+ // object does not refetch the menu, only the session arriving or leaving does.
169
+ const sessionAdapter = (0, SessionAdapterContext_1.useOptionalSessionAdapter)();
170
+ const sessionRef = React.useRef(sessionAdapter?.data ?? null);
171
+ sessionRef.current = sessionAdapter?.data ?? null;
172
+ const hasSession = Boolean(sessionAdapter?.data);
173
+ const sessionStatus = sessionAdapter?.status ?? 'unauthenticated';
165
174
  const [needsScroll, setNeedsScroll] = React.useState(false);
166
175
  const navRef = React.useRef(null);
167
176
  const [hoveredGroup, setHoveredGroup] = React.useState(null);
@@ -203,6 +212,12 @@ function DynamicSidebar({ isCollapsed = false, onMenuItemClick, onToggleSidebar,
203
212
  if (!companyId || !userId) {
204
213
  return;
205
214
  }
215
+ // No session yet: wait for it (this runs again when it arrives); none at all: no menu.
216
+ if (!hasSession) {
217
+ if (sessionStatus !== 'loading')
218
+ setLoading(false);
219
+ return;
220
+ }
206
221
  let isCancelled = false;
207
222
  const fetchNavigation = async () => {
208
223
  // Check cache first - include session start time to invalidate cache across logins
@@ -228,7 +243,7 @@ function DynamicSidebar({ isCollapsed = false, onMenuItemClick, onToggleSidebar,
228
243
  try {
229
244
  setLoading(true);
230
245
  setError(null);
231
- const navigation = await (0, api_1.getDynamicNavigation)(companyId, userId);
246
+ const navigation = await (0, api_1.getDynamicNavigation)(companyId, userId, sessionRef.current);
232
247
  if (!isCancelled) {
233
248
  setGroupedModules(navigation);
234
249
  // Cache the result
@@ -256,7 +271,7 @@ function DynamicSidebar({ isCollapsed = false, onMenuItemClick, onToggleSidebar,
256
271
  clearTimeout(hoverTimeoutRef.current);
257
272
  }
258
273
  };
259
- }, [companyId, userId]);
274
+ }, [companyId, userId, hasSession, sessionStatus]);
260
275
  // Auto-open parent items based on current path (optimized)
261
276
  React.useEffect(() => {
262
277
  if (groupedModules.length === 0)
@@ -8,14 +8,14 @@ const navigation_1 = require("next/navigation");
8
8
  const lucide_react_1 = require("lucide-react");
9
9
  const utils_1 = require("../../lib/utils.js");
10
10
  const LanguageContext_1 = require("../../contexts/LanguageContext.js");
11
- const react_2 = require("next-auth/react");
11
+ const SessionAdapterContext_1 = require("../../contexts/SessionAdapterContext.js");
12
12
  const MessagingContext_1 = require("../../contexts/MessagingContext.js");
13
13
  const messaging_1 = require("../../lib/api/activity/messaging/messaging.js");
14
14
  const conversation_list_1 = require("./conversation-list.js");
15
15
  const ui_1 = require("../ui/index.js");
16
16
  function MessagingPanelContent({ onClose }) {
17
17
  const { t } = (0, LanguageContext_1.useLanguage)();
18
- const { data: session } = (0, react_2.useSession)();
18
+ const session = (0, SessionAdapterContext_1.useOptionalSessionAdapter)()?.data ?? null;
19
19
  const { state, actions } = (0, MessagingContext_1.useMessaging)();
20
20
  const router = (0, navigation_1.useRouter)();
21
21
  const currentUserId = String(session?.user?.UserID || session?.user?.userID || '');
@@ -7,6 +7,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const lucide_react_1 = require("lucide-react");
8
8
  const utils_1 = require("../../../lib/utils.js");
9
9
  const card_1 = require("./card.js");
10
+ const number_format_1 = require("../../../lib/number-format.js");
10
11
  const iconVariants = {
11
12
  default: "bg-primary text-white",
12
13
  accent: "bg-accent text-white",
@@ -16,7 +17,7 @@ const iconVariants = {
16
17
  function StatsCard({ title, value, icon: Icon, trend, description, className, variant = 'default' }) {
17
18
  const TrendIcon = trend?.direction === 'up' ? lucide_react_1.TrendingUp : lucide_react_1.TrendingDown;
18
19
  const trendColor = trend?.direction === 'up' ? 'text-success' : 'text-error';
19
- return ((0, jsx_runtime_1.jsx)(card_1.Card, { className: (0, utils_1.cn)("p-6 min-h-[140px] w-full", className), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-4", children: [Icon && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("flex-shrink-0 p-3 rounded-lg", iconVariants[variant]), children: (0, jsx_runtime_1.jsx)(Icon, { className: "h-6 w-6" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline flex-wrap gap-2", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-2xl font-semibold text-fg-default truncate", children: typeof value === 'number' ? value.toLocaleString() : value }), trend && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("flex items-center text-sm font-semibold", trendColor), children: [(0, jsx_runtime_1.jsx)(TrendIcon, { className: "h-4 w-4 flex-shrink-0" }), (0, jsx_runtime_1.jsxs)("span", { className: "ml-1", children: [Math.abs(trend.value), "%", trend.label && ` ${trend.label}`] })] }))] }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium text-fg-muted mt-2 line-clamp-2", children: title }), description && ((0, jsx_runtime_1.jsx)("p", { className: "text-sm text-fg-subtle mt-1 line-clamp-1", children: description }))] })] }) }));
20
+ return ((0, jsx_runtime_1.jsx)(card_1.Card, { className: (0, utils_1.cn)("p-6 min-h-[140px] w-full", className), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-4", children: [Icon && ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("flex-shrink-0 p-3 rounded-lg", iconVariants[variant]), children: (0, jsx_runtime_1.jsx)(Icon, { className: "h-6 w-6" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline flex-wrap gap-2", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-2xl font-semibold text-fg-default truncate", children: typeof value === 'number' ? (0, number_format_1.formatNumber)(value) : value }), trend && ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("flex items-center text-sm font-semibold", trendColor), children: [(0, jsx_runtime_1.jsx)(TrendIcon, { className: "h-4 w-4 flex-shrink-0" }), (0, jsx_runtime_1.jsxs)("span", { className: "ml-1", children: [Math.abs(trend.value), "%", trend.label && ` ${trend.label}`] })] }))] }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium text-fg-muted mt-2 line-clamp-2", children: title }), description && ((0, jsx_runtime_1.jsx)("p", { className: "text-sm text-fg-subtle mt-1 line-clamp-1", children: description }))] })] }) }));
20
21
  }
21
22
  function StatsGrid({ children, columns = 4, className }) {
22
23
  const gridCols = {
@@ -80,7 +80,10 @@ function Tabs({ tabs, activeTab, onTabChange, fullWidth = false, className = '',
80
80
  ? 'bg-[rgb(var(--color-primary))] text-white border-[rgb(var(--color-primary))]'
81
81
  : 'bg-[rgb(var(--bg-surface))] text-[rgb(var(--fg-muted))] border-[rgb(var(--bd-default))] hover:border-[rgb(var(--color-primary))] hover:text-[rgb(var(--color-primary))]'), children: q.label }, q.value));
82
82
  }) })) : undefined;
83
- return ((0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: tab.dropdownOptions, value: selected, onValueChange: (sel) => {
83
+ return ((0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: tab.dropdownOptions,
84
+ // Periods are listed in time order (Apr, May, Jun… / Week 1, 2, 3…); sorted by label,
85
+ // the months came out Apr, Aug, Dec, Feb.
86
+ preserveOrder: true, value: selected, onValueChange: (sel) => {
84
87
  const arr = Array.isArray(sel) ? sel.map(String) : [String(sel)];
85
88
  // Ticking a named option clears any quick preset (This/Last) — they're exclusive.
86
89
  const quickVals = (tab.quickOptions || []).map(q => q.value);
@@ -8,7 +8,7 @@ exports.useEmailActions = useEmailActions;
8
8
  exports.useEmailAPI = useEmailAPI;
9
9
  const jsx_runtime_1 = require("react/jsx-runtime");
10
10
  const react_1 = require("react");
11
- const react_2 = require("next-auth/react");
11
+ const SessionAdapterContext_1 = require("./SessionAdapterContext.js");
12
12
  const email_1 = require("../lib/api/activity/email/index.js");
13
13
  const FOLDER_CACHE_MAX_AGE = 5 * 60 * 1000; // 5 minutes
14
14
  // Initial State
@@ -152,11 +152,12 @@ function emailReducer(state, action) {
152
152
  const EmailContext = (0, react_1.createContext)(undefined);
153
153
  // Email Provider Component
154
154
  function EmailProvider({ children }) {
155
- const { data: session } = (0, react_2.useSession)();
155
+ const session = (0, SessionAdapterContext_1.useOptionalSessionAdapter)()?.data ?? null;
156
156
  const [state, dispatch] = (0, react_1.useReducer)(emailReducer, initialState);
157
157
  // Memoize on stable identity — useSession() returns a new object each render, so an
158
158
  // unmemoized api would churn every useCallback([api]) and trigger repeated fetches.
159
159
  const sessionIdentity = `${session?.user?.CompanyID ?? ''}:${session?.user?.UserID ?? ''}`;
160
+ // The adapter carries the next-auth session as AuthSessionProvider received it, so it has the shape the email API reads.
160
161
  const api = (0, react_1.useMemo)(() => (0, email_1.createEmailAPI)(session), [sessionIdentity]); // eslint-disable-line react-hooks/exhaustive-deps
161
162
  // Initialize email system when session is available
162
163
  // NOTE: Initialization is now manual - call actions.fetchEmails() when needed
@@ -6,7 +6,7 @@ exports.useMessaging = useMessaging;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
8
  const signalr_1 = require("@microsoft/signalr");
9
- const react_2 = require("next-auth/react");
9
+ const SessionAdapterContext_1 = require("./SessionAdapterContext.js");
10
10
  const messaging_1 = require("../lib/api/activity/messaging/messaging.js");
11
11
  const messaging_2 = require("../lib/api/activity/messaging/messaging.js");
12
12
  const config_1 = require("../lib/api/core/config.js");
@@ -196,7 +196,7 @@ function messagingReducer(state, action) {
196
196
  const MessagingContext = (0, react_1.createContext)(undefined);
197
197
  // ─── Provider ───────────────────────────────────────────────────────────────
198
198
  function MessagingProvider({ children }) {
199
- const { data: session } = (0, react_2.useSession)();
199
+ const session = (0, SessionAdapterContext_1.useOptionalSessionAdapter)()?.data ?? null;
200
200
  const [state, dispatch] = (0, react_1.useReducer)(messagingReducer, initialState);
201
201
  const stateRef = (0, react_1.useRef)(state);
202
202
  stateRef.current = state;
@@ -42,6 +42,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
42
42
  const React = __importStar(require("react"));
43
43
  const api_1 = require("../lib/api/index.js");
44
44
  const utils_1 = require("../lib/utils.js");
45
+ const SessionAdapterContext_1 = require("./SessionAdapterContext.js");
45
46
  /**
46
47
  * Filter grouped modules to only those with MobileSupported = 1/true.
47
48
  * Returns grouped structure with empty groups removed.
@@ -59,11 +60,25 @@ function NavigationProvider({ children, companyId, userId }) {
59
60
  const [groupedModules, setGroupedModules] = React.useState([]);
60
61
  const [loading, setLoading] = React.useState(true);
61
62
  const [error, setError] = React.useState(null);
63
+ // The menu API needs the signed-in session (company credentials). Read from the session adapter,
64
+ // not next-auth, so the library does not require next-auth; held in a ref so a fresh session
65
+ // object does not refetch the menu, only the session arriving or leaving does.
66
+ const sessionAdapter = (0, SessionAdapterContext_1.useOptionalSessionAdapter)();
67
+ const sessionRef = React.useRef(sessionAdapter?.data ?? null);
68
+ sessionRef.current = sessionAdapter?.data ?? null;
69
+ const hasSession = Boolean(sessionAdapter?.data);
70
+ const sessionStatus = sessionAdapter?.status ?? 'unauthenticated';
62
71
  const fetchNavigation = React.useCallback(async () => {
63
72
  if (!companyId || !userId) {
64
73
  setLoading(false);
65
74
  return;
66
75
  }
76
+ // No session yet: wait for it (this runs again when it arrives); none at all: no menu.
77
+ if (!hasSession) {
78
+ if (sessionStatus !== 'loading')
79
+ setLoading(false);
80
+ return;
81
+ }
67
82
  const cacheKey = `navigation_${companyId}_${userId}`;
68
83
  const cacheTimeKey = `${cacheKey}_time`;
69
84
  const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
@@ -80,7 +95,7 @@ function NavigationProvider({ children, companyId, userId }) {
80
95
  }
81
96
  }
82
97
  setLoading(true);
83
- const navigation = await (0, api_1.getDynamicNavigation)(companyId, userId);
98
+ const navigation = await (0, api_1.getDynamicNavigation)(companyId, userId, sessionRef.current);
84
99
  setGroupedModules(navigation);
85
100
  localStorage.setItem(cacheKey, JSON.stringify(navigation));
86
101
  localStorage.setItem(cacheTimeKey, Date.now().toString());
@@ -92,7 +107,7 @@ function NavigationProvider({ children, companyId, userId }) {
92
107
  finally {
93
108
  setLoading(false);
94
109
  }
95
- }, [companyId, userId]);
110
+ }, [companyId, userId, hasSession, sessionStatus]);
96
111
  React.useEffect(() => {
97
112
  fetchNavigation();
98
113
  }, [fetchNavigation]);
@@ -5,7 +5,7 @@ exports.NotificationProvider = NotificationProvider;
5
5
  exports.useNotifications = useNotifications;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
- const react_2 = require("next-auth/react");
8
+ const SessionAdapterContext_1 = require("./SessionAdapterContext.js");
9
9
  const activity_1 = require("../lib/api/activity/index.js");
10
10
  const types_1 = require("../lib/api/activity/notifications/types.js");
11
11
  const useSignalR_1 = require("../hooks/useSignalR.js");
@@ -15,7 +15,7 @@ const NotificationContext = (0, react_1.createContext)(undefined);
15
15
  * app. Consumers read shared state via `useNotifications()` instead of each mounting their own.
16
16
  */
17
17
  function NotificationProvider({ children }) {
18
- const { data: session } = (0, react_2.useSession)();
18
+ const session = (0, SessionAdapterContext_1.useOptionalSessionAdapter)()?.data ?? null;
19
19
  const [notifications, setNotifications] = (0, react_1.useState)([]);
20
20
  const [notificationsLoading, setNotificationsLoading] = (0, react_1.useState)(false);
21
21
  const [showNotificationDropdown, setShowNotificationDropdown] = (0, react_1.useState)(false);
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.SessionAdapterProvider = SessionAdapterProvider;
5
+ exports.useOptionalSessionAdapter = useOptionalSessionAdapter;
5
6
  exports.useSessionAdapter = useSessionAdapter;
6
7
  const jsx_runtime_1 = require("react/jsx-runtime");
7
8
  const react_1 = require("react");
@@ -14,6 +15,13 @@ function SessionAdapterProvider({ user, status, signOut, children }) {
14
15
  }), [user, status, signOut]);
15
16
  return (0, jsx_runtime_1.jsx)(SessionAdapterContext.Provider, { value: value, children: children });
16
17
  }
18
+ /**
19
+ * The session when a provider is present, null when not: for components that also render in apps
20
+ * without one, such as the dynamic sidebar, which simply loads no menu then.
21
+ */
22
+ function useOptionalSessionAdapter() {
23
+ return (0, react_1.useContext)(SessionAdapterContext);
24
+ }
17
25
  /** Drop-in replacement for next-auth's `useSession()` inside library components. */
18
26
  function useSessionAdapter() {
19
27
  const ctx = (0, react_1.useContext)(SessionAdapterContext);