@pattern-stack/frontend-patterns 0.0.4 → 0.0.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 (283) hide show
  1. package/dist/frontend-patterns.css +1 -1
  2. package/dist/index.es.js +1917 -2
  3. package/dist/index.es.js.map +1 -1
  4. package/dist/index.js +1916 -1
  5. package/dist/index.js.map +1 -1
  6. package/package.json +6 -3
  7. package/src/App.tsx +11 -1
  8. package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
  9. package/src/atoms/composed/SalesPanel/index.ts +1 -0
  10. package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
  11. package/src/atoms/composed/index.ts +1 -0
  12. package/src/atoms/types/entity-config.ts +127 -0
  13. package/src/atoms/types/index.ts +2 -1
  14. package/src/atoms/utils/metric-engine.ts +236 -0
  15. package/src/atoms/utils/utils.ts +2 -1
  16. package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
  17. package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
  18. package/src/molecules/layout/Sidebar.tsx +10 -2
  19. package/src/molecules/layout/index.ts +1 -0
  20. package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
  21. package/src/organisms/entity/EntityListPanel.tsx +339 -0
  22. package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
  23. package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
  24. package/src/organisms/entity/index.ts +4 -0
  25. package/src/organisms/index.ts +4 -1
  26. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +77 -75
  27. package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
  28. package/src/pages/AdminShowcase/index.tsx +2 -1
  29. package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
  30. package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
  31. package/src/pages/EntityShowcase/index.ts +2 -0
  32. package/src/pages/EntityTemplateExample.tsx +229 -0
  33. package/src/pages/TestEntityTemplate.tsx +40 -0
  34. package/src/pages/index.ts +2 -1
  35. package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
  36. package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
  37. package/src/templates/entity/configs/financial-config.ts +141 -0
  38. package/src/templates/entity/configs/index.ts +1 -0
  39. package/src/templates/entity/index.ts +3 -0
  40. package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
  41. package/src/templates/index.ts +3 -0
  42. package/dist/atoms/composed/Accordion/Accordion.d.ts +0 -20
  43. package/dist/atoms/composed/Accordion/Accordion.d.ts.map +0 -1
  44. package/dist/atoms/composed/Accordion/index.d.ts +0 -2
  45. package/dist/atoms/composed/Accordion/index.d.ts.map +0 -1
  46. package/dist/atoms/composed/Alert/Alert.d.ts +0 -25
  47. package/dist/atoms/composed/Alert/Alert.d.ts.map +0 -1
  48. package/dist/atoms/composed/Alert/index.d.ts +0 -2
  49. package/dist/atoms/composed/Alert/index.d.ts.map +0 -1
  50. package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts +0 -17
  51. package/dist/atoms/composed/Breadcrumb/Breadcrumb.d.ts.map +0 -1
  52. package/dist/atoms/composed/Breadcrumb/index.d.ts +0 -2
  53. package/dist/atoms/composed/Breadcrumb/index.d.ts.map +0 -1
  54. package/dist/atoms/composed/Chart/Chart.d.ts +0 -37
  55. package/dist/atoms/composed/Chart/Chart.d.ts.map +0 -1
  56. package/dist/atoms/composed/Chart/index.d.ts +0 -3
  57. package/dist/atoms/composed/Chart/index.d.ts.map +0 -1
  58. package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts +0 -19
  59. package/dist/atoms/composed/ColorSwatch/ColorSwatch.d.ts.map +0 -1
  60. package/dist/atoms/composed/ColorSwatch/index.d.ts +0 -2
  61. package/dist/atoms/composed/ColorSwatch/index.d.ts.map +0 -1
  62. package/dist/atoms/composed/DarkModeToggle.d.ts +0 -4
  63. package/dist/atoms/composed/DarkModeToggle.d.ts.map +0 -1
  64. package/dist/atoms/composed/DataBadge/DataBadge.d.ts +0 -13
  65. package/dist/atoms/composed/DataBadge/DataBadge.d.ts.map +0 -1
  66. package/dist/atoms/composed/DataBadge/index.d.ts +0 -2
  67. package/dist/atoms/composed/DataBadge/index.d.ts.map +0 -1
  68. package/dist/atoms/composed/DataTable/DataTable.d.ts +0 -28
  69. package/dist/atoms/composed/DataTable/DataTable.d.ts.map +0 -1
  70. package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts +0 -10
  71. package/dist/atoms/composed/DataTable/TableCellWithTooltip.d.ts.map +0 -1
  72. package/dist/atoms/composed/DataTable/index.d.ts +0 -3
  73. package/dist/atoms/composed/DataTable/index.d.ts.map +0 -1
  74. package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts +0 -45
  75. package/dist/atoms/composed/DateTimePicker/DateTimePicker.d.ts.map +0 -1
  76. package/dist/atoms/composed/DateTimePicker/index.d.ts +0 -3
  77. package/dist/atoms/composed/DateTimePicker/index.d.ts.map +0 -1
  78. package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts +0 -30
  79. package/dist/atoms/composed/DetailedCard/DetailedCard.d.ts.map +0 -1
  80. package/dist/atoms/composed/DetailedCard/index.d.ts +0 -3
  81. package/dist/atoms/composed/DetailedCard/index.d.ts.map +0 -1
  82. package/dist/atoms/composed/EmptyState/EmptyState.d.ts +0 -18
  83. package/dist/atoms/composed/EmptyState/EmptyState.d.ts.map +0 -1
  84. package/dist/atoms/composed/EmptyState/index.d.ts +0 -2
  85. package/dist/atoms/composed/EmptyState/index.d.ts.map +0 -1
  86. package/dist/atoms/composed/FileUpload/FileUpload.d.ts +0 -46
  87. package/dist/atoms/composed/FileUpload/FileUpload.d.ts.map +0 -1
  88. package/dist/atoms/composed/FileUpload/index.d.ts +0 -3
  89. package/dist/atoms/composed/FileUpload/index.d.ts.map +0 -1
  90. package/dist/atoms/composed/FormField/FormField.d.ts +0 -23
  91. package/dist/atoms/composed/FormField/FormField.d.ts.map +0 -1
  92. package/dist/atoms/composed/FormField/index.d.ts +0 -2
  93. package/dist/atoms/composed/FormField/index.d.ts.map +0 -1
  94. package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts +0 -8
  95. package/dist/atoms/composed/GlobalSearch/GlobalSearch.d.ts.map +0 -1
  96. package/dist/atoms/composed/GlobalSearch/index.d.ts +0 -2
  97. package/dist/atoms/composed/GlobalSearch/index.d.ts.map +0 -1
  98. package/dist/atoms/composed/IconBadge/IconBadge.d.ts +0 -16
  99. package/dist/atoms/composed/IconBadge/IconBadge.d.ts.map +0 -1
  100. package/dist/atoms/composed/IconBadge/index.d.ts +0 -3
  101. package/dist/atoms/composed/IconBadge/index.d.ts.map +0 -1
  102. package/dist/atoms/composed/Modal/Modal.d.ts +0 -18
  103. package/dist/atoms/composed/Modal/Modal.d.ts.map +0 -1
  104. package/dist/atoms/composed/Modal/index.d.ts +0 -3
  105. package/dist/atoms/composed/Modal/index.d.ts.map +0 -1
  106. package/dist/atoms/composed/PaletteSwitcher.d.ts +0 -7
  107. package/dist/atoms/composed/PaletteSwitcher.d.ts.map +0 -1
  108. package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts +0 -25
  109. package/dist/atoms/composed/ProgressBar/ProgressBar.d.ts.map +0 -1
  110. package/dist/atoms/composed/ProgressBar/index.d.ts +0 -2
  111. package/dist/atoms/composed/ProgressBar/index.d.ts.map +0 -1
  112. package/dist/atoms/composed/StatCard/StatCard.d.ts +0 -21
  113. package/dist/atoms/composed/StatCard/StatCard.d.ts.map +0 -1
  114. package/dist/atoms/composed/StatCard/index.d.ts +0 -2
  115. package/dist/atoms/composed/StatCard/index.d.ts.map +0 -1
  116. package/dist/atoms/composed/StyleGuide.d.ts +0 -3
  117. package/dist/atoms/composed/StyleGuide.d.ts.map +0 -1
  118. package/dist/atoms/composed/Toast/Toast.d.ts +0 -40
  119. package/dist/atoms/composed/Toast/Toast.d.ts.map +0 -1
  120. package/dist/atoms/composed/Toast/index.d.ts +0 -2
  121. package/dist/atoms/composed/Toast/index.d.ts.map +0 -1
  122. package/dist/atoms/composed/Tooltip/Tooltip.d.ts +0 -16
  123. package/dist/atoms/composed/Tooltip/Tooltip.d.ts.map +0 -1
  124. package/dist/atoms/composed/Tooltip/index.d.ts +0 -2
  125. package/dist/atoms/composed/Tooltip/index.d.ts.map +0 -1
  126. package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts +0 -8
  127. package/dist/atoms/composed/UserAvatar/UserAvatar.d.ts.map +0 -1
  128. package/dist/atoms/composed/UserAvatar/index.d.ts +0 -2
  129. package/dist/atoms/composed/UserAvatar/index.d.ts.map +0 -1
  130. package/dist/atoms/composed/UserMenu/UserMenu.d.ts +0 -8
  131. package/dist/atoms/composed/UserMenu/UserMenu.d.ts.map +0 -1
  132. package/dist/atoms/composed/UserMenu/index.d.ts +0 -2
  133. package/dist/atoms/composed/UserMenu/index.d.ts.map +0 -1
  134. package/dist/atoms/composed/index.d.ts +0 -25
  135. package/dist/atoms/composed/index.d.ts.map +0 -1
  136. package/dist/atoms/hooks/useApi.d.ts +0 -25
  137. package/dist/atoms/hooks/useApi.d.ts.map +0 -1
  138. package/dist/atoms/hooks/useHealth.d.ts +0 -19
  139. package/dist/atoms/hooks/useHealth.d.ts.map +0 -1
  140. package/dist/atoms/index.d.ts +0 -9
  141. package/dist/atoms/index.d.ts.map +0 -1
  142. package/dist/atoms/services/api/client.d.ts +0 -20
  143. package/dist/atoms/services/api/client.d.ts.map +0 -1
  144. package/dist/atoms/services/auth-service.d.ts +0 -24
  145. package/dist/atoms/services/auth-service.d.ts.map +0 -1
  146. package/dist/atoms/services/health.d.ts +0 -7
  147. package/dist/atoms/services/health.d.ts.map +0 -1
  148. package/dist/atoms/services/index.d.ts +0 -4
  149. package/dist/atoms/services/index.d.ts.map +0 -1
  150. package/dist/atoms/shared/config/constants.d.ts +0 -15
  151. package/dist/atoms/shared/config/constants.d.ts.map +0 -1
  152. package/dist/atoms/shared/config/dashboard-sizes.d.ts +0 -83
  153. package/dist/atoms/shared/config/dashboard-sizes.d.ts.map +0 -1
  154. package/dist/atoms/shared/config/environment.d.ts +0 -10
  155. package/dist/atoms/shared/config/environment.d.ts.map +0 -1
  156. package/dist/atoms/shared/index.d.ts +0 -4
  157. package/dist/atoms/shared/index.d.ts.map +0 -1
  158. package/dist/atoms/types/auth.d.ts +0 -56
  159. package/dist/atoms/types/auth.d.ts.map +0 -1
  160. package/dist/atoms/types/generated.d.ts +0 -1469
  161. package/dist/atoms/types/generated.d.ts.map +0 -1
  162. package/dist/atoms/types/index.d.ts +0 -4
  163. package/dist/atoms/types/index.d.ts.map +0 -1
  164. package/dist/atoms/types/loading.d.ts +0 -26
  165. package/dist/atoms/types/loading.d.ts.map +0 -1
  166. package/dist/atoms/ui/Badge.d.ts +0 -10
  167. package/dist/atoms/ui/Badge.d.ts.map +0 -1
  168. package/dist/atoms/ui/ErrorBoundary.d.ts +0 -18
  169. package/dist/atoms/ui/ErrorBoundary.d.ts.map +0 -1
  170. package/dist/atoms/ui/Select.d.ts +0 -28
  171. package/dist/atoms/ui/Select.d.ts.map +0 -1
  172. package/dist/atoms/ui/Switch.d.ts +0 -9
  173. package/dist/atoms/ui/Switch.d.ts.map +0 -1
  174. package/dist/atoms/ui/Tabs.d.ts +0 -30
  175. package/dist/atoms/ui/Tabs.d.ts.map +0 -1
  176. package/dist/atoms/ui/avatar.d.ts +0 -7
  177. package/dist/atoms/ui/avatar.d.ts.map +0 -1
  178. package/dist/atoms/ui/button.d.ts +0 -14
  179. package/dist/atoms/ui/button.d.ts.map +0 -1
  180. package/dist/atoms/ui/card.d.ts +0 -12
  181. package/dist/atoms/ui/card.d.ts.map +0 -1
  182. package/dist/atoms/ui/dropdown-menu.d.ts +0 -28
  183. package/dist/atoms/ui/dropdown-menu.d.ts.map +0 -1
  184. package/dist/atoms/ui/index.d.ts +0 -15
  185. package/dist/atoms/ui/index.d.ts.map +0 -1
  186. package/dist/atoms/ui/input.d.ts +0 -5
  187. package/dist/atoms/ui/input.d.ts.map +0 -1
  188. package/dist/atoms/ui/label.d.ts +0 -6
  189. package/dist/atoms/ui/label.d.ts.map +0 -1
  190. package/dist/atoms/ui/skeleton.d.ts +0 -3
  191. package/dist/atoms/ui/skeleton.d.ts.map +0 -1
  192. package/dist/atoms/ui/spinner.d.ts +0 -14
  193. package/dist/atoms/ui/spinner.d.ts.map +0 -1
  194. package/dist/atoms/ui/table.d.ts +0 -11
  195. package/dist/atoms/ui/table.d.ts.map +0 -1
  196. package/dist/atoms/utils/animations.d.ts +0 -65
  197. package/dist/atoms/utils/animations.d.ts.map +0 -1
  198. package/dist/atoms/utils/tooltip-helpers.d.ts +0 -71
  199. package/dist/atoms/utils/tooltip-helpers.d.ts.map +0 -1
  200. package/dist/atoms/utils/utils.d.ts +0 -4
  201. package/dist/atoms/utils/utils.d.ts.map +0 -1
  202. package/dist/features/auth/components/LoginForm.d.ts +0 -2
  203. package/dist/features/auth/components/LoginForm.d.ts.map +0 -1
  204. package/dist/features/auth/components/LogoutButton.d.ts +0 -2
  205. package/dist/features/auth/components/LogoutButton.d.ts.map +0 -1
  206. package/dist/features/auth/components/ProtectedRoute.d.ts +0 -10
  207. package/dist/features/auth/components/ProtectedRoute.d.ts.map +0 -1
  208. package/dist/features/auth/components/index.d.ts +0 -4
  209. package/dist/features/auth/components/index.d.ts.map +0 -1
  210. package/dist/features/auth/hooks/index.d.ts +0 -3
  211. package/dist/features/auth/hooks/index.d.ts.map +0 -1
  212. package/dist/features/auth/hooks/useAuth.d.ts +0 -10
  213. package/dist/features/auth/hooks/useAuth.d.ts.map +0 -1
  214. package/dist/features/auth/hooks/usePermissions.d.ts +0 -13
  215. package/dist/features/auth/hooks/usePermissions.d.ts.map +0 -1
  216. package/dist/features/auth/index.d.ts +0 -3
  217. package/dist/features/auth/index.d.ts.map +0 -1
  218. package/dist/features/index.d.ts +0 -2
  219. package/dist/features/index.d.ts.map +0 -1
  220. package/dist/index.d.ts +0 -10
  221. package/dist/index.d.ts.map +0 -1
  222. package/dist/molecules/forms/FormGroup.d.ts +0 -17
  223. package/dist/molecules/forms/FormGroup.d.ts.map +0 -1
  224. package/dist/molecules/forms/SearchInput.d.ts +0 -36
  225. package/dist/molecules/forms/SearchInput.d.ts.map +0 -1
  226. package/dist/molecules/forms/index.d.ts +0 -3
  227. package/dist/molecules/forms/index.d.ts.map +0 -1
  228. package/dist/molecules/index.d.ts +0 -4
  229. package/dist/molecules/index.d.ts.map +0 -1
  230. package/dist/molecules/layout/AppHeader/AppHeader.d.ts +0 -7
  231. package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +0 -1
  232. package/dist/molecules/layout/AppHeader/index.d.ts +0 -2
  233. package/dist/molecules/layout/AppHeader/index.d.ts.map +0 -1
  234. package/dist/molecules/layout/AppLayout.d.ts +0 -2
  235. package/dist/molecules/layout/AppLayout.d.ts.map +0 -1
  236. package/dist/molecules/layout/PageTemplate.d.ts +0 -19
  237. package/dist/molecules/layout/PageTemplate.d.ts.map +0 -1
  238. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts +0 -24
  239. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts.map +0 -1
  240. package/dist/molecules/layout/SectionHeader/index.d.ts +0 -2
  241. package/dist/molecules/layout/SectionHeader/index.d.ts.map +0 -1
  242. package/dist/molecules/layout/ShowcaseSection.d.ts +0 -22
  243. package/dist/molecules/layout/ShowcaseSection.d.ts.map +0 -1
  244. package/dist/molecules/layout/Sidebar.d.ts +0 -6
  245. package/dist/molecules/layout/Sidebar.d.ts.map +0 -1
  246. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +0 -13
  247. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +0 -1
  248. package/dist/molecules/layout/SidebarButton/index.d.ts +0 -2
  249. package/dist/molecules/layout/SidebarButton/index.d.ts.map +0 -1
  250. package/dist/molecules/layout/SidebarContext.d.ts +0 -12
  251. package/dist/molecules/layout/SidebarContext.d.ts.map +0 -1
  252. package/dist/molecules/layout/index.d.ts +0 -8
  253. package/dist/molecules/layout/index.d.ts.map +0 -1
  254. package/dist/molecules/navigation/NavMenu.d.ts +0 -20
  255. package/dist/molecules/navigation/NavMenu.d.ts.map +0 -1
  256. package/dist/molecules/navigation/Pagination.d.ts +0 -14
  257. package/dist/molecules/navigation/Pagination.d.ts.map +0 -1
  258. package/dist/molecules/navigation/index.d.ts +0 -3
  259. package/dist/molecules/navigation/index.d.ts.map +0 -1
  260. package/dist/organisms/index.d.ts +0 -2
  261. package/dist/organisms/index.d.ts.map +0 -1
  262. package/dist/organisms/showcase/ComponentShowcasePage.d.ts +0 -3
  263. package/dist/organisms/showcase/ComponentShowcasePage.d.ts.map +0 -1
  264. package/dist/templates/AuthTemplate.d.ts +0 -68
  265. package/dist/templates/AuthTemplate.d.ts.map +0 -1
  266. package/dist/templates/ComponentShowcaseTemplate.d.ts +0 -53
  267. package/dist/templates/ComponentShowcaseTemplate.d.ts.map +0 -1
  268. package/dist/templates/DashboardTemplate.d.ts +0 -62
  269. package/dist/templates/DashboardTemplate.d.ts.map +0 -1
  270. package/dist/templates/DataTemplate.d.ts +0 -78
  271. package/dist/templates/DataTemplate.d.ts.map +0 -1
  272. package/dist/templates/admin/AdminCRUDTemplate.d.ts +0 -105
  273. package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +0 -1
  274. package/dist/templates/admin/AdminDashboardTemplate.d.ts +0 -89
  275. package/dist/templates/admin/AdminDashboardTemplate.d.ts.map +0 -1
  276. package/dist/templates/admin/AdminDetailTemplate.d.ts +0 -132
  277. package/dist/templates/admin/AdminDetailTemplate.d.ts.map +0 -1
  278. package/dist/templates/admin/index.d.ts +0 -4
  279. package/dist/templates/admin/index.d.ts.map +0 -1
  280. package/dist/templates/factory.d.ts +0 -28
  281. package/dist/templates/factory.d.ts.map +0 -1
  282. package/dist/templates/index.d.ts +0 -7
  283. package/dist/templates/index.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -265,6 +265,175 @@ const tooltipContent = {
265
265
  profile: "Profile",
266
266
  account: "Account settings"
267
267
  };
268
+ class MetricCalculationEngine {
269
+ static calculateMetric(config, data, previousData) {
270
+ const currentValue = this.aggregateValue(config, data);
271
+ const previousValue = previousData ? this.aggregateValue(config, previousData) : void 0;
272
+ const trend = this.calculateTrend(currentValue, previousValue);
273
+ const formattedValue = this.formatValue(currentValue, config.format, config.type);
274
+ const target = typeof config.target === "function" ? config.target(data) : config.target;
275
+ return {
276
+ current: currentValue,
277
+ previous: previousValue,
278
+ trend,
279
+ target,
280
+ formattedValue
281
+ };
282
+ }
283
+ static aggregateValue(config, data) {
284
+ if (!data.length) return 0;
285
+ const values = data.map((item) => {
286
+ const value = this.extractValue(item, config.key);
287
+ return typeof value === "number" ? value : 0;
288
+ }).filter((value) => !isNaN(value));
289
+ if (!values.length) return 0;
290
+ switch (config.aggregation || "sum") {
291
+ case "sum":
292
+ return values.reduce((sum, value) => sum + value, 0);
293
+ case "avg":
294
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
295
+ case "count":
296
+ return values.length;
297
+ case "min":
298
+ return Math.min(...values);
299
+ case "max":
300
+ return Math.max(...values);
301
+ default:
302
+ return values.reduce((sum, value) => sum + value, 0);
303
+ }
304
+ }
305
+ static extractValue(item, key) {
306
+ return key.split(".").reduce((obj, k) => obj == null ? void 0 : obj[k], item);
307
+ }
308
+ static calculateTrend(current, previous) {
309
+ if (previous === void 0 || previous === 0) return "neutral";
310
+ const change = (current - previous) / Math.abs(previous) * 100;
311
+ if (change > 1) return "up";
312
+ if (change < -1) return "down";
313
+ return "neutral";
314
+ }
315
+ static formatValue(value, format, type) {
316
+ let formatted = value;
317
+ if ((format == null ? void 0 : format.decimals) !== void 0) {
318
+ formatted = Number(value.toFixed(format.decimals));
319
+ }
320
+ let result = formatted.toString();
321
+ if ((format == null ? void 0 : format.thousands) !== false && Math.abs(formatted) >= 1e3) {
322
+ result = formatted.toLocaleString();
323
+ }
324
+ switch (type) {
325
+ case "currency":
326
+ result = new Intl.NumberFormat("en-US", {
327
+ style: "currency",
328
+ currency: "USD",
329
+ minimumFractionDigits: (format == null ? void 0 : format.decimals) ?? 2,
330
+ maximumFractionDigits: (format == null ? void 0 : format.decimals) ?? 2
331
+ }).format(formatted);
332
+ break;
333
+ case "percentage":
334
+ result = `${formatted.toFixed((format == null ? void 0 : format.decimals) ?? 1)}%`;
335
+ break;
336
+ case "duration":
337
+ result = this.formatDuration(formatted);
338
+ break;
339
+ case "ratio":
340
+ result = `${formatted.toFixed((format == null ? void 0 : format.decimals) ?? 2)}:1`;
341
+ break;
342
+ default:
343
+ if (format == null ? void 0 : format.prefix) result = format.prefix + result;
344
+ if (format == null ? void 0 : format.suffix) result = result + format.suffix;
345
+ }
346
+ return result;
347
+ }
348
+ static formatDuration(minutes) {
349
+ const hours = Math.floor(minutes / 60);
350
+ const mins = Math.floor(minutes % 60);
351
+ if (hours > 0) {
352
+ return `${hours}h ${mins}m`;
353
+ }
354
+ return `${mins}m`;
355
+ }
356
+ static calculateTrendData(config, data, dateField = "date", periods = 12) {
357
+ const groupedData = this.groupByPeriod(data, dateField);
358
+ const sortedDates = Object.keys(groupedData).sort();
359
+ return sortedDates.slice(-periods).map((date) => ({
360
+ date,
361
+ value: this.aggregateValue(config, groupedData[date]),
362
+ label: this.formatDateLabel(date)
363
+ }));
364
+ }
365
+ static groupByPeriod(data, dateField) {
366
+ return data.reduce((groups, item) => {
367
+ const date = this.extractValue(item, dateField);
368
+ if (!date) return groups;
369
+ const period = new Date(date).toISOString().split("T")[0];
370
+ if (!groups[period]) groups[period] = [];
371
+ groups[period].push(item);
372
+ return groups;
373
+ }, {});
374
+ }
375
+ static formatDateLabel(dateString) {
376
+ const date = new Date(dateString);
377
+ return date.toLocaleDateString("en-US", {
378
+ month: "short",
379
+ day: "numeric"
380
+ });
381
+ }
382
+ static calculateCategoryBreakdown(data, categoryField, valueField, maxCategories = 8) {
383
+ const groups = data.reduce((acc, item) => {
384
+ const category = String(this.extractValue(item, categoryField) || "Unknown");
385
+ const value = this.extractValue(item, valueField) || 0;
386
+ if (!acc[category]) acc[category] = 0;
387
+ acc[category] += typeof value === "number" ? value : 0;
388
+ return acc;
389
+ }, {});
390
+ const total = Object.values(groups).reduce((sum, value) => sum + value, 0);
391
+ let categories = Object.entries(groups).map(([category, value]) => ({
392
+ category,
393
+ value,
394
+ percentage: total > 0 ? value / total * 100 : 0
395
+ })).sort((a, b) => b.value - a.value);
396
+ if (categories.length > maxCategories) {
397
+ const topCategories = categories.slice(0, maxCategories - 1);
398
+ const otherValue = categories.slice(maxCategories - 1).reduce((sum, cat) => sum + cat.value, 0);
399
+ topCategories.push({
400
+ category: "Other",
401
+ value: otherValue,
402
+ percentage: total > 0 ? otherValue / total * 100 : 0
403
+ });
404
+ categories = topCategories;
405
+ }
406
+ return categories;
407
+ }
408
+ static detectInsights(metrics, thresholds = {}) {
409
+ const insights = [];
410
+ for (const [key, metric] of Object.entries(metrics)) {
411
+ const threshold = thresholds[key];
412
+ if (metric.target && metric.current < metric.target * 0.8) {
413
+ insights.push({
414
+ type: "negative",
415
+ message: `${key} is significantly below target`,
416
+ value: metric.current
417
+ });
418
+ }
419
+ if (metric.trend === "up" && metric.previous && metric.current > metric.previous * 1.2) {
420
+ insights.push({
421
+ type: "positive",
422
+ message: `${key} showing strong growth`,
423
+ value: metric.current
424
+ });
425
+ }
426
+ if (threshold && metric.current >= threshold.critical) {
427
+ insights.push({
428
+ type: "negative",
429
+ message: `${key} has reached critical threshold`,
430
+ value: metric.current
431
+ });
432
+ }
433
+ }
434
+ return insights.slice(0, 5);
435
+ }
436
+ }
268
437
  function cn(...inputs) {
269
438
  return tailwindMerge.twMerge(clsx.clsx(inputs));
270
439
  }
@@ -1286,6 +1455,83 @@ const DataBadge = ({
1286
1455
  }
1287
1456
  return badge;
1288
1457
  };
1458
+ const getStageStatus = (stage) => {
1459
+ switch (stage) {
1460
+ case "Closed Won":
1461
+ return "success";
1462
+ case "Negotiation":
1463
+ return "warning";
1464
+ case "Proposal Sent":
1465
+ return "info";
1466
+ case "Qualified":
1467
+ return "info";
1468
+ case "Discovery":
1469
+ return "neutral";
1470
+ default:
1471
+ return "neutral";
1472
+ }
1473
+ };
1474
+ const SalesPanel = ({
1475
+ sales,
1476
+ onSaleClick,
1477
+ onClose
1478
+ }) => {
1479
+ const topDeals = sales.slice(0, 5);
1480
+ const totalValue = sales.reduce((sum, sale) => sum + sale.amount, 0);
1481
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed right-0 top-16 h-[calc(100vh-4rem)] w-72 bg-background border-l border-border shadow-lg flex flex-col z-30", children: [
1482
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1483
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "font-medium flex items-center gap-2", children: [
1484
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Target, { className: "w-4 h-4" }),
1485
+ "Pipeline"
1486
+ ] }),
1487
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, children: "×" })
1488
+ ] }) }),
1489
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1490
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1491
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Total Value" }),
1492
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-green-600", children: [
1493
+ "$",
1494
+ totalValue.toLocaleString()
1495
+ ] })
1496
+ ] }),
1497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1498
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Active Deals" }),
1499
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: sales.length })
1500
+ ] })
1501
+ ] }) }),
1502
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto p-3", children: [
1503
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-medium mb-3", children: "Recent Opportunities" }),
1504
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: topDeals.map((sale) => /* @__PURE__ */ jsxRuntime.jsxs(
1505
+ "div",
1506
+ {
1507
+ className: "p-2 border border-border rounded-md hover:bg-muted/50 cursor-pointer transition-colors",
1508
+ onClick: () => onSaleClick == null ? void 0 : onSaleClick(sale),
1509
+ children: [
1510
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start mb-1", children: [
1511
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
1512
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: sale.customer }),
1513
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: sale.product })
1514
+ ] }),
1515
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right ml-2", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-semibold text-green-600", children: [
1516
+ "$",
1517
+ sale.amount.toLocaleString()
1518
+ ] }) })
1519
+ ] }),
1520
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
1521
+ /* @__PURE__ */ jsxRuntime.jsx(DataBadge, { variant: "status", status: getStageStatus(sale.stage), children: sale.stage }),
1522
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: sale.salesperson })
1523
+ ] })
1524
+ ]
1525
+ },
1526
+ sale.id
1527
+ )) })
1528
+ ] }),
1529
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "outline", size: "sm", className: "w-full", children: [
1530
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "w-4 h-4 mr-2" }),
1531
+ "View All Deals"
1532
+ ] }) })
1533
+ ] });
1534
+ };
1289
1535
  const StatCard = ({
1290
1536
  title,
1291
1537
  value,
@@ -5619,7 +5865,11 @@ const Sidebar = ({ className }) => {
5619
5865
  const items = [
5620
5866
  { value: "showcase", label: "Showcase", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: "w-5 h-5" }), path: "/showcase", category: 5 },
5621
5867
  { value: "admin-dashboard", label: "Admin Dashboard", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "w-5 h-5" }), path: "/admin/dashboard", category: 2 },
5622
- { value: "admin-users", label: "User Management", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "w-5 h-5" }), path: "/admin/users", category: 3 }
5868
+ { value: "admin-users", label: "User Management", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "w-5 h-5" }), path: "/admin/users", category: 3 },
5869
+ { value: "admin-sales", label: "Sales Dashboard", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "w-5 h-5" }), path: "/admin/sales", category: 4 },
5870
+ { value: "entity-performance", label: "Performance Dashboard", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BarChart3, { className: "w-5 h-5" }), path: "/entity/performance", category: 6 },
5871
+ { value: "entity-management", label: "Entity Management", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { className: "w-5 h-5" }), path: "/entity/management", category: 7 },
5872
+ { value: "entity-template", label: "Template Example", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Layout, { className: "w-5 h-5" }), path: "/entity/template-example", category: 1 }
5623
5873
  ];
5624
5874
  const handleNavigation = (path) => {
5625
5875
  if (path.includes("?")) {
@@ -5747,6 +5997,28 @@ const AppLayout = () => {
5747
5997
  )
5748
5998
  ] });
5749
5999
  };
6000
+ const DashboardWithSidePanel = ({
6001
+ children,
6002
+ sidePanel,
6003
+ showSidePanel = false,
6004
+ sidePanelWidth = 72,
6005
+ className
6006
+ }) => {
6007
+ const marginClass = `pr-${sidePanelWidth}`;
6008
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative h-full", className), children: [
6009
+ /* @__PURE__ */ jsxRuntime.jsx(
6010
+ "div",
6011
+ {
6012
+ className: cn(
6013
+ "transition-all duration-300",
6014
+ showSidePanel ? marginClass : ""
6015
+ ),
6016
+ children
6017
+ }
6018
+ ),
6019
+ showSidePanel && sidePanel
6020
+ ] });
6021
+ };
5750
6022
  const SectionHeader = ({
5751
6023
  title,
5752
6024
  description,
@@ -7759,6 +8031,1636 @@ const AdminDetailTemplate = ({
7759
8031
  ] }) }) })
7760
8032
  ] });
7761
8033
  };
8034
+ const MetricsOverviewPanel = ({
8035
+ metrics,
8036
+ data,
8037
+ previousData,
8038
+ isLoading = false,
8039
+ onMetricClick,
8040
+ className,
8041
+ layout = "grid",
8042
+ columns = 4,
8043
+ category,
8044
+ renderCustomMetric,
8045
+ renderHeader,
8046
+ renderFooter,
8047
+ headerSlot,
8048
+ footerSlot
8049
+ }) => {
8050
+ const calculatedMetrics = React.useMemo(() => {
8051
+ if (isLoading || !(data == null ? void 0 : data.length) || !(metrics == null ? void 0 : metrics.length)) return {};
8052
+ return metrics.reduce((acc, metric) => {
8053
+ acc[metric.key] = MetricCalculationEngine.calculateMetric(
8054
+ metric,
8055
+ data,
8056
+ previousData
8057
+ );
8058
+ return acc;
8059
+ }, {});
8060
+ }, [metrics, data, previousData, isLoading]);
8061
+ const getLayoutClasses = () => {
8062
+ switch (layout) {
8063
+ case "horizontal":
8064
+ return "flex flex-wrap gap-4";
8065
+ case "vertical":
8066
+ return "flex flex-col gap-4";
8067
+ case "grid":
8068
+ default:
8069
+ return cn(
8070
+ "grid gap-4",
8071
+ {
8072
+ "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4": columns === 4,
8073
+ "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3": columns === 3,
8074
+ "grid-cols-1 sm:grid-cols-2": columns === 2
8075
+ }
8076
+ );
8077
+ }
8078
+ };
8079
+ const renderMetricCard = (metric, index) => {
8080
+ if (renderCustomMetric) {
8081
+ const customContent = renderCustomMetric(metric, calculatedMetrics[metric.key], index);
8082
+ if (customContent) return customContent;
8083
+ }
8084
+ const metricValue = calculatedMetrics[metric.key];
8085
+ if (isLoading || !metricValue) {
8086
+ return /* @__PURE__ */ jsxRuntime.jsx(
8087
+ StatCard,
8088
+ {
8089
+ title: metric.label,
8090
+ value: "",
8091
+ isLoading: true,
8092
+ category,
8093
+ icon: metric.icon ? /* @__PURE__ */ jsxRuntime.jsx(metric.icon, {}) : void 0
8094
+ },
8095
+ metric.key
8096
+ );
8097
+ }
8098
+ const trend = metricValue.trend !== "neutral" && metricValue.previous ? {
8099
+ value: Number(((metricValue.current - metricValue.previous) / Math.abs(metricValue.previous) * 100).toFixed(1)),
8100
+ label: "vs last period"
8101
+ } : void 0;
8102
+ const formatTargetValue = (value) => {
8103
+ switch (metric.type) {
8104
+ case "currency":
8105
+ return new Intl.NumberFormat("en-US", {
8106
+ style: "currency",
8107
+ currency: "USD"
8108
+ }).format(value);
8109
+ case "percentage":
8110
+ return `${value}%`;
8111
+ default:
8112
+ return value.toString();
8113
+ }
8114
+ };
8115
+ const subtitle = metricValue.target ? `Target: ${formatTargetValue(metricValue.target)}` : void 0;
8116
+ return /* @__PURE__ */ jsxRuntime.jsx(
8117
+ StatCard,
8118
+ {
8119
+ title: metric.label,
8120
+ value: metricValue.formattedValue,
8121
+ subtitle,
8122
+ trend,
8123
+ category,
8124
+ icon: metric.icon ? /* @__PURE__ */ jsxRuntime.jsx(metric.icon, {}) : void 0,
8125
+ onClick: onMetricClick ? () => onMetricClick(metric, metricValue) : void 0,
8126
+ valueTooltip: `Current: ${metricValue.formattedValue}${metricValue.previous ? ` | Previous: ${formatTargetValue(metricValue.previous)}` : ""}`,
8127
+ iconTooltip: `View ${metric.label} details`
8128
+ },
8129
+ metric.key
8130
+ );
8131
+ };
8132
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-4", className), "data-component-name": "MetricsOverviewPanel", children: [
8133
+ headerSlot,
8134
+ renderHeader && renderHeader(),
8135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: getLayoutClasses(), children: metrics.map((metric, index) => renderMetricCard(metric, index)) }),
8136
+ renderFooter && renderFooter(),
8137
+ footerSlot
8138
+ ] });
8139
+ };
8140
+ const MetricsOverviewWithInsightsPanel = ({
8141
+ showInsights = true,
8142
+ insightThresholds,
8143
+ renderInsight,
8144
+ ...props
8145
+ }) => {
8146
+ const safeMetrics = props.metrics || [];
8147
+ const safeData = props.data || [];
8148
+ const calculatedMetrics = React.useMemo(() => {
8149
+ if (props.isLoading || !safeData.length || !safeMetrics.length) return {};
8150
+ return safeMetrics.reduce((acc, metric) => {
8151
+ acc[metric.key] = MetricCalculationEngine.calculateMetric(
8152
+ metric,
8153
+ safeData,
8154
+ props.previousData
8155
+ );
8156
+ return acc;
8157
+ }, {});
8158
+ }, [safeMetrics, safeData, props.previousData, props.isLoading]);
8159
+ const insights = React.useMemo(() => {
8160
+ if (!showInsights || props.isLoading || Object.keys(calculatedMetrics).length === 0) {
8161
+ return [];
8162
+ }
8163
+ return MetricCalculationEngine.detectInsights(calculatedMetrics, insightThresholds);
8164
+ }, [calculatedMetrics, showInsights, insightThresholds, props.isLoading]);
8165
+ const renderInsightsSection = () => {
8166
+ if (!showInsights || insights.length === 0) return null;
8167
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
8168
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Key Insights" }),
8169
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: insights.map((insight, index) => {
8170
+ if (renderInsight) {
8171
+ const customInsight = renderInsight(insight, index);
8172
+ if (customInsight) return customInsight;
8173
+ }
8174
+ const colorClass = {
8175
+ positive: "text-status-success",
8176
+ negative: "text-status-error",
8177
+ neutral: "text-muted-foreground"
8178
+ }[insight.type];
8179
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8180
+ "div",
8181
+ {
8182
+ className: cn("text-sm", colorClass),
8183
+ children: [
8184
+ "• ",
8185
+ insight.message
8186
+ ]
8187
+ },
8188
+ index
8189
+ );
8190
+ }) })
8191
+ ] });
8192
+ };
8193
+ return /* @__PURE__ */ jsxRuntime.jsx(
8194
+ MetricsOverviewPanel,
8195
+ {
8196
+ ...props,
8197
+ footerSlot: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8198
+ renderInsightsSection(),
8199
+ props.footerSlot
8200
+ ] })
8201
+ }
8202
+ );
8203
+ };
8204
+ const EntityListPanel = ({
8205
+ config,
8206
+ data,
8207
+ isLoading = false,
8208
+ onRowClick,
8209
+ onAction,
8210
+ className,
8211
+ columns: customColumns,
8212
+ showSearch = true,
8213
+ showPagination = true,
8214
+ pageSize = 10,
8215
+ searchPlaceholder,
8216
+ enableSelection = false,
8217
+ enableBulkActions = false,
8218
+ enableExport = true,
8219
+ enableFiltering = false,
8220
+ enableRefresh = true,
8221
+ renderToolbar,
8222
+ renderBulkActions,
8223
+ renderCustomColumn,
8224
+ renderEmptyState,
8225
+ headerSlot,
8226
+ footerSlot,
8227
+ onExport,
8228
+ onRefresh
8229
+ }) => {
8230
+ const [selectedItems, setSelectedItems] = React.useState([]);
8231
+ const [showFilters, setShowFilters] = React.useState(false);
8232
+ const tableColumns = React.useMemo(() => {
8233
+ if (customColumns) return customColumns;
8234
+ const generatedColumns = [];
8235
+ if (enableSelection) {
8236
+ generatedColumns.push({
8237
+ key: "__selection",
8238
+ header: /* @__PURE__ */ jsxRuntime.jsx(
8239
+ "input",
8240
+ {
8241
+ type: "checkbox",
8242
+ checked: selectedItems.length === data.length && data.length > 0,
8243
+ onChange: (e) => {
8244
+ if (e.target.checked) {
8245
+ setSelectedItems([...data]);
8246
+ } else {
8247
+ setSelectedItems([]);
8248
+ }
8249
+ }
8250
+ }
8251
+ ),
8252
+ cell: (item) => /* @__PURE__ */ jsxRuntime.jsx(
8253
+ "input",
8254
+ {
8255
+ type: "checkbox",
8256
+ checked: selectedItems.some((selected) => selected.id === item.id),
8257
+ onChange: (e) => {
8258
+ if (e.target.checked) {
8259
+ setSelectedItems((prev) => [...prev, item]);
8260
+ } else {
8261
+ setSelectedItems((prev) => prev.filter((selected) => selected.id !== item.id));
8262
+ }
8263
+ }
8264
+ }
8265
+ ),
8266
+ sortable: false,
8267
+ width: "50px"
8268
+ });
8269
+ }
8270
+ if (data.length > 0) {
8271
+ const sampleItem = data[0];
8272
+ Object.keys(sampleItem).forEach((key) => {
8273
+ if (key === "id") return;
8274
+ const isStatus = key.toLowerCase().includes("status");
8275
+ const isCategory = key.toLowerCase().includes("category") || key.toLowerCase().includes("type");
8276
+ const isDate = key.toLowerCase().includes("date") || key.toLowerCase().includes("time");
8277
+ const isAmount = key.toLowerCase().includes("amount") || key.toLowerCase().includes("price") || key.toLowerCase().includes("cost");
8278
+ generatedColumns.push({
8279
+ key,
8280
+ header: key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, " $1"),
8281
+ type: isStatus ? "status" : isCategory ? "category" : "default",
8282
+ sortable: true,
8283
+ cell: renderCustomColumn ? (item) => {
8284
+ const column = { key, header: "", type: isStatus ? "status" : isCategory ? "category" : "default" };
8285
+ const customContent = renderCustomColumn(column, item);
8286
+ if (customContent) return customContent;
8287
+ const value = item[key];
8288
+ if (isDate && value) {
8289
+ return new Date(value).toLocaleDateString();
8290
+ }
8291
+ if (isAmount && typeof value === "number") {
8292
+ return new Intl.NumberFormat("en-US", {
8293
+ style: "currency",
8294
+ currency: "USD"
8295
+ }).format(value);
8296
+ }
8297
+ return (value == null ? void 0 : value.toString()) || "-";
8298
+ } : void 0
8299
+ });
8300
+ });
8301
+ }
8302
+ return generatedColumns;
8303
+ }, [customColumns, data, enableSelection, selectedItems, renderCustomColumn]);
8304
+ const handleExport = () => {
8305
+ if (onExport) {
8306
+ onExport(selectedItems.length > 0 ? selectedItems : data);
8307
+ } else {
8308
+ const headers = tableColumns.filter((col) => col.key !== "__selection").map((col) => col.key);
8309
+ const csvContent = [
8310
+ headers.join(","),
8311
+ ...(selectedItems.length > 0 ? selectedItems : data).map(
8312
+ (item) => headers.map((header) => item[header] || "").join(",")
8313
+ )
8314
+ ].join("\n");
8315
+ const blob = new Blob([csvContent], { type: "text/csv" });
8316
+ const url = URL.createObjectURL(blob);
8317
+ const a = document.createElement("a");
8318
+ a.href = url;
8319
+ a.download = `${config.display.title.toLowerCase().replace(/\s+/g, "-")}-export.csv`;
8320
+ a.click();
8321
+ URL.revokeObjectURL(url);
8322
+ }
8323
+ };
8324
+ const renderToolbarSection = () => {
8325
+ var _a;
8326
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4 mb-4", children: [
8327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8328
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-foreground", children: config.display.title }),
8329
+ config.display.description && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "outline", className: "text-xs", children: [
8330
+ data.length,
8331
+ " items"
8332
+ ] })
8333
+ ] }),
8334
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8335
+ renderToolbar && renderToolbar(),
8336
+ enableFiltering && /* @__PURE__ */ jsxRuntime.jsxs(
8337
+ Button,
8338
+ {
8339
+ variant: "outline",
8340
+ size: "sm",
8341
+ onClick: () => setShowFilters(!showFilters),
8342
+ className: cn(showFilters && "bg-muted"),
8343
+ children: [
8344
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-4 h-4 mr-2" }),
8345
+ "Filters"
8346
+ ]
8347
+ }
8348
+ ),
8349
+ enableRefresh && /* @__PURE__ */ jsxRuntime.jsxs(
8350
+ Button,
8351
+ {
8352
+ variant: "outline",
8353
+ size: "sm",
8354
+ onClick: onRefresh,
8355
+ disabled: isLoading,
8356
+ children: [
8357
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: cn("w-4 h-4 mr-2", isLoading && "animate-spin") }),
8358
+ "Refresh"
8359
+ ]
8360
+ }
8361
+ ),
8362
+ enableExport && /* @__PURE__ */ jsxRuntime.jsxs(
8363
+ Button,
8364
+ {
8365
+ variant: "outline",
8366
+ size: "sm",
8367
+ onClick: handleExport,
8368
+ disabled: data.length === 0,
8369
+ children: [
8370
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "w-4 h-4 mr-2" }),
8371
+ "Export"
8372
+ ]
8373
+ }
8374
+ ),
8375
+ (_a = config.actions) == null ? void 0 : _a.filter((action) => action.type === "primary").map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
8376
+ Button,
8377
+ {
8378
+ size: "sm",
8379
+ onClick: () => onAction == null ? void 0 : onAction(action, []),
8380
+ disabled: isLoading,
8381
+ children: [
8382
+ action.icon && /* @__PURE__ */ jsxRuntime.jsx(action.icon, { className: "w-4 h-4 mr-2" }),
8383
+ action.label
8384
+ ]
8385
+ },
8386
+ action.label
8387
+ ))
8388
+ ] })
8389
+ ] });
8390
+ };
8391
+ const renderBulkActionsSection = () => {
8392
+ var _a;
8393
+ if (!enableBulkActions || selectedItems.length === 0) return null;
8394
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between bg-muted/50 p-3 rounded-md mb-4", children: [
8395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8396
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-muted-foreground", children: [
8397
+ selectedItems.length,
8398
+ " items selected"
8399
+ ] }),
8400
+ /* @__PURE__ */ jsxRuntime.jsx(
8401
+ Button,
8402
+ {
8403
+ variant: "ghost",
8404
+ size: "sm",
8405
+ onClick: () => setSelectedItems([]),
8406
+ children: "Clear selection"
8407
+ }
8408
+ )
8409
+ ] }),
8410
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8411
+ renderBulkActions && renderBulkActions(selectedItems),
8412
+ (_a = config.actions) == null ? void 0 : _a.filter((action) => action.type !== "primary").map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
8413
+ Button,
8414
+ {
8415
+ variant: action.type === "danger" ? "destructive" : "outline",
8416
+ size: "sm",
8417
+ onClick: () => onAction == null ? void 0 : onAction(action, selectedItems),
8418
+ children: [
8419
+ action.icon && /* @__PURE__ */ jsxRuntime.jsx(action.icon, { className: "w-4 h-4 mr-2" }),
8420
+ action.label
8421
+ ]
8422
+ },
8423
+ action.label
8424
+ ))
8425
+ ] })
8426
+ ] });
8427
+ };
8428
+ const renderEmptyStateSection = () => {
8429
+ var _a;
8430
+ if (data.length > 0) return null;
8431
+ if (renderEmptyState) {
8432
+ return renderEmptyState();
8433
+ }
8434
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
8435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-muted-foreground mb-4", children: [
8436
+ "No ",
8437
+ config.display.title.toLowerCase(),
8438
+ " found"
8439
+ ] }),
8440
+ ((_a = config.actions) == null ? void 0 : _a.find((action) => action.type === "primary")) && /* @__PURE__ */ jsxRuntime.jsxs(Button, { onClick: () => {
8441
+ var _a2;
8442
+ const primaryAction = (_a2 = config.actions) == null ? void 0 : _a2.find((action) => action.type === "primary");
8443
+ if (primaryAction) onAction == null ? void 0 : onAction(primaryAction, []);
8444
+ }, children: [
8445
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-4 h-4 mr-2" }),
8446
+ "Add ",
8447
+ config.display.title.slice(0, -1)
8448
+ ] })
8449
+ ] });
8450
+ };
8451
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("p-6", className), category: config.display.category, "data-component-name": "EntityListPanel", children: [
8452
+ headerSlot,
8453
+ renderToolbarSection(),
8454
+ renderBulkActionsSection(),
8455
+ data.length === 0 ? renderEmptyStateSection() : /* @__PURE__ */ jsxRuntime.jsx(
8456
+ DataTable,
8457
+ {
8458
+ data,
8459
+ columns: tableColumns,
8460
+ isLoading,
8461
+ showSearch,
8462
+ showPagination,
8463
+ pageSize,
8464
+ searchPlaceholder: searchPlaceholder || `Search ${config.display.title.toLowerCase()}...`,
8465
+ onRowClick,
8466
+ hover: !!onRowClick,
8467
+ emptyMessage: `No ${config.display.title.toLowerCase()} found`
8468
+ }
8469
+ ),
8470
+ footerSlot
8471
+ ] });
8472
+ };
8473
+ const TrendAnalysisPanel = ({
8474
+ metrics,
8475
+ data,
8476
+ temporal,
8477
+ isLoading = false,
8478
+ className,
8479
+ category,
8480
+ defaultChartType = "line",
8481
+ dateField = "date",
8482
+ enablePeriodSelection = true,
8483
+ enableChartTypeSelection = true,
8484
+ enableMetricSelection = true,
8485
+ showComparisons = true,
8486
+ renderHeader,
8487
+ renderFooter,
8488
+ renderCustomChart,
8489
+ headerSlot,
8490
+ footerSlot,
8491
+ onMetricChange,
8492
+ onPeriodChange,
8493
+ onChartTypeChange,
8494
+ onExport
8495
+ }) => {
8496
+ const [selectedMetric, setSelectedMetric] = React.useState(metrics[0]);
8497
+ const [selectedPeriod, setSelectedPeriod] = React.useState((temporal == null ? void 0 : temporal.defaultCycle) || "monthly");
8498
+ const [selectedChartType, setSelectedChartType] = React.useState(defaultChartType);
8499
+ const [showForecast, setShowForecast] = React.useState(false);
8500
+ const trendData = React.useMemo(() => {
8501
+ if (!selectedMetric || !data.length) return [];
8502
+ const periods = selectedPeriod === "yearly" ? 5 : selectedPeriod === "quarterly" ? 8 : selectedPeriod === "monthly" ? 12 : selectedPeriod === "weekly" ? 12 : 30;
8503
+ return MetricCalculationEngine.calculateTrendData(
8504
+ selectedMetric,
8505
+ data,
8506
+ dateField,
8507
+ periods
8508
+ );
8509
+ }, [selectedMetric, data, dateField, selectedPeriod]);
8510
+ const chartData = React.useMemo(() => {
8511
+ return trendData.map((point) => ({
8512
+ label: point.label || point.date,
8513
+ value: point.value,
8514
+ category
8515
+ }));
8516
+ }, [trendData, category]);
8517
+ const trendPercentage = React.useMemo(() => {
8518
+ if (chartData.length < 2) return null;
8519
+ const first = chartData[0].value;
8520
+ const last = chartData[chartData.length - 1].value;
8521
+ if (first === 0) return null;
8522
+ return (last - first) / Math.abs(first) * 100;
8523
+ }, [chartData]);
8524
+ const forecastData = React.useMemo(() => {
8525
+ var _a, _b;
8526
+ if (!showForecast || !((_a = temporal == null ? void 0 : temporal.forecasting) == null ? void 0 : _a.enabled) || chartData.length < 3) {
8527
+ return [];
8528
+ }
8529
+ const periods = ((_b = temporal == null ? void 0 : temporal.forecasting) == null ? void 0 : _b.periods) || 3;
8530
+ const lastValue = chartData[chartData.length - 1].value;
8531
+ const trend = trendPercentage ? trendPercentage / 100 : 0;
8532
+ return Array.from({ length: periods }, (_, index) => ({
8533
+ label: `Future ${index + 1}`,
8534
+ value: lastValue * (1 + trend * (index + 1) / chartData.length),
8535
+ category: 8
8536
+ // Use category 8 for forecast
8537
+ }));
8538
+ }, [showForecast, temporal == null ? void 0 : temporal.forecasting, chartData, trendPercentage]);
8539
+ const combinedChartData = React.useMemo(() => {
8540
+ if (forecastData.length === 0) return chartData;
8541
+ return [...chartData, ...forecastData];
8542
+ }, [chartData, forecastData]);
8543
+ const handleMetricChange = (metricKey) => {
8544
+ const metric = metrics.find((m) => m.key === metricKey);
8545
+ if (metric) {
8546
+ setSelectedMetric(metric);
8547
+ onMetricChange == null ? void 0 : onMetricChange(metric);
8548
+ }
8549
+ };
8550
+ const handlePeriodChange = (period) => {
8551
+ setSelectedPeriod(period);
8552
+ onPeriodChange == null ? void 0 : onPeriodChange(period);
8553
+ };
8554
+ const handleChartTypeChange = (chartType) => {
8555
+ setSelectedChartType(chartType);
8556
+ onChartTypeChange == null ? void 0 : onChartTypeChange(chartType);
8557
+ };
8558
+ const handleExport = () => {
8559
+ if (onExport) {
8560
+ onExport(combinedChartData, selectedMetric);
8561
+ } else {
8562
+ const csvContent = [
8563
+ "Date,Value",
8564
+ ...combinedChartData.map((point) => `${point.label},${point.value}`)
8565
+ ].join("\n");
8566
+ const blob = new Blob([csvContent], { type: "text/csv" });
8567
+ const url = URL.createObjectURL(blob);
8568
+ const a = document.createElement("a");
8569
+ a.href = url;
8570
+ a.download = `${selectedMetric.label}-trend-data.csv`;
8571
+ a.click();
8572
+ URL.revokeObjectURL(url);
8573
+ }
8574
+ };
8575
+ const renderControls = () => {
8576
+ var _a;
8577
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
8578
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
8579
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8580
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { className: "w-4 h-4 text-muted-foreground" }),
8581
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-foreground", children: "Trend Analysis" })
8582
+ ] }),
8583
+ trendPercentage !== null && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: trendPercentage > 0 ? "default" : "destructive", children: [
8584
+ trendPercentage > 0 ? "+" : "",
8585
+ trendPercentage.toFixed(1),
8586
+ "%"
8587
+ ] })
8588
+ ] }),
8589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8590
+ enableMetricSelection && metrics.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
8591
+ Select,
8592
+ {
8593
+ value: selectedMetric.key,
8594
+ onValueChange: handleMetricChange,
8595
+ children: metrics.map((metric) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: metric.key, children: metric.label }, metric.key))
8596
+ }
8597
+ ),
8598
+ enablePeriodSelection && /* @__PURE__ */ jsxRuntime.jsx(
8599
+ Select,
8600
+ {
8601
+ value: selectedPeriod,
8602
+ onValueChange: (value) => handlePeriodChange(value),
8603
+ children: ((temporal == null ? void 0 : temporal.cycles) || ["daily", "weekly", "monthly", "quarterly", "yearly"]).map((cycle) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: cycle, children: cycle.charAt(0).toUpperCase() + cycle.slice(1) }, cycle))
8604
+ }
8605
+ ),
8606
+ enableChartTypeSelection && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center border rounded", children: [
8607
+ /* @__PURE__ */ jsxRuntime.jsx(
8608
+ Button,
8609
+ {
8610
+ variant: selectedChartType === "line" ? "default" : "ghost",
8611
+ size: "sm",
8612
+ onClick: () => handleChartTypeChange("line"),
8613
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LineChart, { className: "w-4 h-4" })
8614
+ }
8615
+ ),
8616
+ /* @__PURE__ */ jsxRuntime.jsx(
8617
+ Button,
8618
+ {
8619
+ variant: selectedChartType === "bar" ? "default" : "ghost",
8620
+ size: "sm",
8621
+ onClick: () => handleChartTypeChange("bar"),
8622
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BarChart3, { className: "w-4 h-4" })
8623
+ }
8624
+ ),
8625
+ /* @__PURE__ */ jsxRuntime.jsx(
8626
+ Button,
8627
+ {
8628
+ variant: selectedChartType === "area" ? "default" : "ghost",
8629
+ size: "sm",
8630
+ onClick: () => handleChartTypeChange("area"),
8631
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AreaChart, { className: "w-4 h-4" })
8632
+ }
8633
+ )
8634
+ ] }),
8635
+ ((_a = temporal == null ? void 0 : temporal.forecasting) == null ? void 0 : _a.enabled) && /* @__PURE__ */ jsxRuntime.jsx(
8636
+ Button,
8637
+ {
8638
+ variant: showForecast ? "default" : "outline",
8639
+ size: "sm",
8640
+ onClick: () => setShowForecast(!showForecast),
8641
+ children: "Forecast"
8642
+ }
8643
+ ),
8644
+ /* @__PURE__ */ jsxRuntime.jsx(
8645
+ Button,
8646
+ {
8647
+ variant: "outline",
8648
+ size: "sm",
8649
+ onClick: handleExport,
8650
+ disabled: chartData.length === 0,
8651
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "w-4 h-4" })
8652
+ }
8653
+ )
8654
+ ] })
8655
+ ] });
8656
+ };
8657
+ const renderChart = () => {
8658
+ if (renderCustomChart) {
8659
+ const customChart = renderCustomChart(selectedMetric, combinedChartData, selectedChartType);
8660
+ if (customChart) return customChart;
8661
+ }
8662
+ return /* @__PURE__ */ jsxRuntime.jsx(
8663
+ Chart,
8664
+ {
8665
+ title: selectedMetric.label,
8666
+ subtitle: `${selectedPeriod} trend analysis`,
8667
+ data: combinedChartData,
8668
+ type: selectedChartType,
8669
+ category,
8670
+ showTrend: true,
8671
+ trend: trendPercentage !== null ? {
8672
+ value: trendPercentage,
8673
+ label: "overall trend"
8674
+ } : void 0,
8675
+ height: "large",
8676
+ isLoading,
8677
+ noWrapper: true,
8678
+ showLegend: forecastData.length > 0
8679
+ }
8680
+ );
8681
+ };
8682
+ const renderComparisons = () => {
8683
+ var _a, _b;
8684
+ if (!showComparisons || !(temporal == null ? void 0 : temporal.enableComparisons) || chartData.length === 0) {
8685
+ return null;
8686
+ }
8687
+ const currentValue = ((_a = chartData[chartData.length - 1]) == null ? void 0 : _a.value) || 0;
8688
+ const previousValue = ((_b = chartData[chartData.length - 2]) == null ? void 0 : _b.value) || 0;
8689
+ const periodChange = previousValue !== 0 ? (currentValue - previousValue) / Math.abs(previousValue) * 100 : 0;
8690
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-4 mt-4", children: [
8691
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-foreground mb-3", children: "Period Comparisons" }),
8692
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-4", children: [
8693
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
8694
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold", children: currentValue.toFixed(0) }),
8695
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Current" })
8696
+ ] }),
8697
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
8698
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold", children: previousValue.toFixed(0) }),
8699
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Previous" })
8700
+ ] }),
8701
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
8702
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
8703
+ "text-2xl font-bold",
8704
+ periodChange > 0 ? "text-status-success" : periodChange < 0 ? "text-status-error" : "text-muted-foreground"
8705
+ ), children: [
8706
+ periodChange > 0 ? "+" : "",
8707
+ periodChange.toFixed(1),
8708
+ "%"
8709
+ ] }),
8710
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Change" })
8711
+ ] })
8712
+ ] })
8713
+ ] });
8714
+ };
8715
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("p-6", className), category, "data-component-name": "TrendAnalysisPanel", children: [
8716
+ headerSlot,
8717
+ renderHeader && renderHeader(),
8718
+ renderControls(),
8719
+ renderChart(),
8720
+ renderComparisons(),
8721
+ renderFooter && renderFooter(),
8722
+ footerSlot
8723
+ ] });
8724
+ };
8725
+ const CategoryBreakdownPanel = ({
8726
+ data,
8727
+ categoryConfig,
8728
+ valueField,
8729
+ isLoading = false,
8730
+ className,
8731
+ category,
8732
+ title = "Category Breakdown",
8733
+ subtitle,
8734
+ defaultView = "both",
8735
+ defaultChartType = "pie",
8736
+ maxCategories = 8,
8737
+ showPercentages = true,
8738
+ enableDrillDown = true,
8739
+ renderHeader,
8740
+ renderFooter,
8741
+ renderCustomCategory,
8742
+ renderDrillDownContent,
8743
+ headerSlot,
8744
+ footerSlot,
8745
+ onCategoryClick,
8746
+ onDrillDown,
8747
+ onExport
8748
+ }) => {
8749
+ const [currentView, setCurrentView] = React.useState(defaultView);
8750
+ const [chartType, setChartType] = React.useState(defaultChartType);
8751
+ const [expandedCategories, setExpandedCategories] = React.useState(/* @__PURE__ */ new Set());
8752
+ const [drillDownLevel, setDrillDownLevel] = React.useState(0);
8753
+ const [drillDownPath, setDrillDownPath] = React.useState([]);
8754
+ const categoryBreakdown = React.useMemo(() => {
8755
+ var _a;
8756
+ if (!data.length) return [];
8757
+ const currentCategoryField = ((_a = categoryConfig == null ? void 0 : categoryConfig.hierarchy) == null ? void 0 : _a[drillDownLevel]) || (categoryConfig == null ? void 0 : categoryConfig.defaultGroupBy) || "category";
8758
+ return MetricCalculationEngine.calculateCategoryBreakdown(
8759
+ data,
8760
+ currentCategoryField,
8761
+ valueField,
8762
+ maxCategories
8763
+ );
8764
+ }, [data, categoryConfig, valueField, maxCategories, drillDownLevel]);
8765
+ const chartData = React.useMemo(() => {
8766
+ return categoryBreakdown.map((item, index) => ({
8767
+ label: item.category,
8768
+ value: item.value,
8769
+ category: index % 8 + 1
8770
+ }));
8771
+ }, [categoryBreakdown]);
8772
+ const totalValue = React.useMemo(() => {
8773
+ return categoryBreakdown.reduce((sum, item) => sum + item.value, 0);
8774
+ }, [categoryBreakdown]);
8775
+ const handleCategoryClick = (categoryItem) => {
8776
+ var _a;
8777
+ onCategoryClick == null ? void 0 : onCategoryClick(categoryItem);
8778
+ if (enableDrillDown && (categoryConfig == null ? void 0 : categoryConfig.enableDrillDown) && drillDownLevel < (((_a = categoryConfig == null ? void 0 : categoryConfig.hierarchy) == null ? void 0 : _a.length) || 0) - 1) {
8779
+ setDrillDownLevel((prev) => prev + 1);
8780
+ setDrillDownPath((prev) => [...prev, categoryItem.category]);
8781
+ onDrillDown == null ? void 0 : onDrillDown(categoryItem.category, drillDownLevel + 1);
8782
+ }
8783
+ };
8784
+ const handleDrillUp = (level) => {
8785
+ if (level < drillDownLevel) {
8786
+ setDrillDownLevel(level);
8787
+ setDrillDownPath((prev) => prev.slice(0, level));
8788
+ onDrillDown == null ? void 0 : onDrillDown(level > 0 ? drillDownPath[level - 1] : "", level);
8789
+ }
8790
+ };
8791
+ const toggleCategoryExpansion = (categoryName) => {
8792
+ setExpandedCategories((prev) => {
8793
+ const newSet = new Set(prev);
8794
+ if (newSet.has(categoryName)) {
8795
+ newSet.delete(categoryName);
8796
+ } else {
8797
+ newSet.add(categoryName);
8798
+ }
8799
+ return newSet;
8800
+ });
8801
+ };
8802
+ const handleExport = () => {
8803
+ if (onExport) {
8804
+ onExport(categoryBreakdown);
8805
+ } else {
8806
+ const csvContent = [
8807
+ "Category,Value,Percentage",
8808
+ ...categoryBreakdown.map(
8809
+ (item) => `${item.category},${item.value},${item.percentage.toFixed(2)}%`
8810
+ )
8811
+ ].join("\n");
8812
+ const blob = new Blob([csvContent], { type: "text/csv" });
8813
+ const url = URL.createObjectURL(blob);
8814
+ const a = document.createElement("a");
8815
+ a.href = url;
8816
+ a.download = `category-breakdown-${Date.now()}.csv`;
8817
+ a.click();
8818
+ URL.revokeObjectURL(url);
8819
+ }
8820
+ };
8821
+ const renderControls = () => {
8822
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
8823
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
8824
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8825
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PieChart, { className: "w-4 h-4 text-muted-foreground" }),
8826
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-foreground", children: title })
8827
+ ] }),
8828
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "outline", className: "text-xs", children: subtitle }),
8829
+ totalValue > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "outline", children: [
8830
+ "Total: ",
8831
+ new Intl.NumberFormat().format(totalValue)
8832
+ ] })
8833
+ ] }),
8834
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8835
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center border rounded", children: [
8836
+ /* @__PURE__ */ jsxRuntime.jsx(
8837
+ Button,
8838
+ {
8839
+ variant: currentView === "chart" ? "default" : "ghost",
8840
+ size: "sm",
8841
+ onClick: () => setCurrentView("chart"),
8842
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PieChart, { className: "w-4 h-4" })
8843
+ }
8844
+ ),
8845
+ /* @__PURE__ */ jsxRuntime.jsx(
8846
+ Button,
8847
+ {
8848
+ variant: currentView === "list" ? "default" : "ghost",
8849
+ size: "sm",
8850
+ onClick: () => setCurrentView("list"),
8851
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "w-4 h-4" })
8852
+ }
8853
+ ),
8854
+ /* @__PURE__ */ jsxRuntime.jsx(
8855
+ Button,
8856
+ {
8857
+ variant: currentView === "both" ? "default" : "ghost",
8858
+ size: "sm",
8859
+ onClick: () => setCurrentView("both"),
8860
+ children: "Both"
8861
+ }
8862
+ )
8863
+ ] }),
8864
+ (currentView === "chart" || currentView === "both") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center border rounded", children: [
8865
+ /* @__PURE__ */ jsxRuntime.jsx(
8866
+ Button,
8867
+ {
8868
+ variant: chartType === "pie" ? "default" : "ghost",
8869
+ size: "sm",
8870
+ onClick: () => setChartType("pie"),
8871
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PieChart, { className: "w-4 h-4" })
8872
+ }
8873
+ ),
8874
+ /* @__PURE__ */ jsxRuntime.jsx(
8875
+ Button,
8876
+ {
8877
+ variant: chartType === "bar" ? "default" : "ghost",
8878
+ size: "sm",
8879
+ onClick: () => setChartType("bar"),
8880
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BarChart3, { className: "w-4 h-4" })
8881
+ }
8882
+ )
8883
+ ] }),
8884
+ /* @__PURE__ */ jsxRuntime.jsx(
8885
+ Button,
8886
+ {
8887
+ variant: "outline",
8888
+ size: "sm",
8889
+ onClick: handleExport,
8890
+ disabled: categoryBreakdown.length === 0,
8891
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "w-4 h-4" })
8892
+ }
8893
+ )
8894
+ ] })
8895
+ ] });
8896
+ };
8897
+ const renderBreadcrumb = () => {
8898
+ if (drillDownLevel === 0) return null;
8899
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-4 text-sm text-muted-foreground", children: [
8900
+ /* @__PURE__ */ jsxRuntime.jsx(
8901
+ Button,
8902
+ {
8903
+ variant: "ghost",
8904
+ size: "sm",
8905
+ onClick: () => handleDrillUp(0),
8906
+ className: "p-0 h-auto font-normal",
8907
+ children: "All"
8908
+ }
8909
+ ),
8910
+ drillDownPath.map((segment, index) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
8911
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3" }),
8912
+ /* @__PURE__ */ jsxRuntime.jsx(
8913
+ Button,
8914
+ {
8915
+ variant: "ghost",
8916
+ size: "sm",
8917
+ onClick: () => handleDrillUp(index + 1),
8918
+ className: "p-0 h-auto font-normal",
8919
+ children: segment
8920
+ }
8921
+ )
8922
+ ] }, index))
8923
+ ] });
8924
+ };
8925
+ const renderChart = () => {
8926
+ if (currentView === "list") return null;
8927
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(currentView === "both" && "mb-6"), children: /* @__PURE__ */ jsxRuntime.jsx(
8928
+ Chart,
8929
+ {
8930
+ title: "",
8931
+ data: chartData,
8932
+ type: chartType,
8933
+ category,
8934
+ showLegend: true,
8935
+ height: "medium",
8936
+ isLoading,
8937
+ noWrapper: true,
8938
+ onClick: () => {
8939
+ }
8940
+ }
8941
+ ) });
8942
+ };
8943
+ const renderCategoryList = () => {
8944
+ if (currentView === "chart") return null;
8945
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: categoryBreakdown.map((item, index) => {
8946
+ if (renderCustomCategory) {
8947
+ const customContent = renderCustomCategory(item, index);
8948
+ if (customContent) return customContent;
8949
+ }
8950
+ const canExpand = enableDrillDown && categoryConfig.enableDrillDown && "subcategories" in item && item.subcategories && Array.isArray(item.subcategories) && item.subcategories.length > 0;
8951
+ const isExpanded = expandedCategories.has(item.category);
8952
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg", children: [
8953
+ /* @__PURE__ */ jsxRuntime.jsxs(
8954
+ "div",
8955
+ {
8956
+ className: cn(
8957
+ "flex items-center justify-between p-3 cursor-pointer hover:bg-muted/50",
8958
+ canExpand && "cursor-pointer"
8959
+ ),
8960
+ onClick: () => handleCategoryClick(item),
8961
+ children: [
8962
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
8963
+ canExpand && /* @__PURE__ */ jsxRuntime.jsx(
8964
+ Button,
8965
+ {
8966
+ variant: "ghost",
8967
+ size: "sm",
8968
+ className: "p-0 w-4 h-4",
8969
+ onClick: (e) => {
8970
+ e.stopPropagation();
8971
+ toggleCategoryExpansion(item.category);
8972
+ },
8973
+ children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3" })
8974
+ }
8975
+ ),
8976
+ /* @__PURE__ */ jsxRuntime.jsx(
8977
+ DataBadge,
8978
+ {
8979
+ variant: "category",
8980
+ category: index % 8 + 1,
8981
+ size: "sm",
8982
+ children: item.category
8983
+ }
8984
+ )
8985
+ ] }),
8986
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
8987
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
8988
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold", children: new Intl.NumberFormat().format(item.value) }),
8989
+ showPercentages && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
8990
+ item.percentage.toFixed(1),
8991
+ "%"
8992
+ ] })
8993
+ ] }),
8994
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 h-2 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
8995
+ "div",
8996
+ {
8997
+ className: cn(
8998
+ "h-full transition-all duration-300",
8999
+ `bg-category-${index % 8 + 1}`
9000
+ ),
9001
+ style: { width: `${item.percentage}%` }
9002
+ }
9003
+ ) })
9004
+ ] })
9005
+ ]
9006
+ }
9007
+ ),
9008
+ canExpand && isExpanded && "subcategories" in item && item.subcategories && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t bg-muted/20", children: renderDrillDownContent ? renderDrillDownContent(item.category, item.subcategories) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 space-y-1", children: Array.isArray(item.subcategories) && item.subcategories.map((subItem) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-sm pl-4", children: [
9009
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: subItem.category }),
9010
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: new Intl.NumberFormat().format(subItem.value) })
9011
+ ] }, subItem.category)) }) })
9012
+ ] }, item.category);
9013
+ }) });
9014
+ };
9015
+ const renderEmptyState = () => {
9016
+ if (categoryBreakdown.length > 0) return null;
9017
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-12", children: [
9018
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-8 h-8 text-muted-foreground mx-auto mb-4" }),
9019
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: "No category data available" })
9020
+ ] });
9021
+ };
9022
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("p-6", className), category, "data-component-name": "CategoryBreakdownPanel", children: [
9023
+ headerSlot,
9024
+ renderHeader && renderHeader(),
9025
+ renderControls(),
9026
+ renderBreadcrumb(),
9027
+ categoryBreakdown.length === 0 ? renderEmptyState() : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9028
+ renderChart(),
9029
+ renderCategoryList()
9030
+ ] }),
9031
+ renderFooter && renderFooter(),
9032
+ footerSlot
9033
+ ] });
9034
+ };
9035
+ const EntityPerformanceDashboardTemplate = ({
9036
+ config,
9037
+ data,
9038
+ previousData,
9039
+ isLoading = false,
9040
+ className,
9041
+ layout = "standard",
9042
+ showInsights = true,
9043
+ showTrends = true,
9044
+ showCategories = true,
9045
+ renderCustomActions,
9046
+ renderAdditionalMetrics,
9047
+ renderCustomTrendChart,
9048
+ renderCustomCategoryView,
9049
+ headerSlot,
9050
+ footerSlot,
9051
+ metricsHeaderSlot,
9052
+ metricsFooterSlot,
9053
+ trendsHeaderSlot,
9054
+ trendsFooterSlot,
9055
+ categoriesHeaderSlot,
9056
+ categoriesFooterSlot,
9057
+ onMetricClick,
9058
+ onCategoryClick,
9059
+ onTrendPeriodChange,
9060
+ onExport
9061
+ }) => {
9062
+ const getLayoutClasses = () => {
9063
+ switch (layout) {
9064
+ case "compact":
9065
+ return "space-y-4";
9066
+ case "detailed":
9067
+ return "space-y-8";
9068
+ case "standard":
9069
+ default:
9070
+ return "space-y-6";
9071
+ }
9072
+ };
9073
+ const renderPageHeader = () => {
9074
+ return /* @__PURE__ */ jsxRuntime.jsx(
9075
+ SectionHeader,
9076
+ {
9077
+ title: config.display.title,
9078
+ description: config.display.description,
9079
+ category: config.display.category,
9080
+ actions: renderCustomActions ? renderCustomActions() : void 0
9081
+ }
9082
+ );
9083
+ };
9084
+ const renderMetricsSection = () => {
9085
+ if (!config.metrics.length) return null;
9086
+ const MetricsComponent = showInsights ? MetricsOverviewWithInsightsPanel : MetricsOverviewPanel;
9087
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
9088
+ metricsHeaderSlot,
9089
+ /* @__PURE__ */ jsxRuntime.jsx(
9090
+ MetricsComponent,
9091
+ {
9092
+ metrics: config.metrics,
9093
+ data,
9094
+ previousData,
9095
+ isLoading,
9096
+ onMetricClick,
9097
+ category: config.display.category,
9098
+ columns: layout === "compact" ? 2 : layout === "detailed" ? 4 : 3,
9099
+ headerSlot: renderAdditionalMetrics ? renderAdditionalMetrics() : void 0
9100
+ }
9101
+ ),
9102
+ metricsFooterSlot
9103
+ ] });
9104
+ };
9105
+ const renderTrendsSection = () => {
9106
+ if (!showTrends || !config.temporal || !config.metrics.length) return null;
9107
+ if (renderCustomTrendChart) {
9108
+ const customChart = renderCustomTrendChart(config, data);
9109
+ if (customChart) {
9110
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
9111
+ trendsHeaderSlot,
9112
+ customChart,
9113
+ trendsFooterSlot
9114
+ ] });
9115
+ }
9116
+ }
9117
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
9118
+ trendsHeaderSlot,
9119
+ /* @__PURE__ */ jsxRuntime.jsx(
9120
+ TrendAnalysisPanel,
9121
+ {
9122
+ metrics: config.metrics,
9123
+ data,
9124
+ temporal: config.temporal,
9125
+ isLoading,
9126
+ category: config.display.category,
9127
+ enablePeriodSelection: true,
9128
+ enableChartTypeSelection: layout === "detailed",
9129
+ showComparisons: layout !== "compact",
9130
+ onPeriodChange: onTrendPeriodChange,
9131
+ onExport: (chartData, metric) => onExport == null ? void 0 : onExport("trends", { chartData, metric })
9132
+ }
9133
+ ),
9134
+ trendsFooterSlot
9135
+ ] });
9136
+ };
9137
+ const renderCategoriesSection = () => {
9138
+ var _a;
9139
+ if (!showCategories || !config.categories || !data.length) return null;
9140
+ const valueField = ((_a = config.metrics.find((m) => m.type === "currency" || m.type === "count")) == null ? void 0 : _a.key) || Object.keys(data[0]).find((key) => typeof data[0][key] === "number") || "value";
9141
+ if (renderCustomCategoryView) {
9142
+ const customView = renderCustomCategoryView(config, data);
9143
+ if (customView) {
9144
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
9145
+ categoriesHeaderSlot,
9146
+ customView,
9147
+ categoriesFooterSlot
9148
+ ] });
9149
+ }
9150
+ }
9151
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
9152
+ categoriesHeaderSlot,
9153
+ /* @__PURE__ */ jsxRuntime.jsx(
9154
+ CategoryBreakdownPanel,
9155
+ {
9156
+ data,
9157
+ categoryConfig: config.categories,
9158
+ valueField,
9159
+ isLoading,
9160
+ category: config.display.category,
9161
+ title: `${config.display.title} by ${config.categories.defaultGroupBy}`,
9162
+ defaultView: layout === "compact" ? "list" : "both",
9163
+ enableDrillDown: config.categories.enableDrillDown,
9164
+ onCategoryClick,
9165
+ onExport: (categoryData) => onExport == null ? void 0 : onExport("categories", categoryData)
9166
+ }
9167
+ ),
9168
+ categoriesFooterSlot
9169
+ ] });
9170
+ };
9171
+ const renderLayoutContent = () => {
9172
+ const sections = [
9173
+ renderMetricsSection(),
9174
+ renderTrendsSection(),
9175
+ renderCategoriesSection()
9176
+ ].filter(Boolean);
9177
+ if (layout === "detailed" && sections.length > 1) {
9178
+ const [metricsSection, ...otherSections] = sections;
9179
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: getLayoutClasses(), children: [
9180
+ metricsSection,
9181
+ otherSections.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: otherSections })
9182
+ ] });
9183
+ }
9184
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: getLayoutClasses(), children: sections });
9185
+ };
9186
+ return /* @__PURE__ */ jsxRuntime.jsx(AppLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(
9187
+ PageTemplate,
9188
+ {
9189
+ className: cn("container mx-auto px-4 py-6", className),
9190
+ "data-component-name": "EntityPerformanceDashboardTemplate",
9191
+ children: [
9192
+ headerSlot,
9193
+ renderPageHeader(),
9194
+ renderLayoutContent(),
9195
+ footerSlot
9196
+ ]
9197
+ }
9198
+ ) });
9199
+ };
9200
+ const EntityPerformanceDashboardTemplateWithRealTime = ({
9201
+ enableRealTime = false,
9202
+ refreshInterval = 3e4,
9203
+ // 30 seconds
9204
+ onDataUpdate,
9205
+ ...props
9206
+ }) => {
9207
+ React.useEffect(() => {
9208
+ if (!enableRealTime) return;
9209
+ const interval = setInterval(() => {
9210
+ if (onDataUpdate) {
9211
+ onDataUpdate(props.data);
9212
+ }
9213
+ }, refreshInterval);
9214
+ return () => clearInterval(interval);
9215
+ }, [enableRealTime, refreshInterval, onDataUpdate, props.data]);
9216
+ return /* @__PURE__ */ jsxRuntime.jsx(EntityPerformanceDashboardTemplate, { ...props });
9217
+ };
9218
+ const EntityManagementTemplate = ({
9219
+ config,
9220
+ data,
9221
+ isLoading = false,
9222
+ className,
9223
+ enableSearch = true,
9224
+ enableFiltering = true,
9225
+ enableBulkActions = true,
9226
+ enableExport = true,
9227
+ pageSize = 10,
9228
+ onCreate,
9229
+ onUpdate,
9230
+ onDelete,
9231
+ onBulkDelete,
9232
+ onView,
9233
+ renderCreateForm,
9234
+ renderEditForm,
9235
+ renderDetailView,
9236
+ renderCustomActions,
9237
+ renderEmptyState,
9238
+ renderFilterPanel,
9239
+ headerSlot,
9240
+ footerSlot,
9241
+ toolbarSlot,
9242
+ listHeaderSlot,
9243
+ listFooterSlot,
9244
+ onRefresh,
9245
+ onFilter,
9246
+ onExport
9247
+ }) => {
9248
+ const [showCreateModal, setShowCreateModal] = React.useState(false);
9249
+ const [showEditModal, setShowEditModal] = React.useState(false);
9250
+ const [showDetailModal, setShowDetailModal] = React.useState(false);
9251
+ const [showFilterPanel, setShowFilterPanel] = React.useState(false);
9252
+ const [selectedItem, setSelectedItem] = React.useState(null);
9253
+ const [selectedItems, setSelectedItems] = React.useState([]);
9254
+ const handleCreate = async (item) => {
9255
+ if (onCreate) {
9256
+ try {
9257
+ await onCreate(item);
9258
+ setShowCreateModal(false);
9259
+ onRefresh == null ? void 0 : onRefresh();
9260
+ } catch (error) {
9261
+ console.error("Create failed:", error);
9262
+ }
9263
+ }
9264
+ };
9265
+ const handleUpdate = async (item) => {
9266
+ if (onUpdate && selectedItem) {
9267
+ try {
9268
+ await onUpdate(selectedItem.id, item);
9269
+ setShowEditModal(false);
9270
+ setSelectedItem(null);
9271
+ onRefresh == null ? void 0 : onRefresh();
9272
+ } catch (error) {
9273
+ console.error("Update failed:", error);
9274
+ }
9275
+ }
9276
+ };
9277
+ const handleBulkDelete = async () => {
9278
+ if (onBulkDelete && selectedItems.length > 0 && confirm(`Are you sure you want to delete ${selectedItems.length} ${config.display.title.toLowerCase()}?`)) {
9279
+ try {
9280
+ const ids = selectedItems.map((item) => item.id);
9281
+ await onBulkDelete(ids);
9282
+ setSelectedItems([]);
9283
+ onRefresh == null ? void 0 : onRefresh();
9284
+ } catch (error) {
9285
+ console.error("Bulk delete failed:", error);
9286
+ }
9287
+ }
9288
+ };
9289
+ const handleView = (item) => {
9290
+ if (onView) {
9291
+ onView(item);
9292
+ } else {
9293
+ setSelectedItem(item);
9294
+ setShowDetailModal(true);
9295
+ }
9296
+ };
9297
+ const handleEdit = (item) => {
9298
+ setSelectedItem(item);
9299
+ setShowEditModal(true);
9300
+ };
9301
+ const handleRowClick = (item) => {
9302
+ handleView(item);
9303
+ };
9304
+ const handleAction = (action, selectedItems2) => {
9305
+ action.onClick({ selectedItems: selectedItems2, config });
9306
+ };
9307
+ const generateDefaultActions = () => {
9308
+ const actions = [];
9309
+ if (onCreate) {
9310
+ actions.push({
9311
+ label: `Add ${config.display.title.slice(0, -1)}`,
9312
+ type: "primary",
9313
+ icon: lucideReact.Plus,
9314
+ onClick: () => setShowCreateModal(true)
9315
+ });
9316
+ }
9317
+ return actions;
9318
+ };
9319
+ const renderPageHeader = () => {
9320
+ const actions = [
9321
+ ...generateDefaultActions(),
9322
+ ...config.actions || []
9323
+ ];
9324
+ return /* @__PURE__ */ jsxRuntime.jsx(
9325
+ SectionHeader,
9326
+ {
9327
+ title: config.display.title,
9328
+ description: config.display.description,
9329
+ category: config.display.category,
9330
+ actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9331
+ renderCustomActions && renderCustomActions(),
9332
+ enableFiltering && /* @__PURE__ */ jsxRuntime.jsxs(
9333
+ Button,
9334
+ {
9335
+ variant: "outline",
9336
+ size: "sm",
9337
+ onClick: () => setShowFilterPanel(!showFilterPanel),
9338
+ className: cn(showFilterPanel && "bg-muted"),
9339
+ children: [
9340
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Filter, { className: "w-4 h-4 mr-2" }),
9341
+ "Filters"
9342
+ ]
9343
+ }
9344
+ ),
9345
+ enableExport && /* @__PURE__ */ jsxRuntime.jsxs(
9346
+ Button,
9347
+ {
9348
+ variant: "outline",
9349
+ size: "sm",
9350
+ onClick: () => onExport == null ? void 0 : onExport(selectedItems.length > 0 ? selectedItems : data, "csv"),
9351
+ disabled: data.length === 0,
9352
+ children: [
9353
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "w-4 h-4 mr-2" }),
9354
+ "Export"
9355
+ ]
9356
+ }
9357
+ ),
9358
+ actions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
9359
+ Button,
9360
+ {
9361
+ variant: action.type === "primary" ? "default" : "outline",
9362
+ size: "sm",
9363
+ onClick: () => action.onClick({ data, config }),
9364
+ children: [
9365
+ action.icon && /* @__PURE__ */ jsxRuntime.jsx(action.icon, { className: "w-4 h-4 mr-2" }),
9366
+ action.label
9367
+ ]
9368
+ },
9369
+ action.label
9370
+ ))
9371
+ ] })
9372
+ }
9373
+ );
9374
+ };
9375
+ const renderToolbar = () => {
9376
+ if (selectedItems.length === 0) return null;
9377
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted/50 p-4 rounded-lg mb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
9378
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9379
+ /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "secondary", children: [
9380
+ selectedItems.length,
9381
+ " selected"
9382
+ ] }),
9383
+ /* @__PURE__ */ jsxRuntime.jsx(
9384
+ Button,
9385
+ {
9386
+ variant: "ghost",
9387
+ size: "sm",
9388
+ onClick: () => setSelectedItems([]),
9389
+ children: "Clear selection"
9390
+ }
9391
+ )
9392
+ ] }),
9393
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9394
+ onBulkDelete && /* @__PURE__ */ jsxRuntime.jsxs(
9395
+ Button,
9396
+ {
9397
+ variant: "destructive",
9398
+ size: "sm",
9399
+ onClick: handleBulkDelete,
9400
+ children: [
9401
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4 mr-2" }),
9402
+ "Delete Selected"
9403
+ ]
9404
+ }
9405
+ ),
9406
+ enableExport && /* @__PURE__ */ jsxRuntime.jsxs(
9407
+ Button,
9408
+ {
9409
+ variant: "outline",
9410
+ size: "sm",
9411
+ onClick: () => onExport == null ? void 0 : onExport(selectedItems, "csv"),
9412
+ children: [
9413
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "w-4 h-4 mr-2" }),
9414
+ "Export Selected"
9415
+ ]
9416
+ }
9417
+ )
9418
+ ] })
9419
+ ] }) });
9420
+ };
9421
+ const renderFilterPanelSection = () => {
9422
+ if (!showFilterPanel) return null;
9423
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 mb-4", children: renderFilterPanel ? renderFilterPanel(onFilter || (() => {
9424
+ })) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-muted-foreground py-4", children: "Filter functionality not implemented yet" }) });
9425
+ };
9426
+ const renderCreateModal = () => {
9427
+ if (!showCreateModal) return null;
9428
+ return /* @__PURE__ */ jsxRuntime.jsx(
9429
+ Modal,
9430
+ {
9431
+ isOpen: showCreateModal,
9432
+ onClose: () => setShowCreateModal(false),
9433
+ title: `Create ${config.display.title.slice(0, -1)}`,
9434
+ category: config.display.category,
9435
+ children: renderCreateForm ? renderCreateForm(handleCreate, () => setShowCreateModal(false)) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-center text-muted-foreground", children: "Create form not implemented yet" })
9436
+ }
9437
+ );
9438
+ };
9439
+ const renderEditModal = () => {
9440
+ if (!showEditModal || !selectedItem) return null;
9441
+ return /* @__PURE__ */ jsxRuntime.jsx(
9442
+ Modal,
9443
+ {
9444
+ isOpen: showEditModal,
9445
+ onClose: () => {
9446
+ setShowEditModal(false);
9447
+ setSelectedItem(null);
9448
+ },
9449
+ title: `Edit ${config.display.title.slice(0, -1)}`,
9450
+ category: config.display.category,
9451
+ children: renderEditForm ? renderEditForm(
9452
+ selectedItem,
9453
+ handleUpdate,
9454
+ () => {
9455
+ setShowEditModal(false);
9456
+ setSelectedItem(null);
9457
+ }
9458
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-center text-muted-foreground", children: "Edit form not implemented yet" })
9459
+ }
9460
+ );
9461
+ };
9462
+ const renderDetailModal = () => {
9463
+ if (!showDetailModal || !selectedItem) return null;
9464
+ return /* @__PURE__ */ jsxRuntime.jsx(
9465
+ Modal,
9466
+ {
9467
+ isOpen: showDetailModal,
9468
+ onClose: () => {
9469
+ setShowDetailModal(false);
9470
+ setSelectedItem(null);
9471
+ },
9472
+ title: `${config.display.title.slice(0, -1)} Details`,
9473
+ category: config.display.category,
9474
+ size: "large",
9475
+ children: renderDetailView ? renderDetailView(
9476
+ selectedItem,
9477
+ () => {
9478
+ setShowDetailModal(false);
9479
+ handleEdit(selectedItem);
9480
+ },
9481
+ () => {
9482
+ setShowDetailModal(false);
9483
+ setSelectedItem(null);
9484
+ }
9485
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: Object.entries(selectedItem).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
9486
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium capitalize", children: [
9487
+ key,
9488
+ ":"
9489
+ ] }),
9490
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: (value == null ? void 0 : value.toString()) || "-" })
9491
+ ] }, key)) }) })
9492
+ }
9493
+ );
9494
+ };
9495
+ return /* @__PURE__ */ jsxRuntime.jsx(AppLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(
9496
+ PageTemplate,
9497
+ {
9498
+ className: cn("container mx-auto px-4 py-6", className),
9499
+ "data-component-name": "EntityManagementTemplate",
9500
+ children: [
9501
+ headerSlot,
9502
+ renderPageHeader(),
9503
+ toolbarSlot,
9504
+ renderFilterPanelSection(),
9505
+ renderToolbar(),
9506
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
9507
+ listHeaderSlot,
9508
+ /* @__PURE__ */ jsxRuntime.jsx(
9509
+ EntityListPanel,
9510
+ {
9511
+ config,
9512
+ data,
9513
+ isLoading,
9514
+ onRowClick: handleRowClick,
9515
+ onAction: handleAction,
9516
+ enableSelection: enableBulkActions,
9517
+ enableBulkActions,
9518
+ enableExport,
9519
+ enableRefresh: !!onRefresh,
9520
+ showSearch: enableSearch,
9521
+ showPagination: true,
9522
+ pageSize,
9523
+ renderEmptyState,
9524
+ onExport,
9525
+ onRefresh
9526
+ }
9527
+ ),
9528
+ listFooterSlot
9529
+ ] }),
9530
+ renderCreateModal(),
9531
+ renderEditModal(),
9532
+ renderDetailModal(),
9533
+ footerSlot
9534
+ ]
9535
+ }
9536
+ ) });
9537
+ };
9538
+ const financialConfig = {
9539
+ entityType: "transactional",
9540
+ display: {
9541
+ title: "Financial Dashboard",
9542
+ description: "Personal finance overview and transaction management",
9543
+ category: 2
9544
+ // Green theme for financial success
9545
+ },
9546
+ metrics: [
9547
+ {
9548
+ key: "totalBalance",
9549
+ label: "Total Balance",
9550
+ type: "currency",
9551
+ trend: true,
9552
+ icon: lucideReact.DollarSign,
9553
+ aggregation: "sum"
9554
+ },
9555
+ {
9556
+ key: "monthlyIncome",
9557
+ label: "Monthly Income",
9558
+ type: "currency",
9559
+ trend: true,
9560
+ icon: lucideReact.TrendingUp,
9561
+ aggregation: "sum"
9562
+ },
9563
+ {
9564
+ key: "monthlyExpenses",
9565
+ label: "Monthly Expenses",
9566
+ type: "currency",
9567
+ trend: true,
9568
+ icon: lucideReact.Wallet,
9569
+ aggregation: "sum"
9570
+ },
9571
+ {
9572
+ key: "savingsRate",
9573
+ label: "Savings Rate",
9574
+ type: "percentage",
9575
+ target: 20,
9576
+ icon: lucideReact.Target
9577
+ }
9578
+ ],
9579
+ temporal: {
9580
+ cycles: ["monthly", "quarterly", "yearly"],
9581
+ defaultCycle: "monthly",
9582
+ enableComparisons: true,
9583
+ forecasting: {
9584
+ enabled: true,
9585
+ periods: 3,
9586
+ algorithm: "seasonal"
9587
+ }
9588
+ },
9589
+ categories: {
9590
+ hierarchy: ["account", "category", "type"],
9591
+ defaultGroupBy: "category",
9592
+ enableDrillDown: true,
9593
+ colorCoding: true
9594
+ },
9595
+ actions: [
9596
+ {
9597
+ label: "Add Transaction",
9598
+ type: "primary",
9599
+ onClick: ({ data, config }) => {
9600
+ console.log("Adding new transaction", { data, config });
9601
+ }
9602
+ },
9603
+ {
9604
+ label: "Generate Report",
9605
+ type: "secondary",
9606
+ onClick: ({ selectedItems, data, config }) => {
9607
+ console.log("Generating report", { selectedItems, data, config });
9608
+ }
9609
+ }
9610
+ ]
9611
+ };
9612
+ const sampleFinancialData = [
9613
+ {
9614
+ id: "1",
9615
+ amount: 5e3,
9616
+ category: "Salary",
9617
+ account: "Checking",
9618
+ date: "2024-01-15",
9619
+ description: "Monthly salary",
9620
+ type: "income",
9621
+ status: "completed"
9622
+ },
9623
+ {
9624
+ id: "2",
9625
+ amount: -1200,
9626
+ category: "Rent",
9627
+ account: "Checking",
9628
+ date: "2024-01-01",
9629
+ description: "Monthly rent payment",
9630
+ type: "expense",
9631
+ status: "completed"
9632
+ },
9633
+ {
9634
+ id: "3",
9635
+ amount: -300,
9636
+ category: "Groceries",
9637
+ account: "Checking",
9638
+ date: "2024-01-10",
9639
+ description: "Weekly groceries",
9640
+ type: "expense",
9641
+ status: "completed"
9642
+ },
9643
+ {
9644
+ id: "4",
9645
+ amount: -80,
9646
+ category: "Utilities",
9647
+ account: "Checking",
9648
+ date: "2024-01-05",
9649
+ description: "Electric bill",
9650
+ type: "expense",
9651
+ status: "completed"
9652
+ },
9653
+ {
9654
+ id: "5",
9655
+ amount: -45,
9656
+ category: "Entertainment",
9657
+ account: "Checking",
9658
+ date: "2024-01-12",
9659
+ description: "Movie tickets",
9660
+ type: "expense",
9661
+ status: "completed"
9662
+ }
9663
+ ];
7762
9664
  function createReactApp(config) {
7763
9665
  const appConfig = typeof config === "string" ? { title: config } : config;
7764
9666
  const {
@@ -10058,6 +11960,7 @@ exports.CardDescription = CardDescription;
10058
11960
  exports.CardFooter = CardFooter;
10059
11961
  exports.CardHeader = CardHeader;
10060
11962
  exports.CardTitle = CardTitle;
11963
+ exports.CategoryBreakdownPanel = CategoryBreakdownPanel;
10061
11964
  exports.Chart = Chart;
10062
11965
  exports.ColorSwatch = ColorSwatch;
10063
11966
  exports.ComponentShowcasePage = ComponentShowcasePage;
@@ -10069,6 +11972,7 @@ exports.DarkModeToggle = DarkModeToggle;
10069
11972
  exports.DashboardCard = DashboardCard;
10070
11973
  exports.DashboardGrid = DashboardGrid;
10071
11974
  exports.DashboardTemplate = DashboardTemplate;
11975
+ exports.DashboardWithSidePanel = DashboardWithSidePanel;
10072
11976
  exports.DataBadge = DataBadge;
10073
11977
  exports.DataDetailTemplate = DataDetailTemplate;
10074
11978
  exports.DataTable = DataTable;
@@ -10091,6 +11995,10 @@ exports.DropdownMenuSubContent = DropdownMenuSubContent;
10091
11995
  exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger;
10092
11996
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
10093
11997
  exports.EmptyState = EmptyState;
11998
+ exports.EntityListPanel = EntityListPanel;
11999
+ exports.EntityManagementTemplate = EntityManagementTemplate;
12000
+ exports.EntityPerformanceDashboardTemplate = EntityPerformanceDashboardTemplate;
12001
+ exports.EntityPerformanceDashboardTemplateWithRealTime = EntityPerformanceDashboardTemplateWithRealTime;
10094
12002
  exports.ErrorBoundary = ErrorBoundary;
10095
12003
  exports.FileUpload = FileUpload;
10096
12004
  exports.FormField = FormField;
@@ -10102,6 +12010,9 @@ exports.Label = Label;
10102
12010
  exports.Loading = Loading;
10103
12011
  exports.LoginForm = LoginForm;
10104
12012
  exports.LogoutButton = LogoutButton;
12013
+ exports.MetricCalculationEngine = MetricCalculationEngine;
12014
+ exports.MetricsOverviewPanel = MetricsOverviewPanel;
12015
+ exports.MetricsOverviewWithInsightsPanel = MetricsOverviewWithInsightsPanel;
10105
12016
  exports.Modal = Modal;
10106
12017
  exports.NavMenu = NavMenu;
10107
12018
  exports.PageTemplate = PageTemplate;
@@ -10111,6 +12022,7 @@ exports.ProgressBar = ProgressBar;
10111
12022
  exports.ProtectedRoute = ProtectedRoute;
10112
12023
  exports.RESPONSIVE_CHART_HEIGHTS = RESPONSIVE_CHART_HEIGHTS;
10113
12024
  exports.ROUTES = ROUTES;
12025
+ exports.SalesPanel = SalesPanel;
10114
12026
  exports.SearchInput = SearchInput;
10115
12027
  exports.SectionHeader = SectionHeader;
10116
12028
  exports.Select = Select;
@@ -10141,6 +12053,7 @@ exports.TabsTrigger = TabsTrigger;
10141
12053
  exports.Toast = Toast;
10142
12054
  exports.ToastContainer = ToastContainer;
10143
12055
  exports.Tooltip = Tooltip;
12056
+ exports.TrendAnalysisPanel = TrendAnalysisPanel;
10144
12057
  exports.UI_CONFIG = UI_CONFIG;
10145
12058
  exports.UserAvatar = UserAvatar;
10146
12059
  exports.UserMenu = UserMenu;
@@ -10150,12 +12063,14 @@ exports.cn = cn;
10150
12063
  exports.createReactApp = createReactApp;
10151
12064
  exports.createSimpleApp = createSimpleApp;
10152
12065
  exports.env = env;
12066
+ exports.financialConfig = financialConfig;
10153
12067
  exports.formatNumberWithTooltip = formatNumberWithTooltip;
10154
12068
  exports.getAnimationClasses = getAnimationClasses;
10155
12069
  exports.getChartHeight = getChartHeight;
10156
12070
  exports.getContainerHeightClass = getContainerHeightClass;
10157
12071
  exports.interactionVariants = interactionVariants;
10158
12072
  exports.legacyPatterns = legacyPatterns;
12073
+ exports.sampleFinancialData = sampleFinancialData;
10159
12074
  exports.setGlobalAuthService = setGlobalAuthService;
10160
12075
  exports.tooltipContent = tooltipContent;
10161
12076
  exports.useApiMutation = useApiMutation;