@jmruthers/pace-core 0.6.8 → 0.6.10

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 (669) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/audit-tool/audits/02-project-structure.cjs +97 -32
  3. package/audit-tool/audits/03-architecture.cjs +145 -19
  4. package/audit-tool/audits/04-code-quality.cjs +86 -1
  5. package/audit-tool/audits/06-security-rbac.cjs +109 -11
  6. package/cursor-rules/02-project-structure.mdc +2 -26
  7. package/cursor-rules/05-styling.mdc +84 -6
  8. package/cursor-rules/06-security-rbac.mdc +124 -1
  9. package/dist/{DataTable-6RMSCQJ6.js → DataTable-SAXFG4XI.js} +11 -13
  10. package/dist/{AuthService-DmfO5rGS.d.ts → InactivityServiceProvider-DHryoh6K.d.ts} +24 -249
  11. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +7 -0
  12. package/dist/{UnifiedAuthProvider-CKvHP1MK.d.ts → UnifiedAuthProvider-CiBAl9-s.d.ts} +34 -22
  13. package/dist/{api-7P7DI652.js → api-F47QJ7FX.js} +3 -3
  14. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  15. package/dist/assets/app-icons/base_favicon.svg +85 -0
  16. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  17. package/dist/assets/app-icons/core_favicon.svg +256 -0
  18. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  19. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  20. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  21. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  22. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  23. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  24. package/dist/assets/app-icons/team_favicon.svg +67 -0
  25. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  26. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  27. package/dist/audit-Z6ZZBWLU.js +3 -0
  28. package/dist/chunk-3GWSPISD.js +61 -0
  29. package/dist/{chunk-4DDCYDQ3.js → chunk-66R6RLUZ.js} +12 -27
  30. package/dist/{chunk-FYHN4DD5.js → chunk-7YDC7LMU.js} +80 -8
  31. package/dist/{chunk-S7DKJPLT.js → chunk-BCTXBU6U.js} +22 -17
  32. package/dist/{chunk-TTRFSOKR.js → chunk-BTHN5MKC.js} +4 -4
  33. package/dist/{chunk-A3W6LW53.js → chunk-DDMPHZ3D.js} +6 -18
  34. package/dist/{chunk-MPBLMWVR.js → chunk-FBZ7U3ID.js} +140 -92
  35. package/dist/chunk-FN52B75D.js +246 -0
  36. package/dist/{chunk-5W2A3DRC.js → chunk-JJEYZ3DX.js} +5 -4
  37. package/dist/chunk-KPYQWGFQ.js +183 -0
  38. package/dist/{chunk-IUBRCBSY.js → chunk-KSNLMI7N.js} +14 -8
  39. package/dist/chunk-KYURMOQM.js +977 -0
  40. package/dist/{chunk-LX6U42O3.js → chunk-LNHFAF4X.js} +160 -58
  41. package/dist/{chunk-NKHKXPI4.js → chunk-MPY44PWB.js} +683 -627
  42. package/dist/{chunk-AHU7G2R5.js → chunk-NIU6DPQV.js} +10 -6
  43. package/dist/{chunk-HF6O3O37.js → chunk-RMLY6KB5.js} +1 -1
  44. package/dist/{chunk-6GLLNA6U.js → chunk-SACF5YSM.js} +1 -1
  45. package/dist/{chunk-EURB7QFZ.js → chunk-TFIPNIPE.js} +867 -534
  46. package/dist/{chunk-OJ4SKRSV.js → chunk-UZNAFKGW.js} +25 -5
  47. package/dist/chunk-W46INAVW.js +1216 -0
  48. package/dist/chunk-X5EAU5G7.js +793 -0
  49. package/dist/{chunk-T5CVK4R3.js → chunk-Y4PF6HIM.js} +110 -64
  50. package/dist/components.d.ts +8 -86
  51. package/dist/components.js +21 -55
  52. package/dist/{database.generated-CcnC_DRc.d.ts → database.generated-DT8JTZiP.d.ts} +12 -12
  53. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +10 -0
  55. package/dist/{event-CW5YB_2p.d.ts → event-WTAQuGcq.d.ts} +1 -1
  56. package/dist/{functions-lBy5L2ry.d.ts → functions-DH45k8ec.d.ts} +1 -1
  57. package/dist/hooks.d.ts +12 -11
  58. package/dist/hooks.js +69 -44
  59. package/dist/index.d.ts +380 -32
  60. package/dist/index.js +46 -32
  61. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  62. package/dist/providers.d.ts +28 -14
  63. package/dist/providers.js +5 -5
  64. package/dist/rbac/eslint-rules.js +2 -2
  65. package/dist/rbac/index.d.ts +58 -214
  66. package/dist/rbac/index.js +11 -11
  67. package/dist/theming/runtime.d.ts +9 -3
  68. package/dist/theming/runtime.js +2 -2
  69. package/dist/{timezone-BZe_eUxx.d.ts → timezone-K-ptz3HO.d.ts} +22 -23
  70. package/dist/{types-t9H8qKRw.d.ts → types-BE2sEHKd.d.ts} +1 -1
  71. package/dist/{types-BeoeWV5I.d.ts → types-CvOPXWWZ.d.ts} +6 -5
  72. package/dist/{types-DXstZpNI.d.ts → types-D05dCGma.d.ts} +56 -149
  73. package/dist/types-Dr8sNhER.d.ts +50 -0
  74. package/dist/types.d.ts +5 -5
  75. package/dist/{PublicPageProvider-CIGSujI2.d.ts → usePublicPageContext-vxBlEHO9.d.ts} +294 -151
  76. package/dist/{usePublicRouteParams-MamNgwqe.d.ts → usePublicRouteParams-G3Ks53mk.d.ts} +8 -7
  77. package/dist/utils.d.ts +301 -137
  78. package/dist/utils.js +42 -41
  79. package/dist/{validation-643vUDZW.d.ts → validation-g5n0hDkh.d.ts} +2 -2
  80. package/docs/api/modules.md +542 -549
  81. package/docs/api-reference/components.md +5 -5
  82. package/docs/api-reference/rpc-functions.md +3 -3
  83. package/docs/implementation-guides/data-tables.md +256 -8
  84. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  85. package/docs/standards/2-project-structure-standards.md +12 -74
  86. package/docs/standards/6-security-rbac-standards.md +222 -7
  87. package/docs/standards/7-api-tech-stack-standards.md +91 -3
  88. package/docs/testing/README.md +10 -0
  89. package/docs/testing/test-setup-for-consumers.md +914 -0
  90. package/eslint-config-pace-core.cjs +4 -0
  91. package/package.json +1 -1
  92. package/scripts/eslint-audit.cjs +110 -11
  93. package/src/__mocks__/lucide-react.ts +0 -2
  94. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -2
  95. package/src/__tests__/index.test.ts +532 -0
  96. package/src/__tests__/integration/UserProfile.test.tsx +1 -1
  97. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -8
  98. package/src/__tests__/rls-policies.test.ts +3 -2
  99. package/src/assets/app-icons/admin_favicon.svg +462 -0
  100. package/src/assets/app-icons/base_favicon.svg +85 -0
  101. package/src/assets/app-icons/cake_favicon.svg +68 -0
  102. package/src/assets/app-icons/core_favicon.svg +256 -0
  103. package/src/assets/app-icons/gear_favicon.svg +91 -0
  104. package/src/assets/app-icons/index.ts +83 -0
  105. package/src/assets/app-icons/medi_favicon.svg +92 -0
  106. package/src/assets/app-icons/mint_favicon.svg +83 -0
  107. package/src/assets/app-icons/pace_favicon.svg +49 -0
  108. package/src/assets/app-icons/pump_favicon.svg +68 -0
  109. package/src/assets/app-icons/seed_favicon.svg +91 -0
  110. package/src/assets/app-icons/team_favicon.svg +67 -0
  111. package/src/assets/app-icons/trac_favicon.svg +112 -0
  112. package/src/assets/app-icons/trip_favicon.svg +102 -0
  113. package/src/components/AddressField/AddressField.test.tsx +378 -3
  114. package/src/components/AddressField/AddressField.tsx +2 -2
  115. package/src/components/AddressField/types.ts +2 -2
  116. package/src/components/Alert/Alert.test.tsx +35 -25
  117. package/src/components/Alert/Alert.tsx +8 -8
  118. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  119. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  120. package/src/components/Avatar/Avatar.test.tsx +11 -1
  121. package/src/components/Avatar/Avatar.tsx +3 -2
  122. package/src/components/Badge/Badge.test.tsx +11 -1
  123. package/src/components/Button/Button.test.tsx +13 -3
  124. package/src/components/Calendar/Calendar.test.tsx +523 -131
  125. package/src/components/Calendar/Calendar.tsx +107 -488
  126. package/src/components/Card/Card.test.tsx +220 -249
  127. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  128. package/src/components/ContextSelector/ContextSelector.tsx +3 -3
  129. package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +360 -0
  130. package/src/components/DataTable/DataTable.tsx +2 -2
  131. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -1
  132. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +2 -2
  133. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +1 -1
  134. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +485 -0
  135. package/src/components/DataTable/__tests__/DataTable.test.tsx +2 -2
  136. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +1 -1
  137. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +76 -580
  138. package/src/components/DataTable/__tests__/README.md +1 -1
  139. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +1 -1
  140. package/src/components/DataTable/__tests__/keyboard.test.tsx +1 -1
  141. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +1 -3
  142. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -6
  143. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +14 -6
  144. package/src/components/DataTable/components/ActionButtons.tsx +9 -4
  145. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +3 -3
  146. package/src/components/DataTable/components/ColumnFilter.tsx +2 -7
  147. package/src/components/DataTable/components/DataTableCore.tsx +44 -52
  148. package/src/components/DataTable/components/DataTableLayout.tsx +37 -26
  149. package/src/components/DataTable/components/DataTableModals.tsx +118 -30
  150. package/src/components/DataTable/components/DataTableToolbar.tsx +2 -2
  151. package/src/components/DataTable/components/EditFields.tsx +6 -47
  152. package/src/components/DataTable/components/EditableRow.tsx +8 -8
  153. package/src/components/DataTable/components/EmptyState.tsx +6 -3
  154. package/src/components/DataTable/components/FilterRow.tsx +18 -11
  155. package/src/components/DataTable/components/GroupingDropdown.tsx +0 -1
  156. package/src/components/DataTable/components/ImportModal.tsx +305 -133
  157. package/src/components/DataTable/components/LoadingState.tsx +2 -2
  158. package/src/components/DataTable/components/PaginationControls.tsx +0 -4
  159. package/src/components/DataTable/components/RowComponent.tsx +42 -22
  160. package/src/components/DataTable/components/UnifiedTableBody.tsx +52 -12
  161. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +51 -463
  162. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +122 -116
  163. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +40 -68
  164. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +9 -137
  165. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +57 -17
  166. package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +792 -0
  167. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +24 -65
  168. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +467 -0
  169. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +8 -125
  170. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +528 -56
  171. package/src/components/DataTable/components/__tests__/EditFields.test.tsx +526 -0
  172. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +1 -68
  173. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +8 -25
  174. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +3 -62
  175. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +9 -14
  176. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +50 -186
  177. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +39 -97
  178. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +13 -103
  179. package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +629 -0
  180. package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +135 -0
  181. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +31 -171
  182. package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +453 -0
  183. package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +184 -0
  184. package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +381 -0
  185. package/src/components/DataTable/context/DataTableContext.tsx +9 -10
  186. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +12 -26
  187. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  188. package/src/components/DataTable/core/ColumnManager.ts +0 -1
  189. package/src/components/DataTable/core/DataManager.ts +4 -2
  190. package/src/components/DataTable/core/LocalDataAdapter.ts +1 -1
  191. package/src/components/DataTable/core/PluginRegistry.ts +2 -2
  192. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +114 -2
  193. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +103 -5
  194. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +57 -0
  195. package/src/components/DataTable/core/__tests__/DataManager.test.ts +63 -0
  196. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +42 -9
  197. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +29 -7
  198. package/src/components/DataTable/core/__tests__/StateManager.test.ts +58 -4
  199. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +16 -21
  200. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +93 -4
  201. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +227 -54
  202. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +215 -62
  203. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +217 -39
  204. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +101 -6
  205. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +157 -27
  206. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +80 -0
  207. package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +787 -0
  208. package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +258 -0
  209. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +298 -23
  210. package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +440 -0
  211. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  212. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  213. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +1 -1
  214. package/src/components/DataTable/hooks/useDataTablePermissions.ts +11 -22
  215. package/src/components/DataTable/hooks/useDataTableState.ts +20 -24
  216. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +5 -5
  217. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +13 -1
  218. package/src/components/DataTable/hooks/useTableColumns.ts +36 -38
  219. package/src/components/DataTable/hooks/useTableHandlers.ts +8 -20
  220. package/src/components/DataTable/index.ts +24 -2
  221. package/src/components/DataTable/types.ts +6 -3
  222. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +3 -67
  223. package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +288 -0
  224. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +3 -60
  225. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +1 -1
  226. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +9 -21
  227. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +102 -86
  228. package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +593 -0
  229. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +33 -49
  230. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +208 -0
  231. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  232. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  233. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  234. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  235. package/src/components/DataTable/utils/flexibleImport.ts +2 -2
  236. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  237. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  238. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  239. package/src/components/DataTable/utils/selectFieldUtils.ts +127 -0
  240. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +17 -24
  241. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  242. package/src/components/DateTimeField/DateTimeField.test.tsx +2 -15
  243. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  244. package/src/components/Dialog/Dialog.test.tsx +2007 -407
  245. package/src/components/Dialog/Dialog.tsx +97 -192
  246. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  247. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  248. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  249. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  250. package/src/components/ErrorBoundary/index.ts +3 -4
  251. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  252. package/src/components/FileDisplay/FileDisplay.test.tsx +454 -222
  253. package/src/components/FileDisplay/FileDisplay.tsx +14 -12
  254. package/src/components/FileDisplay/index.tsx +1 -1
  255. package/src/components/FileUpload/FileUpload.test.tsx +54 -18
  256. package/src/components/FileUpload/FileUpload.tsx +10 -7
  257. package/src/components/FileUpload/index.tsx +1 -1
  258. package/src/components/Footer/Footer.test.tsx +33 -114
  259. package/src/components/Form/Form.test.tsx +388 -68
  260. package/src/components/Form/Form.tsx +57 -42
  261. package/src/components/Header/Header.test.tsx +645 -154
  262. package/src/components/Header/Header.tsx +52 -43
  263. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  264. package/src/components/Input/Input.test.tsx +34 -120
  265. package/src/components/Label/Label.test.tsx +47 -46
  266. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +9 -12
  267. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  268. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1399 -82
  269. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  270. package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +1934 -0
  271. package/src/components/NavigationMenu/useNavigationFiltering.ts +5 -15
  272. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1307 -0
  273. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +47 -46
  274. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  275. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +87 -66
  276. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +245 -39
  277. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -20
  278. package/src/components/PaceAppLayout/README.md +0 -9
  279. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  280. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +759 -3
  281. package/src/components/PaceLoginPage/PaceLoginPage.tsx +2 -3
  282. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  283. package/src/components/Progress/Progress.test.tsx +127 -1
  284. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  285. package/src/components/ProtectedRoute/ProtectedRoute.tsx +24 -6
  286. package/src/components/PublicLayout/PublicLayout.test.tsx +1435 -14
  287. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  288. package/src/components/PublicLayout/PublicPageLayout.tsx +6 -6
  289. package/src/components/PublicLayout/PublicPageProvider.tsx +2 -41
  290. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  291. package/src/components/Select/Select.test.tsx +46 -9
  292. package/src/components/Select/Select.tsx +31 -24
  293. package/src/components/Select/__tests__/context.test.tsx +56 -0
  294. package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +279 -0
  295. package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +295 -0
  296. package/src/components/Select/hooks/__tests__/useSelectState.test.ts +254 -0
  297. package/src/components/Select/hooks/useSelectState.ts +16 -16
  298. package/src/components/Select/types.ts +3 -0
  299. package/src/components/Select/utils/__tests__/text.test.tsx +104 -0
  300. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  301. package/src/components/Switch/Switch.test.tsx +57 -153
  302. package/src/components/Table/Table.test.tsx +47 -317
  303. package/src/components/Tabs/Tabs.tsx +3 -3
  304. package/src/components/Textarea/Textarea.test.tsx +11 -38
  305. package/src/components/Toast/Toast.test.tsx +78 -569
  306. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  307. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  308. package/src/components/UserMenu/UserMenu.tsx +3 -6
  309. package/src/components/__tests__/index.test.ts +346 -0
  310. package/src/components/index.ts +12 -1
  311. package/src/constants/__tests__/performance.test.ts +91 -0
  312. package/src/hooks/__tests__/ServiceHooks.test.tsx +239 -129
  313. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -3
  314. package/src/hooks/__tests__/useApiFetch.unit.test.ts +1 -1
  315. package/src/hooks/__tests__/useAppConfig.unit.test.ts +88 -29
  316. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +282 -98
  317. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +53 -109
  318. package/src/hooks/__tests__/useDataTableState.test.ts +143 -49
  319. package/src/hooks/__tests__/useDebounce.unit.test.ts +94 -19
  320. package/src/hooks/__tests__/useEvents.unit.test.ts +100 -125
  321. package/src/hooks/__tests__/useFileDisplay.test.ts +540 -0
  322. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +1 -4
  323. package/src/hooks/__tests__/useFileUrl.unit.test.ts +27 -247
  324. package/src/hooks/__tests__/useFileUrlCache.test.ts +246 -56
  325. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +442 -68
  326. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +345 -560
  327. package/src/hooks/__tests__/useFormDialog.test.ts +51 -222
  328. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +1 -1
  329. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +1 -4
  330. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -1
  331. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +1 -1
  332. package/src/hooks/__tests__/usePermissionCache.test.ts +506 -0
  333. package/src/hooks/__tests__/usePreventTabReload.test.ts +255 -36
  334. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +17 -8
  335. package/src/hooks/__tests__/usePublicEvent.test.ts +16 -24
  336. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +12 -4
  337. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +3 -6
  338. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +1 -2
  339. package/src/hooks/__tests__/useQueryCache.test.ts +313 -66
  340. package/src/hooks/__tests__/useSessionDraft.test.ts +496 -103
  341. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +2 -2
  342. package/src/hooks/__tests__/useStorage.unit.test.ts +72 -102
  343. package/src/hooks/__tests__/useToast.test.ts +413 -0
  344. package/src/hooks/__tests__/useToast.unit.test.tsx +1 -1
  345. package/src/hooks/__tests__/useZodForm.unit.test.tsx +175 -21
  346. package/src/hooks/index.ts +13 -1
  347. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  348. package/src/hooks/public/usePublicEvent.ts +11 -11
  349. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  350. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  351. package/src/hooks/public/usePublicFileDisplay.test.ts +723 -0
  352. package/src/hooks/public/usePublicFileDisplay.ts +79 -49
  353. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  354. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  355. package/src/hooks/services/useAuthService.ts +1 -1
  356. package/src/hooks/services/useEventService.ts +1 -1
  357. package/src/hooks/useAccessibleApps.test.ts +400 -0
  358. package/src/hooks/useAccessibleApps.ts +264 -0
  359. package/src/hooks/useAddressAutocomplete.test.ts +165 -42
  360. package/src/hooks/useAddressAutocomplete.ts +41 -28
  361. package/src/hooks/useAppConfig.ts +13 -3
  362. package/src/hooks/useDataTablePerformance.ts +13 -12
  363. package/src/hooks/useDataTableState.ts +5 -5
  364. package/src/hooks/useEventTheme.test.ts +66 -17
  365. package/src/hooks/useEventTheme.ts +1 -1
  366. package/src/hooks/useEvents.ts +8 -1
  367. package/src/hooks/useFileDisplay.ts +66 -33
  368. package/src/hooks/useFileReference.test.ts +365 -87
  369. package/src/hooks/useFileReference.ts +2 -6
  370. package/src/hooks/useFileUrlCache.ts +4 -1
  371. package/src/hooks/useFormDialog.ts +2 -2
  372. package/src/hooks/useInactivityTracker.ts +3 -3
  373. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  374. package/src/hooks/useOrganisationPermissions.ts +1 -4
  375. package/src/hooks/useOrganisationSecurity.test.ts +1 -30
  376. package/src/hooks/useOrganisationSecurity.ts +3 -3
  377. package/src/hooks/useOrganisations.ts +1 -1
  378. package/src/hooks/usePerformanceMonitor.ts +1 -1
  379. package/src/hooks/usePermissionCache.ts +2 -6
  380. package/src/hooks/useQueryCache.ts +7 -7
  381. package/src/hooks/useSessionDraft.ts +14 -11
  382. package/src/hooks/useSessionRestoration.ts +1 -1
  383. package/src/hooks/useStorage.ts +75 -40
  384. package/src/hooks/useToast.ts +2 -2
  385. package/src/hooks/useZodForm.ts +3 -3
  386. package/src/icons/__tests__/index.test.ts +133 -0
  387. package/src/icons/index.ts +1 -1
  388. package/src/index.ts +43 -4
  389. package/src/providers/OrganisationProvider.test.tsx +40 -0
  390. package/src/providers/OrganisationProvider.tsx +5 -5
  391. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  392. package/src/providers/__tests__/AuthProvider.test.tsx +22 -91
  393. package/src/providers/__tests__/EventProvider.test.tsx +16 -80
  394. package/src/providers/__tests__/InactivityProvider.test.tsx +29 -173
  395. package/src/providers/__tests__/OrganisationProvider.test.tsx +4 -5
  396. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +591 -0
  397. package/src/providers/__tests__/ProviderLifecycle.test.tsx +80 -196
  398. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +40 -133
  399. package/src/providers/__tests__/index.test.ts +138 -0
  400. package/src/providers/services/AuthServiceContext.ts +27 -0
  401. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  402. package/src/providers/services/EventServiceContext.ts +25 -0
  403. package/src/providers/services/EventServiceProvider.tsx +11 -20
  404. package/src/providers/services/InactivityServiceContext.ts +25 -0
  405. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  406. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  407. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  408. package/src/providers/services/UnifiedAuthContext.ts +99 -0
  409. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  410. package/src/providers/services/UnifiedAuthProvider.tsx +38 -143
  411. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +61 -95
  412. package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +638 -0
  413. package/src/providers/services/__tests__/EventServiceProvider.test.tsx +839 -0
  414. package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +662 -0
  415. package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +440 -0
  416. package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +435 -0
  417. package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +408 -0
  418. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +55 -48
  419. package/src/providers/services/__tests__/contexts.test.tsx +281 -0
  420. package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +251 -0
  421. package/src/providers/services/useUnifiedAuth.ts +29 -0
  422. package/src/rbac/README.md +5 -5
  423. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +9 -14
  424. package/src/rbac/__tests__/audit-batched.test.ts +550 -0
  425. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +1 -14
  426. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +43 -12
  427. package/src/rbac/__tests__/cache-invalidation.test.ts +8 -14
  428. package/src/rbac/__tests__/engine.comprehensive.test.ts +2 -7
  429. package/src/rbac/__tests__/index.test.ts +107 -0
  430. package/src/rbac/__tests__/performance.test.ts +451 -0
  431. package/src/rbac/__tests__/rbac-core.test.tsx +2 -2
  432. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -5
  433. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +1 -7
  434. package/src/rbac/__tests__/rbac-functions.test.ts +0 -1
  435. package/src/rbac/__tests__/rbac-integration.test.ts +0 -1
  436. package/src/rbac/__tests__/scenarios.user-role.test.tsx +21 -32
  437. package/src/rbac/adapters.test.tsx +654 -0
  438. package/src/rbac/adapters.tsx +24 -9
  439. package/src/rbac/api.test.ts +13 -217
  440. package/src/rbac/api.ts +85 -16
  441. package/src/rbac/audit-batched.ts +5 -4
  442. package/src/rbac/audit.test.ts +225 -28
  443. package/src/rbac/audit.ts +22 -17
  444. package/src/rbac/cache-invalidation.ts +18 -15
  445. package/src/rbac/cache.test.ts +123 -63
  446. package/src/rbac/cache.ts +3 -4
  447. package/src/rbac/components/AccessDenied.tsx +20 -18
  448. package/src/rbac/components/NavigationGuard.tsx +10 -8
  449. package/src/rbac/components/PagePermissionGuard.tsx +27 -25
  450. package/src/rbac/components/__tests__/AccessDenied.test.tsx +324 -0
  451. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +242 -71
  452. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +20 -37
  453. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +18 -17
  454. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +452 -129
  455. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -13
  456. package/src/rbac/config.test.ts +131 -48
  457. package/src/rbac/config.ts +11 -8
  458. package/src/rbac/docs/event-based-apps.md +26 -13
  459. package/src/rbac/engine.test.ts +496 -146
  460. package/src/rbac/engine.ts +53 -13
  461. package/src/rbac/errors.test.ts +99 -87
  462. package/src/rbac/eslint-rules.js +2 -2
  463. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -5
  464. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +601 -1
  465. package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +622 -0
  466. package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +798 -0
  467. package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +843 -0
  468. package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +545 -0
  469. package/src/rbac/hooks/permissions/useAccessLevel.ts +7 -8
  470. package/src/rbac/hooks/permissions/useCan.ts +12 -10
  471. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +57 -8
  472. package/src/rbac/hooks/permissions/usePermissions.ts +15 -14
  473. package/src/rbac/hooks/useCan.test.ts +319 -3
  474. package/src/rbac/hooks/usePermissions.test.ts +426 -0
  475. package/src/rbac/hooks/usePermissions.ts +5 -7
  476. package/src/rbac/hooks/useRBAC.test.ts +1669 -2
  477. package/src/rbac/hooks/useRBAC.ts +7 -11
  478. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  479. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  480. package/src/rbac/hooks/useResourcePermissions.test.ts +538 -1
  481. package/src/rbac/hooks/useResourcePermissions.ts +9 -7
  482. package/src/rbac/hooks/useRoleManagement.test.ts +659 -1
  483. package/src/rbac/hooks/useRoleManagement.ts +16 -12
  484. package/src/rbac/hooks/useSecureSupabase.ts +11 -12
  485. package/src/rbac/index.ts +32 -32
  486. package/src/rbac/permissions.test.ts +149 -68
  487. package/src/rbac/permissions.ts +0 -3
  488. package/src/rbac/request-deduplication.test.ts +347 -0
  489. package/src/rbac/secureClient.test.ts +112 -159
  490. package/src/rbac/secureClient.ts +46 -26
  491. package/src/rbac/security.test.ts +125 -44
  492. package/src/rbac/security.ts +7 -6
  493. package/src/rbac/types.test.ts +236 -0
  494. package/src/rbac/types.ts +7 -5
  495. package/src/rbac/utils/__tests__/clientSecurity.test.ts +192 -0
  496. package/src/rbac/utils/__tests__/contextValidator.test.ts +1 -3
  497. package/src/rbac/utils/__tests__/deep-equal.test.ts +23 -0
  498. package/src/rbac/utils/__tests__/eventContext.test.ts +10 -57
  499. package/src/rbac/utils/clientSecurity.ts +6 -4
  500. package/src/rbac/utils/contextValidator.ts +1 -2
  501. package/src/rbac/utils/eventContext.ts +2 -2
  502. package/src/services/AuthService.ts +13 -11
  503. package/src/services/EventService.ts +4 -5
  504. package/src/services/OrganisationService.ts +13 -30
  505. package/src/services/__tests__/AuthService.edge-cases.test.ts +746 -0
  506. package/src/services/__tests__/AuthService.restoreSession.test.ts +23 -3
  507. package/src/services/__tests__/AuthService.test.ts +4 -8
  508. package/src/services/__tests__/BaseService.edge-cases.test.ts +506 -0
  509. package/src/services/__tests__/BaseService.test.ts +49 -0
  510. package/src/services/__tests__/EventService.edge-cases.test.ts +633 -0
  511. package/src/services/__tests__/EventService.eventColours.test.ts +0 -12
  512. package/src/services/__tests__/EventService.test.ts +0 -7
  513. package/src/services/__tests__/InactivityService.edge-cases.test.ts +492 -0
  514. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -5
  515. package/src/services/__tests__/OrganisationService.edge-cases.test.ts +633 -0
  516. package/src/services/base/BaseService.test.ts +214 -0
  517. package/src/services/interfaces/IOrganisationService.ts +0 -1
  518. package/src/services/interfaces/__tests__/IAuthService.test.ts +190 -0
  519. package/src/services/interfaces/__tests__/IEventService.test.ts +176 -0
  520. package/src/services/interfaces/__tests__/IInactivityService.test.ts +183 -0
  521. package/src/services/interfaces/__tests__/IOrganisationService.test.ts +207 -0
  522. package/src/styles/core.css +1 -0
  523. package/src/theming/__tests__/runtime.test.ts +29 -94
  524. package/src/theming/parseEventColours.ts +18 -9
  525. package/src/theming/runtime.ts +1 -5
  526. package/src/types/__tests__/core.test.ts +397 -0
  527. package/src/types/__tests__/database-generated.test.ts +78 -0
  528. package/src/types/__tests__/file-reference.test.ts +270 -366
  529. package/src/types/__tests__/guards.test.ts +26 -26
  530. package/src/types/__tests__/index.test.ts +265 -0
  531. package/src/types/__tests__/type-validation.test.ts +3 -3
  532. package/src/types/__tests__/validation.test.ts +0 -2
  533. package/src/types/auth.ts +0 -1
  534. package/src/types/database.generated.ts +9 -9
  535. package/src/types/event.ts +1 -1
  536. package/src/types/rpc-responses.ts +33 -0
  537. package/src/types/supabase.ts +1 -2
  538. package/src/types/vitest-globals.d.ts +1 -1
  539. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +64 -77
  540. package/src/utils/__tests__/dynamicUtils.unit.test.ts +13 -0
  541. package/src/utils/__tests__/formatDate.unit.test.ts +1 -1
  542. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -1
  543. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  544. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -2
  545. package/src/utils/__tests__/performanceBudgets.unit.test.ts +48 -13
  546. package/src/utils/__tests__/request-deduplication.test.ts +349 -0
  547. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -1
  548. package/src/utils/__tests__/timezone.test.ts +1 -1
  549. package/src/utils/__tests__/validation.unit.test.ts +1 -2
  550. package/src/utils/__tests__/validationUtils.unit.test.ts +1 -1
  551. package/src/utils/app/appConfig.test.ts +235 -0
  552. package/src/utils/app/appIdResolver.test.ts +188 -20
  553. package/src/utils/app/appNameResolver.test.ts +18 -10
  554. package/src/utils/app/appNameResolver.ts +11 -9
  555. package/src/utils/app/appPortMap.test.ts +125 -0
  556. package/src/utils/app/appPortMap.ts +51 -0
  557. package/src/utils/app/buildAppUrl.test.ts +273 -0
  558. package/src/utils/app/buildAppUrl.ts +114 -0
  559. package/src/utils/audit/audit.test.ts +354 -39
  560. package/src/utils/context/organisationContext.test.ts +10 -4
  561. package/src/utils/context/organisationContext.ts +5 -5
  562. package/src/utils/context/sessionTracking.test.ts +354 -0
  563. package/src/utils/core/__tests__/cn.test.ts +66 -0
  564. package/src/utils/core/__tests__/debugLogger.test.ts +113 -0
  565. package/src/utils/core/__tests__/logger.test.ts +217 -0
  566. package/src/utils/core/debugLogger.ts +15 -8
  567. package/src/utils/core/logger.ts +20 -16
  568. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  569. package/src/utils/device/deviceFingerprint.ts +3 -3
  570. package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +185 -0
  571. package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +156 -0
  572. package/src/utils/dynamic/createLazyComponent.tsx +38 -0
  573. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  574. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  575. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  576. package/src/utils/file-reference/__tests__/file-reference.test.ts +583 -145
  577. package/src/utils/file-reference/index.ts +0 -1
  578. package/src/utils/formatting/formatDate.test.ts +22 -148
  579. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  580. package/src/utils/formatting/formatDateTimeTimezone.test.ts +40 -84
  581. package/src/utils/formatting/formatNumber.test.ts +259 -0
  582. package/src/utils/formatting/formatTime.test.ts +36 -128
  583. package/src/utils/formatting/formatting.ts +1 -1
  584. package/src/utils/google-places/googlePlacesUtils.test.ts +72 -3
  585. package/src/utils/google-places/googlePlacesUtils.ts +15 -2
  586. package/src/utils/google-places/loadGoogleMapsScript.test.ts +58 -1
  587. package/src/utils/google-places/loadGoogleMapsScript.ts +2 -1
  588. package/src/utils/index.ts +52 -11
  589. package/src/utils/location/location.test.ts +18 -115
  590. package/src/utils/performance/__tests__/bundleAnalysis.test.ts +148 -0
  591. package/src/utils/performance/__tests__/performanceBenchmark.test.ts +251 -0
  592. package/src/utils/performance/__tests__/performanceBudgets.test.ts +241 -0
  593. package/src/utils/performance/bundleAnalysis.ts +16 -22
  594. package/src/utils/performance/performanceBenchmark.ts +12 -4
  595. package/src/utils/performance/performanceBudgets.ts +9 -6
  596. package/src/utils/permissions/__tests__/permissionTypes.test.ts +149 -0
  597. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  598. package/src/utils/persistence/__tests__/keyDerivation.test.ts +180 -9
  599. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +164 -16
  600. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  601. package/src/utils/request-deduplication.ts +6 -4
  602. package/src/utils/security/auth-utils.ts +7 -7
  603. package/src/utils/security/secureDataAccess.test.ts +22 -191
  604. package/src/utils/security/secureErrors.test.ts +163 -0
  605. package/src/utils/security/secureStorage.test.ts +156 -0
  606. package/src/utils/security/secureStorage.ts +1 -1
  607. package/src/utils/security/security.test.ts +204 -0
  608. package/src/utils/security/securityMonitor.test.ts +90 -0
  609. package/src/utils/security/securityMonitor.ts +1 -1
  610. package/src/utils/storage/__tests__/config.unit.test.ts +239 -0
  611. package/src/utils/storage/__tests__/index.unit.test.ts +64 -12
  612. package/src/utils/storage/helpers.test.ts +757 -430
  613. package/src/utils/storage/helpers.ts +1 -2
  614. package/src/utils/storage/{index.ts → storageUtils.ts} +1 -36
  615. package/src/utils/storage/types.ts +2 -2
  616. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  617. package/src/utils/supabase/createBaseClient.ts +27 -8
  618. package/src/utils/timezone/timezone.test.ts +25 -43
  619. package/src/utils/validation/__tests__/common.test.ts +115 -0
  620. package/src/utils/validation/__tests__/csrf.test.ts +65 -0
  621. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +27 -7
  622. package/src/utils/validation/__tests__/passwordSchema.test.ts +164 -0
  623. package/src/utils/validation/__tests__/schema.test.ts +127 -0
  624. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +76 -3
  625. package/src/utils/validation/__tests__/user.test.ts +173 -0
  626. package/src/utils/validation/__tests__/validation.test.ts +197 -0
  627. package/src/utils/validation/__tests__/validationUtils.test.ts +265 -43
  628. package/src/utils/validation/htmlSanitization.ts +27 -31
  629. package/src/utils/validation/schema.ts +6 -3
  630. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  631. package/src/vite-env.d.ts +6 -0
  632. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  633. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  634. package/dist/audit-MYQXYZFU.js +0 -3
  635. package/dist/chunk-7ILTDCL2.js +0 -80
  636. package/dist/chunk-EF2UGZWY.js +0 -611
  637. package/dist/chunk-FEJLJNWA.js +0 -181
  638. package/dist/chunk-GS5672WG.js +0 -2003
  639. package/dist/chunk-S6ZQKDY6.js +0 -62
  640. package/dist/chunk-Z2FNRKF3.js +0 -994
  641. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  642. package/src/components/DataTable/components/index.ts +0 -16
  643. package/src/components/DataTable/core/index.ts +0 -1
  644. package/src/components/DataTable/hooks/index.ts +0 -13
  645. package/src/components/DataTable/utils/index.ts +0 -9
  646. package/src/components/PublicLayout/index.ts +0 -32
  647. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  648. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  649. package/src/hooks/public/index.ts +0 -36
  650. package/src/hooks/usePermissionCache.test.ts +0 -536
  651. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  652. package/src/rbac/audit-enhanced.ts +0 -384
  653. package/src/rbac/compliance/database-validator.ts +0 -165
  654. package/src/rbac/compliance/index.ts +0 -48
  655. package/src/rbac/compliance/pattern-detector.ts +0 -553
  656. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  657. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  658. package/src/rbac/compliance/setup-validator.ts +0 -131
  659. package/src/rbac/components/index.ts +0 -26
  660. package/src/rbac/hooks/index.ts +0 -34
  661. package/src/rbac/hooks/permissions/index.ts +0 -4
  662. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  663. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  664. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  665. package/src/utils/google-places/index.ts +0 -26
  666. package/src/utils/location/index.ts +0 -16
  667. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  668. package/src/utils/timezone/index.ts +0 -17
  669. package/src/utils/validation/index.ts +0 -73
@@ -1,33 +1,33 @@
1
- import { AccessDenied } from './chunk-S6ZQKDY6.js';
2
- import { Input, Dialog, DialogContent, DialogHeader, DialogBody, DialogFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Alert, AlertDescription, Label, SelectLabel, SelectSeparator, DialogTitle, deriveFormKey, useSessionDraft, filterSensitiveFields, isSensitiveField, SelectGroup, AlertTitle, Progress } from './chunk-NKHKXPI4.js';
3
- import { Button, useRBAC, useResolvedScope, usePermissions, useEvents, useCan } from './chunk-GS5672WG.js';
4
- import { useAddressAutocomplete, createFileReferenceService, uploadFileWithReference, usePublicFileDisplay, useFileDisplay, getPublicUrl, getSignedUrl, generateFileUrlsBatch, useEventTheme, usePreventTabReload } from './chunk-MPBLMWVR.js';
5
- import { clearPalette } from './chunk-5W2A3DRC.js';
6
- import { useToast } from './chunk-S7DKJPLT.js';
7
- import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, useIsPublicPage, PublicPageContext, useAppConfig, ErrorBoundary } from './chunk-EF2UGZWY.js';
8
- import { useUnifiedAuth, useOrganisations, UnifiedAuthContext, EventServiceContext, useSessionRestoration } from './chunk-T5CVK4R3.js';
9
- import { EventContextRequiredError, OrganisationContextRequiredError, isSuperAdmin } from './chunk-LX6U42O3.js';
1
+ import { useRBAC, useSecureSupabase, useEvents, AccessDenied } from './chunk-X5EAU5G7.js';
2
+ import { Input, Dialog, DialogContent, DialogHeader, DialogBody, DialogFooter, Label, Select, SelectTrigger, SelectContent, SelectLabel, SelectSeparator, SelectItem, DialogTitle, SelectValue, deriveFormKey, useSessionDraft, filterSensitiveFields, isSensitiveField, SelectGroup, Progress } from './chunk-MPY44PWB.js';
3
+ import { Button, Card, CardHeader, CardTitle, CardDescription, CardContent, Alert, AlertDescription, CardFooter, useResolvedScope, usePermissions, useCan, AlertTitle } from './chunk-KYURMOQM.js';
4
+ import { useAddressAutocomplete, createFileReferenceService, uploadFileWithReference, usePublicFileDisplay, useFileDisplay, getPublicUrl, getSignedUrl, generateFileUrlsBatch, useEventTheme, usePreventTabReload } from './chunk-FBZ7U3ID.js';
5
+ import { clearPalette } from './chunk-JJEYZ3DX.js';
6
+ import { useOrganisationSecurity } from './chunk-KPYQWGFQ.js';
7
+ import { useToast } from './chunk-BCTXBU6U.js';
8
+ import { useIsPublicPage, PublicPageContext, useAppConfig } from './chunk-3GWSPISD.js';
9
+ import { useUnifiedAuth, useOrganisations, UnifiedAuthContext, EventServiceContext, useSessionRestoration } from './chunk-Y4PF6HIM.js';
10
+ import { EventContextRequiredError, OrganisationContextRequiredError, isSuperAdmin } from './chunk-LNHFAF4X.js';
10
11
  import { assertAppId } from './chunk-4SXLQIZO.js';
11
- import { getAppId } from './chunk-FEJLJNWA.js';
12
- import { LoadingSpinner } from './chunk-A3W6LW53.js';
13
- import { getCurrentAppName } from './chunk-OJ4SKRSV.js';
14
- import { cn } from './chunk-7ILTDCL2.js';
15
- import { createLogger, logger } from './chunk-TTRFSOKR.js';
16
- import * as React6 from 'react';
17
- import React6__default, { useState, useRef, useMemo, useCallback, useEffect, useContext } from 'react';
12
+ import { getUserTimeZone, getAppIcon, getAppId } from './chunk-FN52B75D.js';
13
+ import { cn, LoadingSpinner, getCurrentAppName } from './chunk-UZNAFKGW.js';
14
+ import { performanceBudgetMonitor } from './chunk-7YDC7LMU.js';
15
+ import { createLogger, logger } from './chunk-BTHN5MKC.js';
16
+ import * as React from 'react';
17
+ import React__default, { useState, useRef, useMemo, useCallback, useEffect, createContext, useContext, Component } from 'react';
18
18
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
19
- import { FileText, ExternalLink, X, ChevronDown, KeyRound, LogOut, Calendar as Calendar$1, Building2, AlertCircle, RefreshCw, File, Check } from 'lucide-react';
19
+ import { FileText, ExternalLink, X, ChevronDown, KeyRound, LogOut, Clock, Calendar as Calendar$1, Building2, AlertCircle, RefreshCw, File, Check } from 'lucide-react';
20
20
  import * as SwitchPrimitive from '@radix-ui/react-switch';
21
21
  import * as TabsPrimitive from '@radix-ui/react-tabs';
22
- import { useDayPicker, DayPicker } from 'react-day-picker';
22
+ import { DayPicker } from 'react-day-picker';
23
23
  import { enAU } from 'date-fns/locale';
24
- import { format } from 'date-fns';
25
24
  import * as ToastPrimitives from '@radix-ui/react-toast';
26
25
  import { useForm, useWatch, FormProvider, useFormContext, Controller } from 'react-hook-form';
27
26
  import { zodResolver } from '@hookform/resolvers/zod';
28
27
  import { useLocation, Link, useNavigate, Outlet, Navigate } from 'react-router-dom';
28
+ import { createClient } from '@supabase/supabase-js';
29
29
 
30
- var AddressField = React6.forwardRef(
30
+ var AddressField = React.forwardRef(
31
31
  ({
32
32
  apiKey,
33
33
  value: controlledValue,
@@ -46,14 +46,14 @@ var AddressField = React6.forwardRef(
46
46
  cacheTTL,
47
47
  ...props
48
48
  }, ref) => {
49
- const [internalValue, setInternalValue] = React6.useState(defaultValue);
50
- const [isOpen, setIsOpen] = React6.useState(false);
51
- const [selectedIndex, setSelectedIndex] = React6.useState(-1);
52
- const [inputFocused, setInputFocused] = React6.useState(false);
53
- const inputRef = React6.useRef(null);
54
- const suggestionsRef = React6.useRef(null);
55
- const containerRef = React6.useRef(null);
56
- const blurTimeoutRef = React6.useRef(null);
49
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
50
+ const [isOpen, setIsOpen] = React.useState(false);
51
+ const [selectedIndex, setSelectedIndex] = React.useState(-1);
52
+ const [inputFocused, setInputFocused] = React.useState(false);
53
+ const inputRef = React.useRef(null);
54
+ const suggestionsRef = React.useRef(null);
55
+ const containerRef = React.useRef(null);
56
+ const blurTimeoutRef = React.useRef(null);
57
57
  const value = controlledValue !== void 0 ? controlledValue : internalValue;
58
58
  const { suggestions, isLoading, error: autocompleteError, selectAddress, clearSuggestions } = useAddressAutocomplete(apiKey, value, {
59
59
  autocompleteOptions,
@@ -61,14 +61,14 @@ var AddressField = React6.forwardRef(
61
61
  cacheEnabled,
62
62
  cacheTTL
63
63
  });
64
- React6.useEffect(() => {
64
+ React.useEffect(() => {
65
65
  if (suggestions.length > 0 && inputFocused && value.trim()) {
66
66
  setIsOpen(true);
67
67
  } else if (suggestions.length === 0 || !value.trim()) {
68
68
  setIsOpen(false);
69
69
  }
70
70
  }, [suggestions, inputFocused, value]);
71
- const handleInputChange = React6.useCallback(
71
+ const handleInputChange = React.useCallback(
72
72
  (e) => {
73
73
  const newValue = e.target.value;
74
74
  if (controlledValue === void 0) {
@@ -83,7 +83,7 @@ var AddressField = React6.forwardRef(
83
83
  },
84
84
  [controlledValue, onInputChange, onChange, clearSuggestions]
85
85
  );
86
- const handleSelectAddress = React6.useCallback(
86
+ const handleSelectAddress = React.useCallback(
87
87
  async (placeId) => {
88
88
  setIsOpen(false);
89
89
  setSelectedIndex(-1);
@@ -100,7 +100,7 @@ var AddressField = React6.forwardRef(
100
100
  },
101
101
  [selectAddress, onChange, onInputChange, controlledValue]
102
102
  );
103
- const handleKeyDown = React6.useCallback(
103
+ const handleKeyDown = React.useCallback(
104
104
  (e) => {
105
105
  if (!isOpen || suggestions.length === 0) {
106
106
  if (e.key === "Escape") {
@@ -138,14 +138,14 @@ var AddressField = React6.forwardRef(
138
138
  },
139
139
  [isOpen, suggestions, selectedIndex, handleSelectAddress]
140
140
  );
141
- const handleFocus = React6.useCallback(() => {
141
+ const handleFocus = React.useCallback(() => {
142
142
  setInputFocused(true);
143
143
  if (suggestions.length > 0 && value.trim()) {
144
144
  setIsOpen(true);
145
145
  }
146
146
  }, [suggestions, value]);
147
- const handleBlur = React6.useCallback(
148
- (e) => {
147
+ const handleBlur = React.useCallback(
148
+ (_e) => {
149
149
  if (blurTimeoutRef.current) {
150
150
  clearTimeout(blurTimeoutRef.current);
151
151
  blurTimeoutRef.current = null;
@@ -165,7 +165,7 @@ var AddressField = React6.forwardRef(
165
165
  },
166
166
  []
167
167
  );
168
- React6.useEffect(() => {
168
+ React.useEffect(() => {
169
169
  return () => {
170
170
  if (blurTimeoutRef.current) {
171
171
  clearTimeout(blurTimeoutRef.current);
@@ -173,7 +173,7 @@ var AddressField = React6.forwardRef(
173
173
  }
174
174
  };
175
175
  }, []);
176
- React6.useEffect(() => {
176
+ React.useEffect(() => {
177
177
  const handleClickOutside = (event) => {
178
178
  if (containerRef.current && !containerRef.current.contains(event.target)) {
179
179
  setIsOpen(false);
@@ -187,8 +187,8 @@ var AddressField = React6.forwardRef(
187
187
  };
188
188
  }
189
189
  }, [isOpen]);
190
- const suggestionsId = React6.useId();
191
- React6.useEffect(() => {
190
+ const suggestionsId = React.useId();
191
+ React.useEffect(() => {
192
192
  if (selectedIndex >= 0) {
193
193
  const selectedItem = document.getElementById(
194
194
  `${suggestionsId}-item-${selectedIndex}`
@@ -198,7 +198,7 @@ var AddressField = React6.forwardRef(
198
198
  }
199
199
  }
200
200
  }, [selectedIndex, suggestionsId]);
201
- React6.useImperativeHandle(ref, () => inputRef.current);
201
+ React.useImperativeHandle(ref, () => inputRef.current);
202
202
  const hasError = error || !!autocompleteError;
203
203
  return /* @__PURE__ */ jsxs("form", { ref: containerRef, className: cn("relative w-full", className), children: [
204
204
  /* @__PURE__ */ jsx(
@@ -238,7 +238,7 @@ var AddressField = React6.forwardRef(
238
238
  "list-none p-0 m-0"
239
239
  ),
240
240
  "data-testid": "address-suggestions",
241
- children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsxs(React6.Fragment, { children: [
241
+ children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
242
242
  /* @__PURE__ */ jsx(
243
243
  "dt",
244
244
  {
@@ -420,7 +420,7 @@ function defaultGenerateFallbackText(fileName) {
420
420
  if (words.length === 0) return "FL";
421
421
  return words.map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
422
422
  }
423
- var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
423
+ var FileDisplayContent = React__default.memo(function FileDisplayContent2({
424
424
  isLoading,
425
425
  error,
426
426
  fileUrl,
@@ -436,7 +436,7 @@ var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
436
436
  children,
437
437
  onDelete,
438
438
  clearError,
439
- organisation_id,
439
+ organisation_id: _organisation_id,
440
440
  loadingComponent: LoadingComponent,
441
441
  errorComponent: ErrorComponent,
442
442
  showFallback = false,
@@ -495,7 +495,7 @@ var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
495
495
  await onDelete();
496
496
  }
497
497
  setImageError(false);
498
- } catch (error2) {
498
+ } catch (_error) {
499
499
  setImageError(false);
500
500
  }
501
501
  };
@@ -564,7 +564,7 @@ var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
564
564
  if (LoadingComponent) {
565
565
  return /* @__PURE__ */ jsx(LoadingComponent, {});
566
566
  }
567
- return /* @__PURE__ */ jsx("figure", { className, title: "Loading", children: /* @__PURE__ */ jsx("p", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }) });
567
+ return /* @__PURE__ */ jsx("figure", { className, title: "Loading", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }) });
568
568
  }
569
569
  if ((category || displayOnly) && fileReference) {
570
570
  const isImage = fileReference.file_metadata.fileType?.startsWith("image/");
@@ -680,7 +680,7 @@ var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
680
680
  ] })
681
681
  ] })
682
682
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
683
- /* @__PURE__ */ jsxs("p", { className: "flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200", children: [
683
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200", children: [
684
684
  /* @__PURE__ */ jsx("span", { className: "text-2xl", children: getFileIcon(fileReference.file_metadata.fileType || "") }),
685
685
  showDelete && /* @__PURE__ */ jsxs(Fragment, { children: [
686
686
  /* @__PURE__ */ jsx(
@@ -743,7 +743,7 @@ var FileDisplayContent = React6__default.memo(function FileDisplayContent2({
743
743
  fileRef.file_metadata.category
744
744
  ] })
745
745
  ] }),
746
- /* @__PURE__ */ jsxs("p", { className: "flex items-center space-x-2", children: [
746
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
747
747
  canDownload && /* @__PURE__ */ jsx(
748
748
  "a",
749
749
  {
@@ -800,8 +800,7 @@ function FileDisplayPublic({
800
800
  fileUrls,
801
801
  fileCount,
802
802
  isLoading,
803
- error,
804
- refetch
803
+ error
805
804
  } = usePublicFileDisplay(
806
805
  table_name,
807
806
  record_id,
@@ -1081,7 +1080,6 @@ function FileDisplay({
1081
1080
  }
1082
1081
  );
1083
1082
  }
1084
- createLogger("useFileReference");
1085
1083
  var urlRefreshManager = {
1086
1084
  subscriptions: /* @__PURE__ */ new Map(),
1087
1085
  subscribe(key, callback) {
@@ -1156,7 +1154,7 @@ function useFileReference(supabase) {
1156
1154
  setIsLoading(false);
1157
1155
  }
1158
1156
  }, [service]);
1159
- const getSignedUrl3 = useCallback(async (table_name, record_id, organisation_id, expires_in) => {
1157
+ const getSignedUrl2 = useCallback(async (table_name, record_id, organisation_id, expires_in) => {
1160
1158
  setIsLoading(true);
1161
1159
  setError(null);
1162
1160
  try {
@@ -1257,7 +1255,7 @@ function useFileReference(supabase) {
1257
1255
  getFileReference,
1258
1256
  getFileReferenceById,
1259
1257
  getFileUrl,
1260
- getSignedUrl: getSignedUrl3,
1258
+ getSignedUrl: getSignedUrl2,
1261
1259
  updateFileReference,
1262
1260
  deleteFileReference,
1263
1261
  listFileReferences,
@@ -1383,7 +1381,7 @@ function useFileReferenceById(supabase, fileReferenceId, organisationId) {
1383
1381
  organisationId
1384
1382
  );
1385
1383
  setFileUrl(url);
1386
- } catch (error2) {
1384
+ } catch (_error) {
1387
1385
  setFileUrl(null);
1388
1386
  }
1389
1387
  };
@@ -1443,7 +1441,7 @@ var sizeClasses = {
1443
1441
  xl: "size-16 text-xl",
1444
1442
  "2xl": "size-20 text-2xl"
1445
1443
  };
1446
- var Avatar = React6.forwardRef(
1444
+ var Avatar = React.forwardRef(
1447
1445
  ({
1448
1446
  table_name,
1449
1447
  record_id,
@@ -1457,10 +1455,10 @@ var Avatar = React6.forwardRef(
1457
1455
  size = "md",
1458
1456
  ...props
1459
1457
  }, ref) => {
1460
- const [imageError, setImageError] = React6.useState(false);
1458
+ const [imageError, setImageError] = React.useState(false);
1461
1459
  const { supabase } = useUnifiedAuth();
1462
1460
  const canFetchFileId = Boolean(fileId && organisation_id && supabase);
1463
- const { fileReference, fileUrl: fileIdUrl, isLoading: fileIdLoading } = useFileReferenceById(
1461
+ const { fileUrl: fileIdUrl, isLoading: fileIdLoading } = useFileReferenceById(
1464
1462
  supabase || {},
1465
1463
  // Hook requires SupabaseClient, but we check canFetchFileId before using result
1466
1464
  canFetchFileId ? fileId : null,
@@ -1474,10 +1472,10 @@ var Avatar = React6.forwardRef(
1474
1472
  const fallbackClasses = "size-full grid place-items-center text-center text-sec-50 bg-sec-500";
1475
1473
  const imageClasses = "object-cover size-full";
1476
1474
  const containerClasses = cn(baseClasses, className);
1477
- const handleImageError = React6.useCallback(() => {
1475
+ const handleImageError = React.useCallback(() => {
1478
1476
  setImageError(true);
1479
1477
  }, []);
1480
- React6.useEffect(() => {
1478
+ React.useEffect(() => {
1481
1479
  if (src) {
1482
1480
  setImageError(false);
1483
1481
  }
@@ -1626,7 +1624,7 @@ function Badge({ className, variant = "solid-main-normal", ref, ...props }) {
1626
1624
  );
1627
1625
  }
1628
1626
  Badge.displayName = "Badge";
1629
- var Switch = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1627
+ var Switch = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1630
1628
  SwitchPrimitive.Root,
1631
1629
  {
1632
1630
  className: cn(
@@ -1667,9 +1665,9 @@ var Switch = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
1667
1665
  }
1668
1666
  ));
1669
1667
  Switch.displayName = SwitchPrimitive.Root.displayName;
1670
- var Tabs = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.Root, { asChild: true, ...props, children: /* @__PURE__ */ jsx("section", { ref, className, children }) }));
1668
+ var Tabs = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.Root, { asChild: true, ...props, children: /* @__PURE__ */ jsx("section", { ref, className, children }) }));
1671
1669
  Tabs.displayName = TabsPrimitive.Root.displayName || "Tabs";
1672
- var TabsList = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.List, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
1670
+ var TabsList = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.List, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
1673
1671
  "nav",
1674
1672
  {
1675
1673
  ref,
@@ -1681,7 +1679,7 @@ var TabsList = React6.forwardRef(({ className, children, ...props }, ref) => /*
1681
1679
  }
1682
1680
  ) }));
1683
1681
  TabsList.displayName = TabsPrimitive.List.displayName || "TabsList";
1684
- var TabsTrigger = React6.forwardRef(({ className, variant, size, children, ...props }, ref) => {
1682
+ var TabsTrigger = React.forwardRef(({ className, variant, size = "lg", children, ...props }, ref) => {
1685
1683
  return /* @__PURE__ */ jsx(TabsPrimitive.Trigger, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
1686
1684
  Button,
1687
1685
  {
@@ -1689,9 +1687,9 @@ var TabsTrigger = React6.forwardRef(({ className, variant, size, children, ...pr
1689
1687
  variant,
1690
1688
  size,
1691
1689
  className: cn(
1692
- "rounded-b-none",
1690
+ "rounded-b-none text-lg px-4",
1693
1691
  "data-[state=active]:bg-main-50 data-[state=active]:text-main-950 data-[state=active]:border-t-1 data-[state=active]:border-x-1 data-[state=active]:shadow-md",
1694
- "data-[state=inactive]:bg-main-300 data-[state=inactive]:text-main-800 ",
1692
+ "data-[state=inactive]:bg-main-300 data-[state=inactive]:text-main-800 data-[state=inactive]:border-t-1 data-[state=inactive]:border-x-1",
1695
1693
  "data-[state=inactive]:hover:bg-acc-400",
1696
1694
  className
1697
1695
  ),
@@ -1700,7 +1698,7 @@ var TabsTrigger = React6.forwardRef(({ className, variant, size, children, ...pr
1700
1698
  ) });
1701
1699
  });
1702
1700
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName || "TabsTrigger";
1703
- var TabsContent = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.Content, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
1701
+ var TabsContent = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(TabsPrimitive.Content, { asChild: true, ...props, children: /* @__PURE__ */ jsx(
1704
1702
  "aside",
1705
1703
  {
1706
1704
  ref,
@@ -1712,41 +1710,58 @@ var TabsContent = React6.forwardRef(({ className, children, ...props }, ref) =>
1712
1710
  }
1713
1711
  ) }));
1714
1712
  TabsContent.displayName = TabsPrimitive.Content.displayName || "TabsContent";
1715
- var assignToRef = (ref, value) => {
1716
- if (!ref) {
1717
- return;
1718
- }
1719
- if (typeof ref === "function") {
1720
- ref(value);
1721
- return;
1722
- }
1723
- ref.current = value;
1724
- };
1725
- var Calendar = React6.forwardRef(
1713
+ var Calendar = React.forwardRef(
1726
1714
  ({ className, classNames, mode, components, locale, month: controlledMonth, onMonthChange: controlledOnMonthChange, onSelect, captionLayout, startMonth, endMonth, ...props }, ref) => {
1727
- const tableRef = React6.useRef(null);
1728
- const setForwardedRef = React6.useCallback(
1729
- (node) => {
1730
- tableRef.current = node;
1731
- if (!ref) {
1732
- return;
1715
+ const dayPickerRef = React.useRef(null);
1716
+ React.useEffect(() => {
1717
+ if (ref && dayPickerRef.current) {
1718
+ const tableElement = dayPickerRef.current.querySelector("table");
1719
+ if (tableElement && typeof ref === "function") {
1720
+ ref(tableElement);
1721
+ } else if (tableElement && ref && "current" in ref) {
1722
+ ref.current = tableElement;
1733
1723
  }
1734
- if (typeof ref === "function") {
1735
- ref(node);
1736
- } else {
1737
- ref.current = node;
1738
- }
1739
- },
1740
- [ref]
1741
- );
1742
- const rootPropsRef = React6.useRef(null);
1724
+ }
1725
+ }, [ref]);
1743
1726
  const selected = props.selected;
1744
1727
  const isMonthControlled = controlledMonth !== void 0;
1745
- const [internalMonth, setInternalMonth] = React6.useState(() => {
1728
+ const [internalMonth, setInternalMonth] = React.useState(() => {
1729
+ if (selected) {
1730
+ if (selected instanceof Date) {
1731
+ return new Date(selected.getFullYear(), selected.getMonth(), 1);
1732
+ }
1733
+ if (typeof selected === "object" && "from" in selected && selected.from) {
1734
+ return new Date(selected.from.getFullYear(), selected.from.getMonth(), 1);
1735
+ }
1736
+ if (Array.isArray(selected) && selected.length > 0 && selected[0] instanceof Date) {
1737
+ return new Date(selected[0].getFullYear(), selected[0].getMonth(), 1);
1738
+ }
1739
+ }
1746
1740
  const now = /* @__PURE__ */ new Date();
1747
1741
  return new Date(now.getFullYear(), now.getMonth(), 1);
1748
1742
  });
1749
- const month = React6.useMemo(() => {
1743
+ React.useEffect(() => {
1744
+ if (!isMonthControlled && selected) {
1745
+ let monthToSync = null;
1746
+ if (selected instanceof Date) {
1747
+ monthToSync = new Date(selected.getFullYear(), selected.getMonth(), 1);
1748
+ } else if (typeof selected === "object" && "from" in selected && selected.from) {
1749
+ monthToSync = new Date(selected.from.getFullYear(), selected.from.getMonth(), 1);
1750
+ } else if (Array.isArray(selected) && selected.length > 0 && selected[0] instanceof Date) {
1751
+ monthToSync = new Date(selected[0].getFullYear(), selected[0].getMonth(), 1);
1752
+ }
1753
+ if (monthToSync) {
1754
+ setInternalMonth((prevMonth) => {
1755
+ const currentMonth = new Date(prevMonth.getFullYear(), prevMonth.getMonth(), 1);
1756
+ if (monthToSync.getTime() !== currentMonth.getTime()) {
1757
+ return monthToSync;
1758
+ }
1759
+ return prevMonth;
1760
+ });
1761
+ }
1762
+ }
1763
+ }, [selected, isMonthControlled]);
1764
+ const month = React.useMemo(() => {
1750
1765
  const monthToUse = isMonthControlled ? controlledMonth : internalMonth;
1751
1766
  if (!monthToUse) {
1752
1767
  const now = /* @__PURE__ */ new Date();
@@ -1755,350 +1770,98 @@ var Calendar = React6.forwardRef(
1755
1770
  const normalized = new Date(monthToUse.getFullYear(), monthToUse.getMonth(), 1);
1756
1771
  return normalized;
1757
1772
  }, [isMonthControlled, controlledMonth, internalMonth]);
1758
- const handleMonthChange = React6.useCallback((newMonth) => {
1773
+ const handleMonthChange = React.useCallback((newMonth) => {
1759
1774
  if (!isMonthControlled) {
1760
1775
  setInternalMonth(newMonth);
1761
1776
  }
1762
1777
  controlledOnMonthChange?.(newMonth);
1763
1778
  }, [isMonthControlled, controlledOnMonthChange]);
1764
- const wrappedHandleMonthChange = React6.useCallback((newMonth) => {
1765
- handleMonthChange(newMonth);
1766
- }, [handleMonthChange]);
1767
- const CustomRoot = React6.memo(({ children, rootRef: dayPickerRootRef, ...rootProps }) => {
1768
- const {
1769
- className: rootClassName,
1770
- style: rootStyle,
1771
- children: _ignoredChildren,
1772
- ...restProps
1773
- } = rootProps;
1774
- rootPropsRef.current = {
1775
- className: rootClassName,
1776
- style: rootStyle,
1777
- rootRef: dayPickerRootRef,
1778
- restProps
1779
- };
1780
- return /* @__PURE__ */ jsx(Fragment, { children });
1781
- });
1782
- CustomRoot.displayName = "CustomRoot";
1783
- const CustomMonths = React6.memo(({ children }) => {
1784
- const childrenArray = React6.Children.toArray(children);
1785
- const filteredChildren = childrenArray.filter((child) => {
1786
- if (!React6.isValidElement(child)) return true;
1787
- const childType = child.type;
1788
- const displayName = childType?.displayName || childType?.name;
1789
- if (displayName === "MonthCaption" || displayName === "Dropdown" || displayName === "DropdownMonth" || displayName === "DropdownYear" || typeof childType === "string" && childType.includes("dropdown")) {
1790
- return false;
1791
- }
1792
- if (childType === "div") {
1793
- const childProps = child.props;
1794
- if (childProps?.children) {
1795
- const childChildren = React6.Children.toArray(childProps.children);
1796
- const hasCaptionSpan = childChildren.some((cc) => {
1797
- if (!React6.isValidElement(cc) || cc.type !== "span") return false;
1798
- const spanProps = cc.props;
1799
- return spanProps?.role === "status" && spanProps?.["aria-live"] === "polite";
1800
- });
1801
- if (hasCaptionSpan) {
1802
- return false;
1803
- }
1804
- }
1805
- }
1806
- return true;
1807
- });
1808
- return /* @__PURE__ */ jsx(Fragment, { children: filteredChildren });
1809
- });
1810
- CustomMonths.displayName = "CustomMonths";
1811
- const CustomMonthGrid = React6.forwardRef((props2, forwardedRef) => {
1812
- return /* @__PURE__ */ jsx("table", { ref: forwardedRef, ...props2 });
1813
- });
1814
- CustomMonthGrid.displayName = "CustomMonthGrid";
1815
- const CustomMonthCaption = React6.memo(({ displayMonth, startMonth: captionStartMonth, endMonth: captionEndMonth, locale: captionLocale }) => {
1816
- const { goToMonth } = useDayPicker();
1817
- const calendarLocale = captionLocale || enAU;
1818
- const fromDate = captionStartMonth || new Date(1900, 0);
1819
- const toDate = captionEndMonth || new Date(2100, 11);
1820
- const monthOptions = React6.useMemo(() => {
1821
- const months = [];
1822
- for (let i = 0; i < 12; i++) {
1823
- const monthDate = new Date(displayMonth.getFullYear(), i, 1);
1824
- const label = format(monthDate, "MMMM", { locale: calendarLocale });
1825
- months.push({ value: i.toString(), label });
1826
- }
1827
- return months;
1828
- }, [calendarLocale, displayMonth]);
1829
- const yearOptions = React6.useMemo(() => {
1830
- const years = [];
1831
- const startYear = fromDate.getFullYear();
1832
- const endYear = toDate.getFullYear();
1833
- for (let year = startYear; year <= endYear; year++) {
1834
- years.push({ value: year.toString(), label: year.toString() });
1835
- }
1836
- return years;
1837
- }, [fromDate, toDate]);
1838
- const currentMonth = displayMonth.getMonth();
1839
- const currentYear = displayMonth.getFullYear();
1840
- const handleMonthChange2 = React6.useCallback((value) => {
1841
- const newMonth = parseInt(value, 10);
1842
- const newDate = new Date(currentYear, newMonth, 1);
1843
- goToMonth(newDate);
1844
- }, [currentYear, goToMonth]);
1845
- const handleYearChange = React6.useCallback((value) => {
1846
- const newYear = parseInt(value, 10);
1847
- const newDate = new Date(newYear, currentMonth, 1);
1848
- goToMonth(newDate);
1849
- }, [currentMonth, goToMonth]);
1850
- return /* @__PURE__ */ jsxs("nav", { className: "relative flex items-center justify-center gap-2", children: [
1851
- /* @__PURE__ */ jsxs(Select, { value: currentMonth.toString(), onValueChange: handleMonthChange2, children: [
1852
- /* @__PURE__ */ jsx(SelectTrigger, { className: "w-auto min-w-[120px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1853
- /* @__PURE__ */ jsx(SelectContent, { children: monthOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
1854
- ] }),
1855
- /* @__PURE__ */ jsxs(Select, { value: currentYear.toString(), onValueChange: handleYearChange, children: [
1856
- /* @__PURE__ */ jsx(SelectTrigger, { className: "w-auto min-w-[100px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1857
- /* @__PURE__ */ jsx(SelectContent, { children: yearOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
1858
- ] })
1859
- ] });
1860
- });
1861
- CustomMonthCaption.displayName = "CustomMonthCaption";
1862
- const CustomMonth = React6.memo(({ calendarMonth, displayIndex, className: className2, children, captionLayout: monthCaptionLayout, startMonth: monthStartMonth, endMonth: monthEndMonth }) => {
1863
- const { formatters, components: components2, labels, classNames: classNames2, previousMonth, nextMonth, goToMonth } = useDayPicker();
1864
- const caption = formatters.formatCaption(calendarMonth.date, {});
1865
- const Chevron = components2?.Chevron;
1866
- const childrenArray = React6.Children.toArray(children);
1867
- const monthGridIndex = childrenArray.findIndex((child) => {
1868
- if (!React6.isValidElement(child)) return false;
1869
- const childType = child.type;
1870
- return typeof childType === "function" && childType.displayName === "MonthGrid" || child.type === "table";
1871
- });
1872
- return /* @__PURE__ */ jsx(Fragment, { children: childrenArray.map((child, index) => {
1873
- if (React6.isValidElement(child) && child.type?.displayName === "MonthCaption") {
1874
- return null;
1875
- }
1876
- if (index === monthGridIndex && React6.isValidElement(child)) {
1877
- const monthGridChild = child;
1878
- const applyRootProps = displayIndex === 0 && index === monthGridIndex;
1879
- const storedRootProps = applyRootProps ? rootPropsRef.current : null;
1880
- const { children: monthGridChildren, className: monthGridClassName, style: monthGridStyle, ...monthGridRest } = monthGridChild.props;
1881
- const mergedClassName = cn(
1882
- "w-full border-collapse rounded-md border border-sec-200 bg-background",
1883
- applyRootProps ? storedRootProps?.className : void 0,
1884
- className2,
1885
- monthGridClassName
1886
- );
1887
- const mergedStyle = {
1888
- ...applyRootProps ? storedRootProps?.style ?? {} : {},
1889
- ...monthGridStyle ?? {}
1890
- };
1891
- const tableProps = {
1892
- ...applyRootProps && storedRootProps?.restProps ? storedRootProps.restProps : {},
1893
- ...monthGridRest,
1894
- className: mergedClassName,
1895
- ...Object.keys(mergedStyle).length ? { style: mergedStyle } : {}
1896
- };
1897
- if (mode && tableProps["data-mode"] === void 0) {
1898
- tableProps["data-mode"] = mode;
1899
- }
1900
- const shouldAttachRef = applyRootProps || storedRootProps?.rootRef;
1901
- const handleTableRef = shouldAttachRef ? (node) => {
1902
- if (applyRootProps) {
1903
- setForwardedRef(node);
1904
- }
1905
- if (storedRootProps?.rootRef) {
1906
- assignToRef(storedRootProps.rootRef, node);
1907
- }
1908
- } : void 0;
1909
- const handlePreviousClick = (event) => {
1910
- event.preventDefault();
1911
- if (!previousMonth) return;
1912
- goToMonth(previousMonth);
1913
- };
1914
- const handleNextClick = (event) => {
1915
- event.preventDefault();
1916
- if (!nextMonth) return;
1917
- goToMonth(nextMonth);
1918
- };
1919
- const monthGridElement = monthGridChild;
1920
- const mergedRef = handleTableRef || monthGridElement.ref ? (node) => {
1921
- if (handleTableRef) {
1922
- handleTableRef(node);
1923
- }
1924
- assignToRef(monthGridElement.ref, node);
1925
- } : void 0;
1926
- const isDropdownLayout = monthCaptionLayout === "dropdown";
1927
- return React6.cloneElement(
1928
- monthGridElement,
1929
- {
1930
- key: child.key ?? `month-grid-${displayIndex}`,
1931
- ...tableProps,
1932
- ...mergedRef ? { ref: mergedRef } : {}
1933
- },
1934
- /* @__PURE__ */ jsxs(Fragment, { children: [
1935
- /* @__PURE__ */ jsx("caption", { className: "relative", children: isDropdownLayout ? /* @__PURE__ */ jsx(
1936
- CustomMonthCaption,
1937
- {
1938
- displayMonth: calendarMonth.date,
1939
- startMonth: monthStartMonth,
1940
- endMonth: monthEndMonth,
1941
- locale
1942
- }
1943
- ) : /* @__PURE__ */ jsxs("nav", { className: "relative flex items-center justify-center gap-1", children: [
1944
- /* @__PURE__ */ jsx(
1945
- "button",
1946
- {
1947
- type: "button",
1948
- className: cn(
1949
- "h-7 w-7 bg-transparent p-0",
1950
- "inline-flex items-center justify-center rounded-md",
1951
- "hover:bg-acc-100",
1952
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2",
1953
- "disabled:opacity-50 disabled:pointer-events-none",
1954
- classNames2?.button_previous
1955
- ),
1956
- tabIndex: previousMonth ? void 0 : -1,
1957
- "aria-disabled": previousMonth ? void 0 : true,
1958
- "aria-label": previousMonth ? labels.labelPrevious(previousMonth) : void 0,
1959
- onClick: handlePreviousClick,
1960
- disabled: !previousMonth,
1961
- children: Chevron ? /* @__PURE__ */ jsx(Chevron, { orientation: "left", className: "size-4", disabled: !previousMonth }) : /* @__PURE__ */ jsx("span", { children: "\u2039" })
1962
- }
1963
- ),
1964
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: caption }),
1965
- /* @__PURE__ */ jsx(
1966
- "button",
1967
- {
1968
- type: "button",
1969
- className: cn(
1970
- "h-7 w-7 bg-transparent p-0",
1971
- "inline-flex items-center justify-center rounded-md",
1972
- "hover:bg-acc-100",
1973
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2",
1974
- "disabled:opacity-50 disabled:pointer-events-none",
1975
- classNames2?.button_next
1976
- ),
1977
- tabIndex: nextMonth ? void 0 : -1,
1978
- "aria-disabled": nextMonth ? void 0 : true,
1979
- "aria-label": nextMonth ? labels.labelNext(nextMonth) : void 0,
1980
- onClick: handleNextClick,
1981
- disabled: !nextMonth,
1982
- children: Chevron ? /* @__PURE__ */ jsx(Chevron, { orientation: "right", className: "size-4", disabled: !nextMonth }) : /* @__PURE__ */ jsx("span", { children: "\u203A" })
1983
- }
1984
- )
1985
- ] }) }),
1986
- monthGridChildren
1987
- ] })
1988
- );
1989
- }
1990
- return React6.isValidElement(child) ? React6.cloneElement(child, { key: child.key ?? `calendar-child-${index}` }) : child;
1991
- }) });
1992
- });
1993
- CustomMonth.displayName = "CustomMonth";
1994
- const CustomWeekdays = React6.memo(({ className: className2, children, ...props2 }) => {
1995
- return /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: cn("text-xs text-sec-500", className2), ...props2, children }) });
1996
- });
1997
- CustomWeekdays.displayName = "CustomWeekdays";
1998
- const CustomMonthWithProps = React6.useCallback((props2) => {
1999
- return /* @__PURE__ */ jsx(
2000
- CustomMonth,
2001
- {
2002
- ...props2,
2003
- captionLayout,
2004
- startMonth,
2005
- endMonth
2006
- }
2007
- );
2008
- }, [captionLayout, startMonth, endMonth]);
2009
- const CustomMonthCaptionWrapper = React6.memo((_props) => {
2010
- return null;
2011
- });
2012
- CustomMonthCaptionWrapper.displayName = "CustomMonthCaptionWrapper";
2013
- const defaultComponents = React6.useMemo(() => ({
2014
- Root: CustomRoot,
2015
- Months: CustomMonths,
2016
- Month: CustomMonthWithProps,
2017
- MonthGrid: CustomMonthGrid,
2018
- // MonthCaption returns null - actual caption is rendered in CustomMonth inside <caption>
2019
- MonthCaption: CustomMonthCaptionWrapper,
2020
- Weekdays: CustomWeekdays,
2021
- // Spread user components AFTER ours so ours take precedence
2022
- ...components || {}
2023
- }), [components, CustomRoot, CustomMonths, CustomMonthWithProps, CustomMonthCaptionWrapper, CustomWeekdays]);
2024
- return /* @__PURE__ */ jsx(
2025
- DayPicker,
1779
+ const {
1780
+ captionLayout: _captionLayoutFromProps,
1781
+ startMonth: _startMonthFromProps,
1782
+ endMonth: _endMonthFromProps,
1783
+ ...restProps
1784
+ } = props;
1785
+ const dayPickerProps = {
1786
+ ...mode ? { mode } : {},
1787
+ locale: locale ?? enAU,
1788
+ // Explicitly pass captionLayout, startMonth, endMonth to ensure they're not overridden
1789
+ ...captionLayout !== void 0 ? { captionLayout } : {},
1790
+ ...startMonth !== void 0 ? { startMonth } : {},
1791
+ ...endMonth !== void 0 ? { endMonth } : {},
1792
+ ...restProps,
1793
+ ...selected !== void 0 ? { selected } : {},
1794
+ ...onSelect !== void 0 ? { onSelect } : {},
1795
+ month,
1796
+ onMonthChange: handleMonthChange,
1797
+ className,
1798
+ classNames: {
1799
+ // Basic spacing for calendar grid
1800
+ month_grid: "w-full border-collapse",
1801
+ weekdays: "text-xs text-sec-500",
1802
+ weekday: "w-9 p-0 font-normal text-center",
1803
+ week: "mt-2",
1804
+ day: "p-0 text-center",
1805
+ day_button: cn(
1806
+ "h-9 w-9 p-0 font-normal",
1807
+ "hover:bg-acc-100 hover:text-main-600",
1808
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2",
1809
+ "inline-flex items-center justify-center rounded-md"
1810
+ ),
1811
+ selected: "bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50",
1812
+ today: "bg-sec-100 text-main-600 font-semibold",
1813
+ disabled: "text-sec-400 opacity-50 cursor-not-allowed",
1814
+ // Caption and dropdown layout styling
1815
+ month_caption: "flex items-center justify-center gap-2 mb-2",
1816
+ caption_label: captionLayout === "dropdown" ? "hidden" : "text-sm font-medium",
1817
+ // Hide label when using dropdowns
1818
+ dropdowns: "flex items-center gap-2",
1819
+ months_dropdown: "px-2 py-1 text-sm border border-sec-300 rounded bg-background",
1820
+ years_dropdown: "px-2 py-1 text-sm border border-sec-300 rounded bg-background",
1821
+ chevron: "hidden",
1822
+ // Hide extra chevron icons
1823
+ ...classNames
1824
+ },
1825
+ ...components ? { components } : {}
1826
+ };
1827
+ return /* @__PURE__ */ jsx("div", { ref: dayPickerRef, children: /* @__PURE__ */ jsx(DayPicker, { ...dayPickerProps }) });
1828
+ }
1829
+ );
1830
+ Calendar.displayName = "Calendar";
1831
+ function DatePickerWithTimezone({
1832
+ selected,
1833
+ onSelect,
1834
+ onDone,
1835
+ timezone,
1836
+ className
1837
+ }) {
1838
+ const userTimezone = getUserTimeZone();
1839
+ const displayTimezone = timezone || userTimezone;
1840
+ const timezoneDisplay = displayTimezone === userTimezone ? "Local" : displayTimezone;
1841
+ return /* @__PURE__ */ jsxs("form", { className: cn("grid grid-cols-[1fr_auto] gap-2", className), children: [
1842
+ /* @__PURE__ */ jsx(
1843
+ Calendar,
2026
1844
  {
2027
- ...mode ? { mode } : {},
2028
- locale: locale ?? enAU,
2029
- hideNavigation: true,
2030
- ...props,
1845
+ mode: "single",
2031
1846
  selected,
2032
1847
  onSelect,
2033
- month,
2034
- onMonthChange: wrappedHandleMonthChange,
2035
- className,
2036
- classNames: {
2037
- // v9 API: Updated for table-based structure
2038
- months: "",
2039
- // No wrapper - removed by CustomMonths
2040
- month: "",
2041
- // No wrapper - removed by CustomMonth
2042
- month_caption: "",
2043
- // Now handled by custom component (renders as <caption>)
2044
- caption_label: "text-sm font-medium",
2045
- nav: "relative flex items-center justify-center space-x-1",
2046
- // v9: button_previous and button_next for navigation buttons
2047
- button_previous: cn(
2048
- "absolute left-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
2049
- "border border-input hover:bg-acc-100",
2050
- "inline-flex items-center justify-center rounded-md",
2051
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2"
2052
- ),
2053
- button_next: cn(
2054
- "absolute right-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
2055
- "border border-input hover:bg-acc-100",
2056
- "inline-flex items-center justify-center rounded-md",
2057
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2"
2058
- ),
2059
- // v9: table -> month_grid (now a proper <table>)
2060
- month_grid: "",
2061
- // Styles applied directly to table in CustomMonth
2062
- // v9: head_row -> weekdays (now wrapped in <thead> by custom component)
2063
- weekdays: "",
2064
- // Styles applied to <tr> inside <thead>
2065
- weekday: "text-sec-600 rounded-md w-9 font-normal text-[0.8rem]",
2066
- // v9: row -> week (now a proper <tr>)
2067
- week: "mt-2",
2068
- // v9: cell -> day (now a proper <td> by custom component)
2069
- day: "",
2070
- // Styles moved to <td> in custom component
2071
- // v9: day -> day_button (the button inside the cell)
2072
- day_button: cn(
2073
- "h-9 w-9 p-0 font-normal aria-selected:opacity-100",
2074
- "hover:bg-acc-100 hover:text-main-600",
2075
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2",
2076
- "inline-flex items-center justify-center rounded-md"
2077
- ),
2078
- // v9: day_range_end -> range_end
2079
- range_end: "range-end",
2080
- // v9: day_selected -> selected
2081
- selected: "bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50 focus:bg-main-600 focus:text-main-50",
2082
- // v9: day_today -> today
2083
- today: "bg-sec-100 text-main-600 font-semibold",
2084
- // v9: day_outside -> outside
2085
- outside: "outside text-sec-400 opacity-50 aria-selected:bg-acc-50/50 aria-selected:text-sec-400 aria-selected:opacity-30",
2086
- // v9: day_disabled -> disabled
2087
- disabled: "text-sec-400 opacity-50 cursor-not-allowed",
2088
- // v9: day_range_middle -> range_middle
2089
- range_middle: "aria-selected:bg-acc-100 aria-selected:text-main-600",
2090
- // v9: day_hidden -> hidden
2091
- hidden: "invisible",
2092
- ...classNames
2093
- },
2094
- components: defaultComponents
1848
+ initialFocus: true,
1849
+ captionLayout: "dropdown",
1850
+ startMonth: new Date(1900, 0),
1851
+ endMonth: new Date(2100, 11),
1852
+ className: "p-0 col-span-full"
2095
1853
  }
2096
- );
2097
- }
2098
- );
2099
- Calendar.displayName = "Calendar";
1854
+ ),
1855
+ /* @__PURE__ */ jsxs("label", { htmlFor: "timezone", children: [
1856
+ /* @__PURE__ */ jsx(Clock, { className: "size-4 inline-block mr-2", "aria-hidden": "true" }),
1857
+ "Timezone: ",
1858
+ /* @__PURE__ */ jsx("span", { "aria-label": `Timezone ${timezoneDisplay}`, children: timezoneDisplay })
1859
+ ] }),
1860
+ onDone && /* @__PURE__ */ jsx(Button, { onClick: onDone, size: "sm", className: "ml-auto h-8", children: "Done" })
1861
+ ] });
1862
+ }
2100
1863
  var ToastProvider = ToastPrimitives.Provider;
2101
- var ToastViewport = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1864
+ var ToastViewport = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2102
1865
  ToastPrimitives.Viewport,
2103
1866
  {
2104
1867
  ref,
@@ -2111,7 +1874,7 @@ var ToastViewport = React6.forwardRef(({ className, ...props }, ref) => /* @__PU
2111
1874
  }
2112
1875
  ));
2113
1876
  ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
2114
- var Toast = React6.forwardRef(({ className, ...props }, ref) => {
1877
+ var Toast = React.forwardRef(({ className, ...props }, ref) => {
2115
1878
  return /* @__PURE__ */ jsx(
2116
1879
  ToastPrimitives.Root,
2117
1880
  {
@@ -2126,7 +1889,7 @@ var Toast = React6.forwardRef(({ className, ...props }, ref) => {
2126
1889
  );
2127
1890
  });
2128
1891
  Toast.displayName = ToastPrimitives.Root.displayName;
2129
- var ToastAction = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1892
+ var ToastAction = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2130
1893
  ToastPrimitives.Action,
2131
1894
  {
2132
1895
  ref,
@@ -2139,7 +1902,7 @@ var ToastAction = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE
2139
1902
  }
2140
1903
  ));
2141
1904
  ToastAction.displayName = ToastPrimitives.Action.displayName;
2142
- var ToastClose = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1905
+ var ToastClose = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2143
1906
  ToastPrimitives.Close,
2144
1907
  {
2145
1908
  ref,
@@ -2154,7 +1917,7 @@ var ToastClose = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE_
2154
1917
  }
2155
1918
  ));
2156
1919
  ToastClose.displayName = ToastPrimitives.Close.displayName;
2157
- var ToastTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1920
+ var ToastTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2158
1921
  ToastPrimitives.Title,
2159
1922
  {
2160
1923
  ref,
@@ -2164,7 +1927,7 @@ var ToastTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE_
2164
1927
  }
2165
1928
  ));
2166
1929
  ToastTitle.displayName = ToastPrimitives.Title.displayName;
2167
- var ToastDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1930
+ var ToastDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2168
1931
  ToastPrimitives.Description,
2169
1932
  {
2170
1933
  ref,
@@ -2198,6 +1961,7 @@ function Form({
2198
1961
  children,
2199
1962
  className
2200
1963
  }) {
1964
+ const logger2 = createLogger("Form");
2201
1965
  const location = useLocation();
2202
1966
  const auth = useUnifiedAuth();
2203
1967
  const userId = auth.user?.id || null;
@@ -2303,7 +2067,7 @@ function Form({
2303
2067
  valuesToRestore[fieldName] = persistedValues[numericKey];
2304
2068
  }
2305
2069
  }
2306
- console.log("[Form Persistence] Mapped numeric keys to field names:", {
2070
+ logger2.debug("[Form Persistence] Mapped numeric keys to field names:", {
2307
2071
  numericKeys: persistedKeys,
2308
2072
  fieldNames,
2309
2073
  mappedValues: valuesToRestore
@@ -2321,7 +2085,7 @@ function Form({
2321
2085
  const type = fieldTypes?.[name];
2322
2086
  return isSensitiveField(name, type);
2323
2087
  });
2324
- console.log("[Form Persistence] \u2705 Restoring persisted values:", {
2088
+ logger2.debug("[Form Persistence] \u2705 Restoring persisted values:", {
2325
2089
  persistenceKey,
2326
2090
  persistedValuesKeys: persistedKeys,
2327
2091
  persistedValuesString: JSON.stringify(persistedValues),
@@ -2344,7 +2108,7 @@ function Form({
2344
2108
  }
2345
2109
  }
2346
2110
  if (hasValuesToSet) {
2347
- console.log("[Form Persistence] \u{1F504} Setting form values via reset():", {
2111
+ logger2.debug("[Form Persistence] \u{1F504} Setting form values via reset():", {
2348
2112
  persistenceKey,
2349
2113
  valuesToSetKeys: Object.keys(valuesToSet),
2350
2114
  valuesToSet,
@@ -2354,12 +2118,12 @@ function Form({
2354
2118
  ...methods.getValues(),
2355
2119
  ...valuesToSet
2356
2120
  });
2357
- console.log("[Form Persistence] \u2705 Form values set successfully", {
2121
+ logger2.debug("[Form Persistence] \u2705 Form values set successfully", {
2358
2122
  persistenceKey,
2359
2123
  currentValues: methods.getValues()
2360
2124
  });
2361
2125
  } else {
2362
- console.log("[Form Persistence] \u23ED\uFE0F No values to set (all values already match)", {
2126
+ logger2.debug("[Form Persistence] \u23ED\uFE0F No values to set (all values already match)", {
2363
2127
  persistenceKey
2364
2128
  });
2365
2129
  }
@@ -2404,7 +2168,7 @@ function Form({
2404
2168
  const type = fieldTypes?.[name];
2405
2169
  return isSensitiveField(name, type);
2406
2170
  });
2407
- console.log("[Form Persistence] \u{1F4BE} Persisting form values:", {
2171
+ logger2.debug("[Form Persistence] \u{1F4BE} Persisting form values:", {
2408
2172
  persistenceKey,
2409
2173
  filteredValuesKeys: Object.keys(filteredValues),
2410
2174
  originalValuesKeys: Object.keys(watchedValues),
@@ -2415,15 +2179,19 @@ function Form({
2415
2179
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2416
2180
  });
2417
2181
  setPersistedValues(filteredValues);
2418
- if (persistenceKey) {
2182
+ if (persistenceKey && typeof sessionStorage !== "undefined") {
2419
2183
  setTimeout(() => {
2420
- const storageKey = `pace-core:draft:${persistenceKey}`;
2421
- const stored = sessionStorage.getItem(storageKey);
2422
- console.log("[Form Persistence] \u{1F4E6} SessionStorage AFTER setPersistedValues:", {
2423
- persistenceKey,
2424
- storageKey,
2425
- stored: stored ? JSON.parse(stored) : null
2426
- });
2184
+ try {
2185
+ const storageKey = `pace-core:draft:${persistenceKey}`;
2186
+ const stored = sessionStorage.getItem(storageKey);
2187
+ logger2.debug("[Form Persistence] \u{1F4E6} SessionStorage AFTER setPersistedValues:", {
2188
+ persistenceKey,
2189
+ storageKey,
2190
+ stored: stored ? JSON.parse(stored) : null
2191
+ });
2192
+ } catch (error) {
2193
+ logger2.debug("[Form Persistence] Could not access sessionStorage after setPersistedValues", { error });
2194
+ }
2427
2195
  }, 100);
2428
2196
  }
2429
2197
  persistTimeoutRef.current = null;
@@ -2437,34 +2205,40 @@ function Form({
2437
2205
  }, [watchedValues, persistenceKey]);
2438
2206
  const handleSubmit = methods.handleSubmit(
2439
2207
  async (data) => {
2440
- console.log("[Form Lifecycle] \u{1F4E4} Form submit started", {
2208
+ logger2.debug("[Form Lifecycle] \u{1F4E4} Form submit started", {
2441
2209
  persistenceKey,
2442
2210
  dataKeys: Object.keys(data),
2443
2211
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2444
2212
  });
2445
2213
  await onSubmit(data);
2446
- console.log("[Form Lifecycle] \u2705 Form submit successful", {
2214
+ logger2.debug("[Form Lifecycle] \u2705 Form submit successful", {
2447
2215
  persistenceKey,
2448
2216
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2449
2217
  });
2450
2218
  if (persistenceKey && clearDraft) {
2451
- console.log("[Form Persistence] \u{1F5D1}\uFE0F Clearing draft after successful submit", {
2219
+ logger2.debug("[Form Persistence] \u{1F5D1}\uFE0F Clearing draft after successful submit", {
2452
2220
  persistenceKey
2453
2221
  });
2454
2222
  clearDraft();
2455
- setTimeout(() => {
2456
- const storageKey = `pace-core:draft:${persistenceKey}`;
2457
- const stored = sessionStorage.getItem(storageKey);
2458
- console.log("[Form Persistence] \u{1F4E6} SessionStorage AFTER clearDraft (submit):", {
2459
- persistenceKey,
2460
- storageKey,
2461
- stored: stored ? JSON.parse(stored) : null
2462
- });
2463
- }, 100);
2223
+ if (typeof sessionStorage !== "undefined") {
2224
+ setTimeout(() => {
2225
+ try {
2226
+ const storageKey = `pace-core:draft:${persistenceKey}`;
2227
+ const stored = sessionStorage.getItem(storageKey);
2228
+ logger2.debug("[Form Persistence] \u{1F4E6} SessionStorage AFTER clearDraft (submit):", {
2229
+ persistenceKey,
2230
+ storageKey,
2231
+ stored: stored ? JSON.parse(stored) : null
2232
+ });
2233
+ } catch (error) {
2234
+ logger2.debug("[Form Persistence] Could not access sessionStorage after clearDraft", { error });
2235
+ }
2236
+ }, 100);
2237
+ }
2464
2238
  }
2465
2239
  },
2466
2240
  (errors) => {
2467
- console.log("[Form Lifecycle] \u274C Form submit failed with errors", {
2241
+ logger2.debug("[Form Lifecycle] \u274C Form submit failed with errors", {
2468
2242
  persistenceKey,
2469
2243
  errors,
2470
2244
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -2528,7 +2302,7 @@ function FormField({
2528
2302
  )
2529
2303
  ] });
2530
2304
  }
2531
- var LoginForm = React6__default.memo(({
2305
+ var LoginForm = React__default.memo(({
2532
2306
  onSignIn,
2533
2307
  onSuccess,
2534
2308
  onError,
@@ -2629,6 +2403,363 @@ var LoginForm = React6__default.memo(({
2629
2403
  ] })
2630
2404
  ] }) });
2631
2405
  });
2406
+ function useAccessibleApps(currentAppName) {
2407
+ const supabase = useSecureSupabase();
2408
+ const authContext = useUnifiedAuth();
2409
+ const user = authContext?.user ?? null;
2410
+ const { superAdminContext } = useOrganisationSecurity();
2411
+ const isSuperAdmin2 = superAdminContext.isSuperAdmin;
2412
+ const [apps, setApps] = useState([]);
2413
+ const [loading, setLoading] = useState(true);
2414
+ const [error, setError] = useState(null);
2415
+ const fetchApps = useMemo(
2416
+ () => async () => {
2417
+ if (!supabase || !user) {
2418
+ setApps([]);
2419
+ setLoading(false);
2420
+ return;
2421
+ }
2422
+ setLoading(true);
2423
+ setError(null);
2424
+ try {
2425
+ let data = [];
2426
+ let actualIsSuperAdmin = isSuperAdmin2;
2427
+ if (user && supabase) {
2428
+ try {
2429
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2430
+ const { data: superAdminData, error: superAdminError } = await supabase.from("rbac_global_roles").select("role").eq("user_id", user.id).eq("role", "super_admin").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).limit(1);
2431
+ if (!superAdminError && superAdminData && superAdminData.length > 0) {
2432
+ actualIsSuperAdmin = true;
2433
+ } else {
2434
+ actualIsSuperAdmin = false;
2435
+ }
2436
+ } catch (checkError) {
2437
+ logger.warn("useAccessibleApps", "Error checking super admin status directly:", checkError);
2438
+ actualIsSuperAdmin = isSuperAdmin2;
2439
+ }
2440
+ }
2441
+ if (actualIsSuperAdmin) {
2442
+ const { data: allApps, error: queryError } = await supabase.from("rbac_apps").select("id, name, display_name, is_active").eq("is_active", true).order("display_name");
2443
+ if (queryError) {
2444
+ logger.error("useAccessibleApps", "Failed to fetch all apps for super admin:", queryError);
2445
+ throw new Error(`Failed to fetch all apps: ${queryError.message}`);
2446
+ }
2447
+ data = allApps || [];
2448
+ } else {
2449
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2450
+ const { data: roleData, error: queryError } = await supabase.from("rbac_event_app_roles").select(
2451
+ `
2452
+ app_id,
2453
+ rbac_apps!inner (
2454
+ id,
2455
+ name,
2456
+ display_name,
2457
+ is_active
2458
+ )
2459
+ `
2460
+ ).eq("user_id", user.id).eq("status", "active").or(`valid_to.is.null,valid_to.gt.${now}`);
2461
+ if (queryError) {
2462
+ throw new Error(`Failed to fetch accessible apps: ${queryError.message}`);
2463
+ }
2464
+ if (!roleData) {
2465
+ setApps([]);
2466
+ setLoading(false);
2467
+ return;
2468
+ }
2469
+ const appMap2 = /* @__PURE__ */ new Map();
2470
+ for (const row of roleData) {
2471
+ const appData = row.rbac_apps;
2472
+ if (!appData || !appData.is_active) {
2473
+ continue;
2474
+ }
2475
+ if (!appMap2.has(appData.id)) {
2476
+ appMap2.set(appData.id, {
2477
+ id: appData.id,
2478
+ name: appData.name,
2479
+ display_name: appData.display_name,
2480
+ is_active: appData.is_active
2481
+ });
2482
+ }
2483
+ }
2484
+ data = Array.from(appMap2.values());
2485
+ }
2486
+ const appMap = /* @__PURE__ */ new Map();
2487
+ for (const appData of data) {
2488
+ if (!appData.is_active) {
2489
+ continue;
2490
+ }
2491
+ if (currentAppName && appData.name.toUpperCase() === currentAppName.toUpperCase()) {
2492
+ continue;
2493
+ }
2494
+ if (!appMap.has(appData.id)) {
2495
+ appMap.set(appData.id, {
2496
+ id: appData.id,
2497
+ name: appData.name,
2498
+ displayName: appData.display_name
2499
+ });
2500
+ }
2501
+ }
2502
+ const appsArray = Array.from(appMap.values()).sort(
2503
+ (a, b) => a.displayName.localeCompare(b.displayName)
2504
+ );
2505
+ setApps(appsArray);
2506
+ } catch (err) {
2507
+ const error2 = err instanceof Error ? err : new Error("Unknown error fetching apps");
2508
+ setError(error2);
2509
+ setApps([]);
2510
+ } finally {
2511
+ setLoading(false);
2512
+ }
2513
+ },
2514
+ [supabase, user, currentAppName, isSuperAdmin2]
2515
+ );
2516
+ useEffect(() => {
2517
+ void fetchApps();
2518
+ }, [fetchApps]);
2519
+ return {
2520
+ apps,
2521
+ loading,
2522
+ error,
2523
+ refetch: fetchApps
2524
+ };
2525
+ }
2526
+
2527
+ // src/utils/app/appPortMap.ts
2528
+ var DEFAULT_APP_PORT_MAP = {
2529
+ "CORE": 8080,
2530
+ "ADMIN": 8081,
2531
+ "BASE": 8082,
2532
+ "CAKE": 8083,
2533
+ "GEAR": 8084,
2534
+ "MINT": 8085,
2535
+ "PORTAL": 8086,
2536
+ "PUMP": 8087,
2537
+ "TRAC": 8088
2538
+ };
2539
+ function getAppPort(appName) {
2540
+ const upperAppName = appName.toUpperCase();
2541
+ return DEFAULT_APP_PORT_MAP[upperAppName];
2542
+ }
2543
+ function getAllAppPorts() {
2544
+ return { ...DEFAULT_APP_PORT_MAP };
2545
+ }
2546
+
2547
+ // src/utils/app/buildAppUrl.ts
2548
+ function buildAppUrl(options) {
2549
+ const { appName, path = "/", port } = options;
2550
+ const isDevelopment = isDevEnvironment();
2551
+ if (isDevelopment) {
2552
+ const appPort = port || getAppPort(appName);
2553
+ if (!appPort) {
2554
+ const currentPort = window.location.port || "3000";
2555
+ return `http://localhost:${currentPort}${path}`;
2556
+ }
2557
+ return `http://localhost:${appPort}${path}`;
2558
+ } else {
2559
+ const baseDomain = getBaseDomain();
2560
+ const appSubdomain = appName.toLowerCase();
2561
+ const protocol = window.location.protocol;
2562
+ const url = `${protocol}//${appSubdomain}.${baseDomain}${path}`;
2563
+ return url;
2564
+ }
2565
+ }
2566
+ function isDevEnvironment() {
2567
+ const hostname = window.location.hostname;
2568
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
2569
+ }
2570
+ function getBaseDomain() {
2571
+ const hostname = window.location.hostname;
2572
+ const parts = hostname.split(".");
2573
+ if (parts.length > 2) {
2574
+ return parts.slice(1).join(".");
2575
+ }
2576
+ return hostname;
2577
+ }
2578
+ var APP_DISPLAY_ORDER = [
2579
+ "ADMIN",
2580
+ "PACE",
2581
+ "TEAM",
2582
+ "TRIP",
2583
+ "BASE",
2584
+ "GEAR",
2585
+ "MINT",
2586
+ "MEDI",
2587
+ "TRAC",
2588
+ "PUMP",
2589
+ "CAKE",
2590
+ "CORE"
2591
+ ];
2592
+ var getCacheKey = (userId) => {
2593
+ return `pace-core:appswitcher:apps:${userId}`;
2594
+ };
2595
+ var loadAppsFromCache = (userId) => {
2596
+ if (typeof window === "undefined" || !window.sessionStorage) {
2597
+ return null;
2598
+ }
2599
+ try {
2600
+ const cacheKey = getCacheKey(userId);
2601
+ const cached = window.sessionStorage.getItem(cacheKey);
2602
+ if (!cached) {
2603
+ return null;
2604
+ }
2605
+ const parsed = JSON.parse(cached);
2606
+ return Array.isArray(parsed) ? parsed : null;
2607
+ } catch {
2608
+ return null;
2609
+ }
2610
+ };
2611
+ var saveAppsToCache = (userId, apps) => {
2612
+ if (typeof window === "undefined" || !window.sessionStorage) {
2613
+ return;
2614
+ }
2615
+ try {
2616
+ const cacheKey = getCacheKey(userId);
2617
+ window.sessionStorage.setItem(cacheKey, JSON.stringify(apps));
2618
+ } catch {
2619
+ }
2620
+ };
2621
+ function enrichAppsWithCacheData(apps) {
2622
+ const orderMap = new Map(APP_DISPLAY_ORDER.map((name, index) => [name.toUpperCase(), index]));
2623
+ return apps.map((app) => ({
2624
+ id: app.id,
2625
+ name: app.name,
2626
+ displayName: app.displayName,
2627
+ logoUrl: getAppIcon(app.name),
2628
+ sortId: orderMap.get(app.name.toUpperCase()) ?? -1
2629
+ // -1 if not in APP_DISPLAY_ORDER
2630
+ }));
2631
+ }
2632
+ function AppSwitcher({
2633
+ currentAppName,
2634
+ trigger,
2635
+ className,
2636
+ showSwitcher = true
2637
+ }) {
2638
+ const { apps, loading, error } = useAccessibleApps(currentAppName);
2639
+ const { session, user } = useUnifiedAuth();
2640
+ const [cachedApps, setCachedApps] = React__default.useState(null);
2641
+ React__default.useEffect(() => {
2642
+ if (!user?.id) {
2643
+ setCachedApps(null);
2644
+ return;
2645
+ }
2646
+ const cached = loadAppsFromCache(user.id);
2647
+ if (cached) {
2648
+ setCachedApps(cached);
2649
+ }
2650
+ }, [user?.id]);
2651
+ React__default.useEffect(() => {
2652
+ if (!user?.id || loading || error || apps.length === 0) {
2653
+ return;
2654
+ }
2655
+ const enriched = enrichAppsWithCacheData(apps);
2656
+ saveAppsToCache(user.id, enriched);
2657
+ setCachedApps(enriched);
2658
+ }, [apps, loading, error, user?.id]);
2659
+ React__default.useEffect(() => {
2660
+ return () => {
2661
+ if (user?.id) ;
2662
+ };
2663
+ }, [user?.id]);
2664
+ const processedApps = (() => {
2665
+ if (!cachedApps) return [];
2666
+ const filtered = cachedApps.filter(
2667
+ (app) => app.name.toUpperCase() !== currentAppName.toUpperCase()
2668
+ );
2669
+ return filtered.sort((a, b) => {
2670
+ if (a.sortId >= 0 && b.sortId >= 0) return a.sortId - b.sortId;
2671
+ if (a.sortId >= 0) return -1;
2672
+ if (b.sortId >= 0) return 1;
2673
+ return a.displayName.localeCompare(b.displayName);
2674
+ });
2675
+ })();
2676
+ if (!showSwitcher || !loading && processedApps.length === 0) {
2677
+ return trigger ? /* @__PURE__ */ jsx(Fragment, { children: trigger }) : null;
2678
+ }
2679
+ const handleAppSelect = (appName) => {
2680
+ let url = buildAppUrl({ appName, path: "/" });
2681
+ if (session?.access_token && session?.refresh_token) {
2682
+ const urlObj = new URL(url);
2683
+ try {
2684
+ const sessionData = JSON.stringify({
2685
+ access_token: session.access_token,
2686
+ refresh_token: session.refresh_token,
2687
+ expires_at: session.expires_at,
2688
+ expires_in: session.expires_in,
2689
+ token_type: session.token_type,
2690
+ user: {
2691
+ id: session.user.id,
2692
+ email: session.user.email
2693
+ // Include minimal user data needed
2694
+ }
2695
+ });
2696
+ const encodedSession = btoa(sessionData);
2697
+ urlObj.searchParams.set("session", encodedSession);
2698
+ url = urlObj.toString();
2699
+ } catch (_error) {
2700
+ urlObj.searchParams.set("session_token", session.access_token);
2701
+ url = urlObj.toString();
2702
+ }
2703
+ }
2704
+ window.open(url, "_blank");
2705
+ };
2706
+ if (error) {
2707
+ return trigger ? /* @__PURE__ */ jsx(Fragment, { children: trigger }) : null;
2708
+ }
2709
+ const hasApps = processedApps.length > 0;
2710
+ const isDisabled = loading || !hasApps;
2711
+ return /* @__PURE__ */ jsxs(
2712
+ Select,
2713
+ {
2714
+ onValueChange: handleAppSelect,
2715
+ disabled: isDisabled,
2716
+ className: cn(className),
2717
+ children: [
2718
+ trigger ? /* @__PURE__ */ jsx(
2719
+ SelectTrigger,
2720
+ {
2721
+ asChild: true,
2722
+ disabled: isDisabled,
2723
+ variant: "ghost",
2724
+ showChevron: false,
2725
+ children: trigger
2726
+ }
2727
+ ) : /* @__PURE__ */ jsxs(
2728
+ SelectTrigger,
2729
+ {
2730
+ disabled: isDisabled,
2731
+ variant: "ghost",
2732
+ showChevron: false,
2733
+ className: "p-0 bg-main-500 overflow-hidden hover:bg-none",
2734
+ children: [
2735
+ /* @__PURE__ */ jsx(
2736
+ "img",
2737
+ {
2738
+ src: getAppIcon("pace"),
2739
+ alt: "PACE",
2740
+ className: "absolute inset-0 size-full object-contain hover:hue-rotate-180 hover:invert transition-all"
2741
+ }
2742
+ ),
2743
+ /* @__PURE__ */ jsx(SelectValue, { placeholder: "PACE", className: "opacity-0" })
2744
+ ]
2745
+ }
2746
+ ),
2747
+ hasApps && /* @__PURE__ */ jsx(SelectContent, { className: "grid grid-cols-[2rem_auto_auto] gap-1 auto-rows-min pt-2", children: processedApps.map((app) => /* @__PURE__ */ jsxs(SelectItem, { value: app.name, className: "col-span-3 grid grid-cols-subgrid items-center py-0", children: [
2748
+ /* @__PURE__ */ jsx(
2749
+ "img",
2750
+ {
2751
+ src: app.logoUrl,
2752
+ alt: `${app.displayName} logo`,
2753
+ className: "size-5 col-start-1"
2754
+ }
2755
+ ),
2756
+ /* @__PURE__ */ jsx("h6", { className: " uppercase col-start-2 my-0", children: app.name }),
2757
+ /* @__PURE__ */ jsx("small", { className: "col-start-3 whitespace-nowrap", children: app.displayName })
2758
+ ] }, app.id)) })
2759
+ ]
2760
+ }
2761
+ );
2762
+ }
2632
2763
  function ContextSelector({
2633
2764
  placeholder = "Select organisation or event",
2634
2765
  className,
@@ -2666,7 +2797,7 @@ function ContextSelector({
2666
2797
  return `org:${selectedOrganisation.id}`;
2667
2798
  }
2668
2799
  return "";
2669
- }, [showOrganisations, showEvents, selectedOrganisation?.id, selectedEvent]);
2800
+ }, [showOrganisations, showEvents, selectedOrganisation, selectedEvent]);
2670
2801
  const displayValue = useMemo(() => {
2671
2802
  if (showEvents && selectedEvent) {
2672
2803
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2727,7 +2858,7 @@ function ContextSelector({
2727
2858
  };
2728
2859
  if (isLoading && !hasItems) {
2729
2860
  const loadingText = compact ? "Loading..." : showOrganisations && showEvents ? "Loading organisations and events..." : showOrganisations ? "Loading organisations..." : "Loading events...";
2730
- return /* @__PURE__ */ jsxs("p", { className, children: [
2861
+ return /* @__PURE__ */ jsxs("div", { className, children: [
2731
2862
  /* @__PURE__ */ jsx(LoadingSpinner, { size: "sm" }),
2732
2863
  /* @__PURE__ */ jsx("br", {}),
2733
2864
  /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: loadingText })
@@ -2916,7 +3047,7 @@ function PasswordChangeForm({ onSubmit, onSuccess, className }) {
2916
3047
  )
2917
3048
  ] });
2918
3049
  }
2919
- var UserMenu = React6__default.memo(function UserMenu2({
3050
+ var UserMenu = React__default.memo(function UserMenu2({
2920
3051
  user,
2921
3052
  onSignOut,
2922
3053
  onChangePassword,
@@ -2961,11 +3092,11 @@ var UserMenu = React6__default.memo(function UserMenu2({
2961
3092
  /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
2962
3093
  ] }) }),
2963
3094
  /* @__PURE__ */ jsxs(SelectContent, { children: [
2964
- /* @__PURE__ */ jsx(SelectLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs("li", { className: "pt-2", children: [
3095
+ /* @__PURE__ */ jsxs(SelectLabel, { className: "font-normal pt-2", children: [
2965
3096
  userInfo.displayName,
2966
3097
  /* @__PURE__ */ jsx("br", {}),
2967
3098
  /* @__PURE__ */ jsx("small", { children: userInfo.email })
2968
- ] }) }),
3099
+ ] }),
2969
3100
  /* @__PURE__ */ jsx(SelectSeparator, {}),
2970
3101
  /* @__PURE__ */ jsxs(
2971
3102
  SelectItem,
@@ -2998,7 +3129,7 @@ var UserMenu = React6__default.memo(function UserMenu2({
2998
3129
  ] }) })
2999
3130
  ] });
3000
3131
  });
3001
- var UserMenuLoading = React6__default.memo(function UserMenuLoading2() {
3132
+ var UserMenuLoading = React__default.memo(function UserMenuLoading2() {
3002
3133
  return /* @__PURE__ */ jsxs(
3003
3134
  Button,
3004
3135
  {
@@ -3019,10 +3150,10 @@ UserMenu.Loading = UserMenuLoading;
3019
3150
  function useNavigationFiltering({
3020
3151
  items,
3021
3152
  itemsPreFiltered = false,
3022
- auditLog = true
3153
+ auditLog: _auditLog = true
3023
3154
  }) {
3024
- const [resolvedAppId, setResolvedAppId] = React6.useState(void 0);
3025
- const previousFilteredItemsRef = React6.useRef([]);
3155
+ const [resolvedAppId, setResolvedAppId] = React.useState(void 0);
3156
+ const previousFilteredItemsRef = React.useRef([]);
3026
3157
  const authContext = useUnifiedAuth();
3027
3158
  const rbacContext = useRBAC();
3028
3159
  const eventLoadingRaw = authContext?.eventLoading;
@@ -3037,14 +3168,14 @@ function useNavigationFiltering({
3037
3168
  selectedEventId: itemsPreFiltered ? null : selectedEvent?.event_id || null,
3038
3169
  selectedEventOrganisationId: itemsPreFiltered ? null : selectedEvent?.organisation_id || null
3039
3170
  });
3040
- React6.useEffect(() => {
3171
+ React.useEffect(() => {
3041
3172
  if (!scopeLoading && !resolvedScope?.appId && selectedOrganisation?.id && authContext?.appName && authContext?.user?.id && !resolvedAppId) {
3042
3173
  if (!authContext.user || !authContext.appName) {
3043
3174
  return;
3044
3175
  }
3045
3176
  const userId2 = authContext.user.id;
3046
3177
  const appName = authContext.appName;
3047
- import('./api-7P7DI652.js').then(({ resolveAppContext }) => {
3178
+ import('./api-F47QJ7FX.js').then(({ resolveAppContext }) => {
3048
3179
  resolveAppContext({
3049
3180
  userId: userId2,
3050
3181
  appName
@@ -3062,10 +3193,10 @@ function useNavigationFiltering({
3062
3193
  resolvedScope?.appId,
3063
3194
  selectedOrganisation?.id,
3064
3195
  authContext?.appName,
3065
- authContext?.user?.id,
3196
+ authContext?.user,
3066
3197
  resolvedAppId
3067
3198
  ]);
3068
- const effectiveScope = React6.useMemo(() => {
3199
+ const effectiveScope = React.useMemo(() => {
3069
3200
  if (resolvedScope?.organisationId) {
3070
3201
  return resolvedScope;
3071
3202
  }
@@ -3079,8 +3210,7 @@ function useNavigationFiltering({
3079
3210
  }
3080
3211
  return null;
3081
3212
  }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id, resolvedAppId]);
3082
- const scopeKey = effectiveScope ? `${effectiveScope.organisationId || ""}-${effectiveScope.eventId || ""}-${effectiveScope.appId || ""}` : "empty";
3083
- const stableScope = React6.useMemo(() => {
3213
+ const stableScope = React.useMemo(() => {
3084
3214
  if (effectiveScope?.organisationId) {
3085
3215
  return {
3086
3216
  organisationId: effectiveScope.organisationId,
@@ -3093,7 +3223,7 @@ function useNavigationFiltering({
3093
3223
  eventId: void 0,
3094
3224
  appId: void 0
3095
3225
  };
3096
- }, [scopeKey, effectiveScope]);
3226
+ }, [effectiveScope]);
3097
3227
  const userId = authContext?.user?.id || "";
3098
3228
  const {
3099
3229
  permissions: permissionMap,
@@ -3106,7 +3236,7 @@ function useNavigationFiltering({
3106
3236
  itemsPreFiltered ? void 0 : stableScope.eventId,
3107
3237
  itemsPreFiltered ? void 0 : stableScope.appId
3108
3238
  );
3109
- const filteredItems = React6.useMemo(() => {
3239
+ const filteredItems = React.useMemo(() => {
3110
3240
  if (itemsPreFiltered && items && items.length > 0) {
3111
3241
  const visibleItems = (items || []).filter((item) => !item.meta?.hidden);
3112
3242
  previousFilteredItemsRef.current = visibleItems;
@@ -3264,12 +3394,8 @@ function useNavigationFiltering({
3264
3394
  scopeLoading,
3265
3395
  scopeError,
3266
3396
  permissionsLoading,
3267
- resolvedScope,
3268
- effectiveScope,
3269
- auditLog,
3270
3397
  eventLoadingRaw,
3271
3398
  eventLoading,
3272
- selectedEvent,
3273
3399
  orgContextReady,
3274
3400
  selectedOrganisation?.id,
3275
3401
  permissionsError,
@@ -3285,7 +3411,7 @@ function useNavigationFiltering({
3285
3411
  hasAnyPermission: hasAnyPermission || null
3286
3412
  };
3287
3413
  }
3288
- var NavigationMenu = React6.forwardRef(({
3414
+ var NavigationMenu = React.forwardRef(({
3289
3415
  items,
3290
3416
  mode = "dropdown",
3291
3417
  currentPath,
@@ -3293,7 +3419,7 @@ var NavigationMenu = React6.forwardRef(({
3293
3419
  className,
3294
3420
  disabled = false,
3295
3421
  buttonText = "Menu",
3296
- showIcons = true,
3422
+ showIcons: _showIcons = true,
3297
3423
  navigationLabel = "Main navigation",
3298
3424
  // NEW: Phase 2 - Enhanced Security Features
3299
3425
  strictMode = true,
@@ -3303,8 +3429,8 @@ var NavigationMenu = React6.forwardRef(({
3303
3429
  itemsPreFiltered = false,
3304
3430
  ...props
3305
3431
  }, ref) => {
3306
- const [expandedItems, setExpandedItems] = React6.useState(/* @__PURE__ */ new Set());
3307
- const buttonRef = React6.useRef(null);
3432
+ const [expandedItems, setExpandedItems] = React.useState(/* @__PURE__ */ new Set());
3433
+ const buttonRef = React.useRef(null);
3308
3434
  const { authContext, rbacContext, filteredItems, permissionMap, hasAnyPermission } = useNavigationFiltering({ items, itemsPreFiltered, auditLog });
3309
3435
  const handleHierarchicalKeyDown = (event, item) => {
3310
3436
  switch (event.key) {
@@ -3446,7 +3572,7 @@ var NavigationMenu = React6.forwardRef(({
3446
3572
  id: `submenu-${item.id}`,
3447
3573
  role: "menu",
3448
3574
  "aria-label": `${item.label} submenu`,
3449
- children: item.children.map((child) => /* @__PURE__ */ jsx(React6.Fragment, { children: renderHierarchicalItem(child, level + 1) }, child.id))
3575
+ children: item.children.map((child) => /* @__PURE__ */ jsx(React.Fragment, { children: renderHierarchicalItem(child, level + 1) }, child.id))
3450
3576
  }
3451
3577
  )
3452
3578
  ] }) : /* @__PURE__ */ jsx(
@@ -3508,15 +3634,15 @@ var NavigationMenu = React6.forwardRef(({
3508
3634
  className,
3509
3635
  "aria-label": navigationLabel,
3510
3636
  ...props,
3511
- children: /* @__PURE__ */ jsx("ul", { role: "menubar", children: filteredItems.map((item) => /* @__PURE__ */ jsx(React6.Fragment, { children: renderHierarchicalItem(item, 0) }, item.id)) })
3637
+ children: /* @__PURE__ */ jsx("ul", { role: "menubar", children: filteredItems.map((item) => /* @__PURE__ */ jsx(React.Fragment, { children: renderHierarchicalItem(item, 0) }, item.id)) })
3512
3638
  }
3513
3639
  );
3514
3640
  });
3515
3641
  NavigationMenu.displayName = "NavigationMenu";
3642
+ var DEFAULT_LOGO_SRC = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIGZpbGw9IiNmZmYiLz48L3N2Zz4=";
3516
3643
  function Header({
3517
3644
  logoUrl,
3518
3645
  logoAlt = "Logo",
3519
- logo,
3520
3646
  navItems = [],
3521
3647
  user,
3522
3648
  onSignOut,
@@ -3535,39 +3661,54 @@ function Header({
3535
3661
  const shouldShowContextSelector = showContextSelector !== false;
3536
3662
  const { switchOrganisation } = useOrganisations();
3537
3663
  const { events, setSelectedEvent } = useEvents();
3664
+ const authContext = useUnifiedAuth();
3665
+ const isAuthenticated = authContext?.isAuthenticated ?? false;
3666
+ const appName = authContext?.appName;
3538
3667
  return /* @__PURE__ */ jsx("header", { className: cn(
3539
3668
  "w-full border-b border-main-200 h-16 shadow-sm bg-main-100 ",
3540
3669
  className
3541
- ), role: "banner", children: /* @__PURE__ */ jsxs("nav", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_1fr_auto_auto_auto_auto] items-center gap-4 h-full", children: [
3542
- logo ? logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: logo }) : logo : logoUrl ? logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: /* @__PURE__ */ jsx(
3670
+ ), role: "banner", children: /* @__PURE__ */ jsxs("nav", { className: cn(
3671
+ "px-4 w-[min(var(--app-width),100%)] mx-auto grid items-center gap-4 h-full",
3672
+ isAuthenticated && appName ? "grid-cols-[auto_auto_1fr_auto_auto]" : "grid-cols-[auto_1fr_auto_auto]"
3673
+ ), children: [
3674
+ isAuthenticated && appName && /* @__PURE__ */ jsx(
3675
+ AppSwitcher,
3676
+ {
3677
+ currentAppName: appName,
3678
+ className: "w-9"
3679
+ }
3680
+ ),
3681
+ logoUrl && (logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity flex items-center", children: /* @__PURE__ */ jsx(
3543
3682
  "img",
3544
3683
  {
3545
3684
  src: logoUrl,
3546
3685
  alt: logoAlt || "Logo",
3547
- className: "h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent"
3686
+ className: "h-9 w-auto shadow-md"
3548
3687
  }
3549
3688
  ) }) : /* @__PURE__ */ jsx(
3550
3689
  "img",
3551
3690
  {
3552
3691
  src: logoUrl,
3553
3692
  alt: logoAlt || "Logo",
3554
- className: "h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent"
3693
+ className: "h-9 w-auto shadow-md"
3555
3694
  }
3556
- ) : logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: /* @__PURE__ */ jsx(
3695
+ )),
3696
+ !logoUrl && // Default logo when logoUrl is not provided
3697
+ (logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity flex items-center", children: /* @__PURE__ */ jsx(
3557
3698
  "img",
3558
3699
  {
3559
- src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E",
3700
+ src: DEFAULT_LOGO_SRC,
3560
3701
  alt: logoAlt || "Logo",
3561
- className: "size-8 shadow-md"
3702
+ className: "h-9 w-auto shadow-md"
3562
3703
  }
3563
3704
  ) }) : /* @__PURE__ */ jsx(
3564
3705
  "img",
3565
3706
  {
3566
- src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E",
3707
+ src: DEFAULT_LOGO_SRC,
3567
3708
  alt: logoAlt || "Logo",
3568
- className: "size-8 shadow-md"
3709
+ className: "h-9 w-auto shadow-md"
3569
3710
  }
3570
- ),
3711
+ )),
3571
3712
  navItems && navItems.length > 0 && /* @__PURE__ */ jsx(
3572
3713
  NavigationMenu,
3573
3714
  {
@@ -3583,11 +3724,7 @@ function Header({
3583
3724
  ContextSelector,
3584
3725
  {
3585
3726
  placeholder: "Select organisation or event",
3586
- className: cn(
3587
- "w-96",
3588
- // Adjust width based on whether actions exist
3589
- actions ? "col-span-1" : "col-span-2"
3590
- ),
3727
+ className: "w-96",
3591
3728
  showOrganisations,
3592
3729
  showEvents,
3593
3730
  onOrganisationSelect: async (org) => {
@@ -3631,7 +3768,7 @@ var FooterComponent = ({
3631
3768
  ] }) });
3632
3769
  };
3633
3770
  FooterComponent.displayName = "Footer";
3634
- var Footer = React6__default.memo(FooterComponent);
3771
+ var Footer = React__default.memo(FooterComponent);
3635
3772
  Footer.displayName = "Footer";
3636
3773
  var EMPTY_PAGE_ID_MAPPING = {};
3637
3774
  var EMPTY_ROUTE_PERMISSIONS = {};
@@ -3642,7 +3779,6 @@ function PaceAppLayout({
3642
3779
  showOrganisations = true,
3643
3780
  showEvents = true,
3644
3781
  headerActions,
3645
- customLogo,
3646
3782
  logoHref = "/dashboard",
3647
3783
  customUserMenu,
3648
3784
  headerClassName,
@@ -3669,9 +3805,9 @@ function PaceAppLayout({
3669
3805
  const { user, signOut, updatePassword, supabase, appId: contextAppId, selectedOrganisationId } = useUnifiedAuth();
3670
3806
  const {
3671
3807
  selectedOrganisation,
3672
- isContextReady,
3673
- hasValidOrganisationContext,
3674
- ensureOrganisationContext,
3808
+ isContextReady: _isContextReady,
3809
+ hasValidOrganisationContext: _hasValidOrganisationContext,
3810
+ ensureOrganisationContext: _ensureOrganisationContext,
3675
3811
  isLoading: organisationLoading
3676
3812
  } = useOrganisations();
3677
3813
  const { isSuperAdmin: isSuperAdminFromRBAC, isLoading: rbacLoading } = useRBAC();
@@ -3709,7 +3845,7 @@ function PaceAppLayout({
3709
3845
  try {
3710
3846
  const eventsContext = useEvents();
3711
3847
  selectedEvent = eventsContext.selectedEvent;
3712
- } catch (error) {
3848
+ } catch (_error) {
3713
3849
  }
3714
3850
  const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({
3715
3851
  supabase: supabase || null,
@@ -3741,7 +3877,7 @@ function PaceAppLayout({
3741
3877
  { id: "ui-showcase", label: "UI Showcase", href: "/ui-showcase", icon: "Component" },
3742
3878
  { id: "data-table-showcase", label: "DataTable Showcase", href: "/data-table-showcase", icon: "Table" }
3743
3879
  ], []);
3744
- const baseMenuItems = useMemo(() => navItems || defaultNavItems, [navItems]);
3880
+ const baseMenuItems = useMemo(() => navItems || defaultNavItems, [navItems, defaultNavItems]);
3745
3881
  const currentRoutePermission = useMemo(() => {
3746
3882
  const currentPath = location.pathname;
3747
3883
  return routePermissions[currentPath] || defaultPermission;
@@ -3833,7 +3969,7 @@ function PaceAppLayout({
3833
3969
  return;
3834
3970
  }
3835
3971
  try {
3836
- const { isSuperAdmin: checkSuperAdminDynamic } = await import('./api-7P7DI652.js');
3972
+ const { isSuperAdmin: checkSuperAdminDynamic } = await import('./api-F47QJ7FX.js');
3837
3973
  const isSuper = await checkSuperAdminDynamic(user.id);
3838
3974
  if (isSuper) {
3839
3975
  if (isMounted) {
@@ -3847,7 +3983,7 @@ function PaceAppLayout({
3847
3983
  }
3848
3984
  }
3849
3985
  try {
3850
- const { getPermissionMap } = await import('./api-7P7DI652.js');
3986
+ const { getPermissionMap } = await import('./api-F47QJ7FX.js');
3851
3987
  const permissionScope = {
3852
3988
  organisationId: currentScope.organisationId,
3853
3989
  eventId: currentScope.eventId,
@@ -3858,7 +3994,7 @@ function PaceAppLayout({
3858
3994
  userId: user.id,
3859
3995
  scope: permissionScope
3860
3996
  });
3861
- const { getPageScopeType } = await import('./api-7P7DI652.js');
3997
+ const { getPageScopeType } = await import('./api-F47QJ7FX.js');
3862
3998
  const effectiveAppId = currentScope.appId || resolvedAppId;
3863
3999
  const effectiveAppName = appName;
3864
4000
  const hasEventContext = !!currentScope.eventId;
@@ -3944,7 +4080,7 @@ function PaceAppLayout({
3944
4080
  return () => {
3945
4081
  isMounted = false;
3946
4082
  };
3947
- }, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, selectedOrganisation?.id, selectedEvent?.event_id, appName]);
4083
+ }, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, resolvedAppId, selectedOrganisation?.id, selectedEvent?.event_id, appName]);
3948
4084
  useEffect(() => {
3949
4085
  if (!roleBasedRouting || routeConfig.length === 0) return;
3950
4086
  let isMounted = true;
@@ -3967,7 +4103,7 @@ function PaceAppLayout({
3967
4103
  let hasAccess = true;
3968
4104
  if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
3969
4105
  try {
3970
- const { isPermittedCached } = await import('./api-7P7DI652.js');
4106
+ const { isPermittedCached } = await import('./api-F47QJ7FX.js');
3971
4107
  const hasPagePermission = await isPermittedCached({
3972
4108
  userId: user?.id || "",
3973
4109
  scope,
@@ -3983,7 +4119,7 @@ function PaceAppLayout({
3983
4119
  }
3984
4120
  }
3985
4121
  if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
3986
- const { useUnifiedAuth: useUnifiedAuth2 } = await import('./UnifiedAuthProvider-7SNDOWYD.js');
4122
+ const { useUnifiedAuth: useUnifiedAuth2 } = await import('./UnifiedAuthProvider-BBD2PS3Q.js');
3987
4123
  hasAccess = true;
3988
4124
  }
3989
4125
  if (!isMounted) return;
@@ -4020,7 +4156,7 @@ function PaceAppLayout({
4020
4156
  logger.error("PaceAppLayout", "Failed to sign out", { error: error instanceof Error ? error.message : String(error) });
4021
4157
  }
4022
4158
  };
4023
- const handleChangePassword = async (newPassword, confirmPassword) => {
4159
+ const handleChangePassword = async (newPassword, _confirmPassword) => {
4024
4160
  try {
4025
4161
  const result = await updatePassword(newPassword);
4026
4162
  if (result?.error) {
@@ -4098,8 +4234,7 @@ function PaceAppLayout({
4098
4234
  /* @__PURE__ */ jsx(
4099
4235
  Header,
4100
4236
  {
4101
- logo: customLogo || void 0,
4102
- logoUrl: !customLogo ? `/${appName.toLowerCase()}_logo_wide.svg` : void 0,
4237
+ logoUrl: `/${appName.toLowerCase()}_logo_wide.svg`,
4103
4238
  logoAlt: `${appName} Logo`,
4104
4239
  logoHref,
4105
4240
  navItems: filteredMenuItems,
@@ -4160,7 +4295,7 @@ var PaceLoginPage = ({
4160
4295
  if (isOnLoginPage && eventService) {
4161
4296
  await eventService.restorePersistedEvent();
4162
4297
  }
4163
- } catch (error) {
4298
+ } catch (_error) {
4164
4299
  }
4165
4300
  };
4166
4301
  const timeoutId = setTimeout(() => {
@@ -4407,6 +4542,10 @@ function ProtectedRoute({
4407
4542
  });
4408
4543
  return /* @__PURE__ */ jsx(Navigate, { to: loginPath, replace: true });
4409
4544
  }
4545
+ const restorationNotComplete = !sessionRestoration.restorationComplete && !sessionRestoration.hasTimedOut && !sessionRestoration.restorationError;
4546
+ if (restorationNotComplete || sessionRestoration.isRestoring || isLoading) {
4547
+ return loadingFallback || /* @__PURE__ */ jsx("main", { className: "grid place-items-center size-full", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) });
4548
+ }
4410
4549
  if (!wasAuthenticatedRef.current) {
4411
4550
  return /* @__PURE__ */ jsx(Navigate, { to: loginPath, replace: true });
4412
4551
  }
@@ -4436,6 +4575,168 @@ function ProtectedRoute({
4436
4575
  }
4437
4576
  return /* @__PURE__ */ jsx(Outlet, {});
4438
4577
  }
4578
+ var ErrorBoundaryContext = createContext(void 0);
4579
+ function ErrorBoundaryProvider({
4580
+ children,
4581
+ defaultErrorHandler
4582
+ }) {
4583
+ const contextValue = {
4584
+ defaultErrorHandler
4585
+ };
4586
+ return /* @__PURE__ */ jsx(ErrorBoundaryContext.Provider, { value: contextValue, children });
4587
+ }
4588
+ var ErrorBoundary = class extends Component {
4589
+ constructor(props) {
4590
+ super(props);
4591
+ this.retryTimeoutId = null;
4592
+ this.reportError = (errorId, componentName) => {
4593
+ if (import.meta.env.MODE === "production") {
4594
+ logger.warn("ErrorBoundary", "Error reporting would be triggered in production:", { errorId, componentName });
4595
+ }
4596
+ };
4597
+ this.handleRetry = () => {
4598
+ const { maxRetries = 3 } = this.props;
4599
+ const { retryCount } = this.state;
4600
+ if (retryCount < maxRetries) {
4601
+ logger.debug("ErrorBoundary", `Retrying component render (attempt ${retryCount + 1}/${maxRetries})`);
4602
+ this.setState((prevState) => ({
4603
+ hasError: false,
4604
+ error: void 0,
4605
+ errorInfo: void 0,
4606
+ errorId: void 0,
4607
+ retryCount: prevState.retryCount + 1
4608
+ }));
4609
+ }
4610
+ };
4611
+ this.state = {
4612
+ hasError: false,
4613
+ retryCount: 0
4614
+ };
4615
+ }
4616
+ static getDerivedStateFromError(error) {
4617
+ const errorId = `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
4618
+ return {
4619
+ hasError: true,
4620
+ error,
4621
+ errorId
4622
+ };
4623
+ }
4624
+ componentDidCatch(error, errorInfo) {
4625
+ const { componentName = "Unknown Component", onError, enableReporting = true } = this.props;
4626
+ const errorId = this.state.errorId;
4627
+ const componentNameForHandler = componentName || "Unknown Component";
4628
+ this.setState({ errorInfo });
4629
+ logger.error("ErrorBoundary", `[${componentNameForHandler}] Caught error ${errorId}:`, error, errorInfo);
4630
+ performanceBudgetMonitor.measure("ERROR_BOUNDARY_TRIGGER", 1, {
4631
+ componentName: componentNameForHandler,
4632
+ errorId,
4633
+ errorMessage: error.message,
4634
+ stack: error.stack?.substring(0, 200)
4635
+ // Truncated stack trace
4636
+ });
4637
+ if (enableReporting) {
4638
+ this.reportError(errorId, componentNameForHandler);
4639
+ }
4640
+ if (onError) {
4641
+ onError(error, errorInfo, errorId);
4642
+ } else if (this.props._globalErrorHandler) {
4643
+ this.props._globalErrorHandler(error, errorInfo, errorId, componentNameForHandler);
4644
+ }
4645
+ }
4646
+ componentWillUnmount() {
4647
+ if (this.retryTimeoutId) {
4648
+ clearTimeout(this.retryTimeoutId);
4649
+ }
4650
+ }
4651
+ render() {
4652
+ if (this.state.hasError) {
4653
+ const {
4654
+ componentName = "Component",
4655
+ fallback,
4656
+ enableRetry = true,
4657
+ maxRetries = 3
4658
+ } = this.props;
4659
+ const { retryCount, errorId } = this.state;
4660
+ if (fallback) {
4661
+ return fallback;
4662
+ }
4663
+ return /* @__PURE__ */ jsxs(
4664
+ Card,
4665
+ {
4666
+ role: "alert",
4667
+ className: "bg-destructive/10 border-destructive/20",
4668
+ "data-error-boundary": errorId,
4669
+ children: [
4670
+ /* @__PURE__ */ jsxs(CardHeader, { className: "flex items-start gap-3", children: [
4671
+ /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-destructive flex-shrink-0", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }),
4672
+ /* @__PURE__ */ jsxs(CardTitle, { className: "text-destructive", children: [
4673
+ "Error in ",
4674
+ componentName
4675
+ ] }),
4676
+ /* @__PURE__ */ jsx(CardDescription, { className: "text-destructive/80", children: this.state.error?.message || "An unexpected error occurred." })
4677
+ ] }),
4678
+ import.meta.env.MODE === "development" && this.state.error && /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("details", { className: "text-sm text-destructive/70", children: [
4679
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer font-medium mb-2", children: "Error Details (Development)" }),
4680
+ /* @__PURE__ */ jsxs("pre", { children: [
4681
+ "Error ID: ",
4682
+ errorId,
4683
+ /* @__PURE__ */ jsxs("code", { className: "overflow-auto max-h-32", children: [
4684
+ this.state.error.toString(),
4685
+ this.state.errorInfo?.componentStack
4686
+ ] })
4687
+ ] })
4688
+ ] }) }),
4689
+ enableRetry && retryCount < maxRetries && /* @__PURE__ */ jsxs(CardFooter, { className: "flex gap-3", children: [
4690
+ /* @__PURE__ */ jsxs(
4691
+ "button",
4692
+ {
4693
+ onClick: this.handleRetry,
4694
+ className: "px-4 py-2 bg-destructive text-destructive-foreground rounded-md hover:bg-destructive/90 transition-colors text-sm font-medium",
4695
+ children: [
4696
+ "Retry (",
4697
+ retryCount + 1,
4698
+ "/",
4699
+ maxRetries,
4700
+ ")"
4701
+ ]
4702
+ }
4703
+ ),
4704
+ /* @__PURE__ */ jsx(
4705
+ "button",
4706
+ {
4707
+ onClick: () => window.location.reload(),
4708
+ className: "px-4 py-2 bg-sec-600 text-main-50 rounded-md hover:bg-sec-700 transition-colors text-sm font-medium",
4709
+ children: "Reload Page"
4710
+ }
4711
+ )
4712
+ ] }),
4713
+ retryCount >= maxRetries && /* @__PURE__ */ jsxs(CardFooter, { className: "flex flex-col gap-3", children: [
4714
+ /* @__PURE__ */ jsx("p", { className: "text-acc-800", children: "Maximum retry attempts reached. Please reload the page or contact support." }),
4715
+ /* @__PURE__ */ jsx(
4716
+ "button",
4717
+ {
4718
+ onClick: () => window.location.reload(),
4719
+ className: "px-3 py-1 bg-acc-600 text-main-50 rounded text-sm hover:bg-acc-700",
4720
+ children: "Reload Page"
4721
+ }
4722
+ )
4723
+ ] })
4724
+ ]
4725
+ }
4726
+ );
4727
+ }
4728
+ return this.props.children;
4729
+ }
4730
+ };
4731
+ function useErrorBoundaryContext() {
4732
+ return useContext(ErrorBoundaryContext);
4733
+ }
4734
+ var ErrorBoundary2 = React__default.forwardRef((props, ref) => {
4735
+ const context = useErrorBoundaryContext();
4736
+ const globalErrorHandler = context?.defaultErrorHandler;
4737
+ return React__default.createElement(ErrorBoundary, { ...props, ref, _globalErrorHandler: globalErrorHandler });
4738
+ });
4739
+ ErrorBoundary2.displayName = "ErrorBoundary";
4439
4740
  function FileUpload({
4440
4741
  supabase,
4441
4742
  table_name,
@@ -4461,11 +4762,10 @@ function FileUpload({
4461
4762
  onProgress,
4462
4763
  children
4463
4764
  }) {
4765
+ const logger2 = createLogger("FileUpload");
4464
4766
  if (!pageContext) {
4465
4767
  const errorMsg = "pageContext is required for FileUpload component. This is used for permission checks.";
4466
- if (import.meta.env.MODE === "development") {
4467
- console.error("[FileUpload]", errorMsg);
4468
- }
4768
+ logger2.error(errorMsg);
4469
4769
  throw new Error(errorMsg);
4470
4770
  }
4471
4771
  const [isDragging, setIsDragging] = useState(false);
@@ -4475,13 +4775,14 @@ function FileUpload({
4475
4775
  const [appIdError, setAppIdError] = useState(null);
4476
4776
  const fileInputRef = useRef(null);
4477
4777
  const progressIntervalsRef = useRef(/* @__PURE__ */ new Map());
4478
- const { uploadFile, isLoading, error } = useFileReference(supabase);
4778
+ const { uploadFile, error } = useFileReference(supabase);
4479
4779
  useEffect(() => {
4780
+ const intervals = progressIntervalsRef.current;
4480
4781
  return () => {
4481
- progressIntervalsRef.current.forEach((interval) => {
4782
+ intervals.forEach((interval) => {
4482
4783
  clearInterval(interval);
4483
4784
  });
4484
- progressIntervalsRef.current.clear();
4785
+ intervals.clear();
4485
4786
  };
4486
4787
  }, []);
4487
4788
  useEffect(() => {
@@ -4754,7 +5055,7 @@ function FileUpload({
4754
5055
  onUploadError?.(errorMessage, file);
4755
5056
  }
4756
5057
  }
4757
- }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError, pageContext]);
5058
+ }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError, pageContext, event_id, userId]);
4758
5059
  const handleDragOver = useCallback((e) => {
4759
5060
  e.preventDefault();
4760
5061
  e.stopPropagation();
@@ -4908,7 +5209,7 @@ function FileUpload({
4908
5209
  }
4909
5210
  function PublicPageHeader({
4910
5211
  event,
4911
- eventCode,
5212
+ eventCode: _eventCode,
4912
5213
  title,
4913
5214
  description,
4914
5215
  showEventLogo = true,
@@ -4935,7 +5236,7 @@ function PublicPageHeader({
4935
5236
  showEventLogo && event && /* @__PURE__ */ jsx(Fragment, { children: customEventLogo || /* @__PURE__ */ jsx(
4936
5237
  FileDisplay,
4937
5238
  {
4938
- table_name: "event",
5239
+ table_name: "core_events",
4939
5240
  record_id: event.event_id,
4940
5241
  organisation_id: event.organisation_id,
4941
5242
  category: "event_logos" /* EVENT_LOGOS */,
@@ -4943,7 +5244,7 @@ function PublicPageHeader({
4943
5244
  showFallback: true,
4944
5245
  fallbackSize: "md",
4945
5246
  className: "mr-4 max-w-36 row-span-2",
4946
- generateFallbackText: (fileName) => {
5247
+ generateFallbackText: (_fileName) => {
4947
5248
  if (!event.event_name) return "EV";
4948
5249
  return event.event_name.split(/[\s\-_]+/).map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
4949
5250
  }
@@ -4959,7 +5260,7 @@ function PublicPageHeader({
4959
5260
  ] });
4960
5261
  }
4961
5262
  function PublicPageFooter({
4962
- event,
5263
+ event: _event,
4963
5264
  companyName = "Solvera Solutions Pty Ltd",
4964
5265
  year = (/* @__PURE__ */ new Date()).getFullYear(),
4965
5266
  links,
@@ -4998,7 +5299,7 @@ function PublicPageLayout({
4998
5299
  if (LoadingFallback) {
4999
5300
  return /* @__PURE__ */ jsx(LoadingFallback, {});
5000
5301
  }
5001
- return /* @__PURE__ */ jsxs("p", { className: "grid place-items-center text-center size-full", children: [
5302
+ return /* @__PURE__ */ jsxs("div", { className: "grid place-items-center text-center size-full", children: [
5002
5303
  /* @__PURE__ */ jsx(
5003
5304
  LoadingSpinner,
5004
5305
  {
@@ -5030,7 +5331,7 @@ function PublicPageLayout({
5030
5331
  handleRefetch && /* @__PURE__ */ jsx(Button, { onClick: handleRefetch, children: "Try Again" })
5031
5332
  ] });
5032
5333
  }
5033
- return /* @__PURE__ */ jsx(ErrorBoundary, { componentName: "PublicPageLayout", children: /* @__PURE__ */ jsxs(Fragment, { children: [
5334
+ return /* @__PURE__ */ jsx(ErrorBoundary2, { componentName: "PublicPageLayout", children: /* @__PURE__ */ jsxs(Fragment, { children: [
5034
5335
  customHeader || /* @__PURE__ */ jsx(
5035
5336
  PublicPageHeader,
5036
5337
  {
@@ -5042,5 +5343,37 @@ function PublicPageLayout({
5042
5343
  showFooter && event && (customFooter || /* @__PURE__ */ jsx(PublicPageFooter, { event }))
5043
5344
  ] }) });
5044
5345
  }
5346
+ function PublicPageProvider({ children, appName }) {
5347
+ const getEnvVar = (key) => {
5348
+ if (typeof import.meta !== "undefined" && import.meta.env) {
5349
+ const env = import.meta.env;
5350
+ return env[key];
5351
+ }
5352
+ if (typeof process !== "undefined" && process.env) {
5353
+ return process.env[key];
5354
+ }
5355
+ return void 0;
5356
+ };
5357
+ const supabaseUrl = getEnvVar("VITE_SUPABASE_URL") || getEnvVar("NEXT_PUBLIC_SUPABASE_URL") || null;
5358
+ const supabaseKey = getEnvVar("VITE_SUPABASE_PUBLISHABLE_KEY") || getEnvVar("NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY") || getEnvVar("VITE_SUPABASE_ANON_KEY") || getEnvVar("NEXT_PUBLIC_SUPABASE_ANON_KEY") || null;
5359
+ const supabase = useMemo(() => {
5360
+ if (!supabaseUrl || !supabaseKey) {
5361
+ logger.warn("PublicPageProvider", "Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are set in your environment.");
5362
+ return null;
5363
+ }
5364
+ const client = createClient(supabaseUrl, supabaseKey);
5365
+ return client;
5366
+ }, [supabaseUrl, supabaseKey]);
5367
+ const contextValue = {
5368
+ isPublicPage: true,
5369
+ supabase,
5370
+ appName: appName || null,
5371
+ environment: {
5372
+ supabaseUrl,
5373
+ supabaseKey
5374
+ }
5375
+ };
5376
+ return /* @__PURE__ */ jsx(PublicPageContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ErrorBoundary2, { componentName: "PublicPageProvider", children }) });
5377
+ }
5045
5378
 
5046
- export { AddressField, Avatar, Badge, Calendar, ContextSelector, FileDisplay, FileUpload, Footer, Form, FormField, Header, LoginForm, NavigationMenu, PaceAppLayout, PaceLoginPage, PasswordChangeForm, ProtectedRoute, PublicPageFooter, PublicPageHeader, PublicPageLayout, SessionRestorationLoader, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, UserMenu, useFileReference, useFileReferenceById, useFileReferenceForRecord, useFilesByCategory };
5379
+ export { AddressField, AppSwitcher, Avatar, Badge, Calendar, ContextSelector, DEFAULT_APP_PORT_MAP, DatePickerWithTimezone, ErrorBoundary2 as ErrorBoundary, ErrorBoundaryProvider, FileDisplay, FileUpload, Footer, Form, FormField, Header, LoginForm, NavigationMenu, PaceAppLayout, PaceLoginPage, PasswordChangeForm, ProtectedRoute, PublicPageFooter, PublicPageHeader, PublicPageLayout, PublicPageProvider, SessionRestorationLoader, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, UserMenu, buildAppUrl, getAllAppPorts, getAppPort, useAccessibleApps, useFileReference, useFileReferenceById, useFileReferenceForRecord, useFilesByCategory };