@jmruthers/pace-core 0.5.181 → 0.5.182

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 (750) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +16 -2
  3. package/dist/{AuthService-DYuQPJj6.d.ts → AuthService-B-cd2MA4.d.ts} +9 -11
  4. package/dist/{DataTable-CWAZZcXC.d.ts → DataTable-Bz8ffqyA.d.ts} +1 -1
  5. package/dist/{DataTable-UA6CL4JI.js → DataTable-QAB34V6K.js} +14 -15
  6. package/dist/UnifiedAuthProvider-7F6T4B6K.js +13 -0
  7. package/dist/{UnifiedAuthProvider-DJxGTftH.d.ts → UnifiedAuthProvider-F86d7dSi.d.ts} +5 -6
  8. package/dist/{api-45XYYO2A.js → api-ROMBCNKU.js} +5 -5
  9. package/dist/{audit-64X3VJXB.js → audit-WRS3KJKI.js} +4 -4
  10. package/dist/auth-BZOJqrdd.d.ts +49 -0
  11. package/dist/{chunk-CX5M4ZAG.js → chunk-5DRSZLL2.js} +1 -1
  12. package/dist/chunk-5DRSZLL2.js.map +1 -0
  13. package/dist/{chunk-BESYRHQM.js → chunk-6C4YBBJM.js} +10 -7
  14. package/dist/chunk-6C4YBBJM.js.map +1 -0
  15. package/dist/{chunk-PLDDJCW6.js → chunk-7D4SUZUM.js} +2 -13
  16. package/dist/{chunk-HRO5HWN2.js → chunk-CSOFYHAG.js} +55 -162
  17. package/dist/chunk-CSOFYHAG.js.map +1 -0
  18. package/dist/{chunk-ANBQRTPX.js → chunk-E66EQZE6.js} +3 -5
  19. package/dist/{chunk-ANBQRTPX.js.map → chunk-E66EQZE6.js.map} +1 -1
  20. package/dist/{chunk-Q5QRDWKI.js → chunk-F2IMUDXZ.js} +4 -6
  21. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  22. package/dist/{chunk-SBVILCCA.js → chunk-FSFQFJCU.js} +28 -6
  23. package/dist/chunk-FSFQFJCU.js.map +1 -0
  24. package/dist/chunk-FUEYYMX5.js +2296 -0
  25. package/dist/chunk-FUEYYMX5.js.map +1 -0
  26. package/dist/{chunk-FFKNH6U5.js → chunk-HKIT6O7W.js} +3 -5
  27. package/dist/{chunk-FFKNH6U5.js.map → chunk-HKIT6O7W.js.map} +1 -1
  28. package/dist/chunk-KQCRWDSA.js +1 -0
  29. package/dist/{chunk-S5OFRT4M.js → chunk-KUEN3HFB.js} +6 -6
  30. package/dist/chunk-KUEN3HFB.js.map +1 -0
  31. package/dist/chunk-LMC26NLJ.js +84 -0
  32. package/dist/chunk-LMC26NLJ.js.map +1 -0
  33. package/dist/{chunk-BVYWGZVV.js → chunk-M7W4CP3M.js} +52 -19
  34. package/dist/chunk-M7W4CP3M.js.map +1 -0
  35. package/dist/{chunk-HZLDFOE4.js → chunk-MI7HBHN3.js} +164 -243
  36. package/dist/chunk-MI7HBHN3.js.map +1 -0
  37. package/dist/{chunk-PPMP5J6T.js → chunk-PWAHJW4G.js} +180 -29
  38. package/dist/chunk-PWAHJW4G.js.map +1 -0
  39. package/dist/chunk-PWLANIRT.js +127 -0
  40. package/dist/{chunk-XDNLUEXI.js.map → chunk-PWLANIRT.js.map} +1 -1
  41. package/dist/chunk-QCDXODCA.js +75 -0
  42. package/dist/chunk-QCDXODCA.js.map +1 -0
  43. package/dist/{chunk-D7LCGMVS.js → chunk-QETLRQI6.js} +526 -887
  44. package/dist/chunk-QETLRQI6.js.map +1 -0
  45. package/dist/{chunk-5MT24GKJ.js → chunk-QUVSNGIP.js} +264 -262
  46. package/dist/chunk-QUVSNGIP.js.map +1 -0
  47. package/dist/chunk-QXHPKYJV.js +113 -0
  48. package/dist/chunk-QXHPKYJV.js.map +1 -0
  49. package/dist/{chunk-OWAG3GSU.js → chunk-R77UEZ4E.js} +11 -1
  50. package/dist/chunk-R77UEZ4E.js.map +1 -0
  51. package/dist/{chunk-ZYTYSTO5.js → chunk-RA3JUFMW.js} +314 -161
  52. package/dist/chunk-RA3JUFMW.js.map +1 -0
  53. package/dist/{chunk-ERISIBYU.js → chunk-SQGMNID3.js} +3 -8
  54. package/dist/chunk-SQGMNID3.js.map +1 -0
  55. package/dist/{chunk-XJ2HZOBU.js → chunk-UHNYIBXL.js} +1 -1
  56. package/dist/chunk-UHNYIBXL.js.map +1 -0
  57. package/{src/utils/secureStorage.ts → dist/chunk-VBXEHIUJ.js} +113 -88
  58. package/dist/{chunk-7QCC6MCP.js.map → chunk-VBXEHIUJ.js.map} +1 -1
  59. package/dist/{chunk-VZ4VDGTB.js → chunk-W22JP75J.js} +5 -13
  60. package/dist/{chunk-VZ4VDGTB.js.map → chunk-W22JP75J.js.map} +1 -1
  61. package/dist/components.d.ts +12 -93
  62. package/dist/components.js +23 -106
  63. package/dist/components.js.map +1 -1
  64. package/dist/core-CUElvH_C.d.ts +164 -0
  65. package/dist/database.generated-CBmg2950.d.ts +8284 -0
  66. package/dist/event-CW5YB_2p.d.ts +239 -0
  67. package/dist/{file-reference-C6Gkn77H.d.ts → file-reference-D06mEEWW.d.ts} +7 -5
  68. package/dist/functions-D_kgHktt.d.ts +208 -0
  69. package/dist/hooks.d.ts +54 -7
  70. package/dist/hooks.js +204 -17
  71. package/dist/hooks.js.map +1 -1
  72. package/dist/{EventLogo-B3V3otev.d.ts → index-Bl--n7-T.d.ts} +387 -397
  73. package/dist/index.d.ts +94 -261
  74. package/dist/index.js +314 -126
  75. package/dist/index.js.map +1 -1
  76. package/dist/providers.d.ts +7 -8
  77. package/dist/providers.js +6 -13
  78. package/dist/rbac/index.d.ts +171 -101
  79. package/dist/rbac/index.js +23 -17
  80. package/dist/styles/index.d.ts +1 -3
  81. package/dist/styles/index.js +2 -17
  82. package/dist/theming/runtime.js +3 -3
  83. package/dist/types-UU913iLA.d.ts +102 -0
  84. package/dist/{types-Dfz9dmVH.d.ts → types-_x1f4QBF.d.ts} +6 -6
  85. package/dist/types.d.ts +88 -227
  86. package/dist/types.js +64 -112
  87. package/dist/types.js.map +1 -1
  88. package/dist/{usePublicRouteParams-B7PabvuH.d.ts → usePublicRouteParams-JJczomYq.d.ts} +203 -6
  89. package/dist/utils.d.ts +299 -13
  90. package/dist/utils.js +481 -55
  91. package/dist/utils.js.map +1 -1
  92. package/dist/validation-643vUDZW.d.ts +177 -0
  93. package/docs/DOCUMENTATION_REVIEW_TRACKER.md +511 -0
  94. package/docs/README.md +9 -8
  95. package/docs/api/README.md +16 -2
  96. package/docs/api/classes/ColumnFactory.md +1 -1
  97. package/docs/api/classes/ErrorBoundary.md +1 -1
  98. package/docs/api/classes/InvalidScopeError.md +4 -4
  99. package/docs/api/classes/MissingUserContextError.md +4 -4
  100. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  101. package/docs/api/classes/PermissionDeniedError.md +4 -4
  102. package/docs/api/classes/RBACAuditManager.md +14 -14
  103. package/docs/api/classes/RBACCache.md +1 -1
  104. package/docs/api/classes/RBACEngine.md +2 -2
  105. package/docs/api/classes/RBACError.md +4 -4
  106. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  107. package/docs/api/classes/SecureSupabaseClient.md +29 -9
  108. package/docs/api/classes/StorageUtils.md +1 -1
  109. package/docs/api/enums/FileCategory.md +17 -17
  110. package/docs/api/enums/RBACErrorCode.md +228 -0
  111. package/docs/api/enums/RPCFunction.md +118 -0
  112. package/docs/api/interfaces/AggregateConfig.md +1 -1
  113. package/docs/api/interfaces/BadgeProps.md +1 -1
  114. package/docs/api/interfaces/ButtonProps.md +2 -2
  115. package/docs/api/interfaces/CalendarProps.md +1 -1
  116. package/docs/api/interfaces/CardProps.md +29 -3
  117. package/docs/api/interfaces/ColorPalette.md +1 -1
  118. package/docs/api/interfaces/ColorShade.md +1 -1
  119. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  120. package/docs/api/interfaces/DataRecord.md +1 -1
  121. package/docs/api/interfaces/DataTableAction.md +2 -2
  122. package/docs/api/interfaces/DataTableColumn.md +6 -6
  123. package/docs/api/interfaces/DataTableProps.md +1 -1
  124. package/docs/api/interfaces/DataTableToolbarButton.md +2 -2
  125. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  126. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  127. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  128. package/docs/api/interfaces/ExportColumn.md +5 -5
  129. package/docs/api/interfaces/ExportOptions.md +4 -4
  130. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  131. package/docs/api/interfaces/FileMetadata.md +13 -13
  132. package/docs/api/interfaces/FileReference.md +12 -12
  133. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  134. package/docs/api/interfaces/FileUploadOptions.md +10 -10
  135. package/docs/api/interfaces/FileUploadProps.md +19 -19
  136. package/docs/api/interfaces/FooterProps.md +1 -1
  137. package/docs/api/interfaces/FormFieldProps.md +166 -0
  138. package/docs/api/interfaces/FormProps.md +113 -0
  139. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  140. package/docs/api/interfaces/InactivityWarningModalProps.md +8 -8
  141. package/docs/api/interfaces/InputProps.md +2 -2
  142. package/docs/api/interfaces/LabelProps.md +8 -8
  143. package/docs/api/interfaces/LoginFormProps.md +1 -1
  144. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  145. package/docs/api/interfaces/NavigationContextType.md +1 -1
  146. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  147. package/docs/api/interfaces/NavigationItem.md +17 -73
  148. package/docs/api/interfaces/NavigationMenuProps.md +38 -53
  149. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  150. package/docs/api/interfaces/Organisation.md +13 -13
  151. package/docs/api/interfaces/OrganisationContextType.md +21 -21
  152. package/docs/api/interfaces/OrganisationMembership.md +15 -15
  153. package/docs/api/interfaces/OrganisationProviderProps.md +59 -2
  154. package/docs/api/interfaces/OrganisationSecurityError.md +5 -5
  155. package/docs/api/interfaces/PaceAppLayoutProps.md +26 -39
  156. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  157. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  158. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  159. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  160. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  161. package/docs/api/interfaces/PaletteData.md +1 -1
  162. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  163. package/docs/api/interfaces/ProgressProps.md +50 -0
  164. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  165. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  166. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  167. package/docs/api/interfaces/PublicPageLayoutProps.md +15 -15
  168. package/docs/api/interfaces/RBACAccessValidateParams.md +52 -0
  169. package/docs/api/interfaces/RBACAccessValidateResult.md +41 -0
  170. package/docs/api/interfaces/RBACAuditLogParams.md +85 -0
  171. package/docs/api/interfaces/RBACAuditLogResult.md +52 -0
  172. package/docs/api/interfaces/RBACConfig.md +2 -2
  173. package/docs/api/interfaces/RBACContext.md +52 -0
  174. package/docs/api/interfaces/RBACLogger.md +1 -1
  175. package/docs/api/interfaces/RBACPageAccessCheckParams.md +74 -0
  176. package/docs/api/interfaces/RBACPermissionCheckParams.md +74 -0
  177. package/docs/api/interfaces/RBACPermissionCheckResult.md +52 -0
  178. package/docs/api/interfaces/RBACPermissionsGetParams.md +63 -0
  179. package/docs/api/interfaces/RBACPermissionsGetResult.md +63 -0
  180. package/docs/api/interfaces/RBACResult.md +58 -0
  181. package/docs/api/interfaces/RBACRoleGrantParams.md +63 -0
  182. package/docs/api/interfaces/RBACRoleGrantResult.md +52 -0
  183. package/docs/api/interfaces/RBACRoleRevokeParams.md +63 -0
  184. package/docs/api/interfaces/RBACRoleRevokeResult.md +52 -0
  185. package/docs/api/interfaces/RBACRoleValidateParams.md +52 -0
  186. package/docs/api/interfaces/RBACRoleValidateResult.md +63 -0
  187. package/docs/api/interfaces/RBACRolesListParams.md +52 -0
  188. package/docs/api/interfaces/RBACRolesListResult.md +74 -0
  189. package/docs/api/interfaces/RBACSessionTrackParams.md +74 -0
  190. package/docs/api/interfaces/RBACSessionTrackResult.md +52 -0
  191. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  192. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  193. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  194. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  195. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  196. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  197. package/docs/api/interfaces/RouteConfig.md +1 -1
  198. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  199. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  200. package/docs/api/interfaces/SessionRestorationLoaderProps.md +15 -2
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +43 -2
  215. package/docs/api/interfaces/TextareaProps.md +2 -2
  216. package/docs/api/interfaces/ToastActionElement.md +1 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +61 -61
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  220. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  221. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  222. package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
  223. package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
  224. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  225. package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
  226. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  227. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  228. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  229. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  230. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  231. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  232. package/docs/api/interfaces/UserEventAccess.md +1 -1
  233. package/docs/api/interfaces/UserMenuProps.md +4 -4
  234. package/docs/api/interfaces/UserProfile.md +7 -7
  235. package/docs/api/modules.md +484 -462
  236. package/docs/api-reference/components.md +186 -15
  237. package/docs/api-reference/deprecated.md +376 -0
  238. package/docs/api-reference/hooks.md +149 -19
  239. package/docs/api-reference/providers.md +61 -6
  240. package/docs/api-reference/rpc-functions.md +397 -0
  241. package/docs/api-reference/types.md +135 -78
  242. package/docs/api-reference/utilities.md +51 -380
  243. package/docs/architecture/README.md +49 -3
  244. package/docs/architecture/database-schema-requirements.md +40 -3
  245. package/docs/architecture/rbac-security-architecture.md +41 -4
  246. package/docs/architecture/services.md +127 -42
  247. package/docs/best-practices/README.md +51 -5
  248. package/docs/best-practices/accessibility.md +32 -3
  249. package/docs/best-practices/common-patterns.md +50 -3
  250. package/docs/best-practices/deployment.md +50 -4
  251. package/docs/best-practices/performance.md +50 -3
  252. package/docs/best-practices/security.md +94 -41
  253. package/docs/best-practices/testing.md +33 -4
  254. package/docs/core-concepts/authentication.md +5 -5
  255. package/docs/core-concepts/events.md +3 -3
  256. package/docs/core-concepts/organisations.md +3 -3
  257. package/docs/core-concepts/permissions.md +3 -3
  258. package/docs/core-concepts/rbac-system.md +5 -5
  259. package/docs/documentation-index.md +30 -8
  260. package/docs/getting-started/documentation-index.md +1 -1
  261. package/docs/getting-started/examples/README.md +7 -5
  262. package/docs/getting-started/examples/basic-auth-app.md +3 -0
  263. package/docs/getting-started/examples/full-featured-app.md +5 -3
  264. package/docs/getting-started/faq.md +6 -6
  265. package/docs/getting-started/installation-guide.md +192 -13
  266. package/docs/getting-started/local-development.md +303 -0
  267. package/docs/getting-started/quick-reference.md +3 -3
  268. package/docs/getting-started/quick-start.md +517 -0
  269. package/docs/implementation-guides/app-layout.md +45 -3
  270. package/docs/implementation-guides/authentication.md +66 -7
  271. package/docs/implementation-guides/component-styling.md +53 -3
  272. package/docs/implementation-guides/data-tables.md +76 -7
  273. package/docs/implementation-guides/datatable-filtering.md +1 -2
  274. package/docs/implementation-guides/datatable-rbac-usage.md +0 -1
  275. package/docs/implementation-guides/dynamic-colors.md +155 -4
  276. package/docs/implementation-guides/file-reference-system.md +72 -3
  277. package/docs/implementation-guides/file-upload-storage.md +72 -3
  278. package/docs/implementation-guides/forms.md +53 -3
  279. package/docs/implementation-guides/inactivity-tracking.md +53 -3
  280. package/docs/implementation-guides/large-datasets.md +1 -1
  281. package/docs/implementation-guides/navigation.md +55 -5
  282. package/docs/implementation-guides/organisation-security.md +72 -3
  283. package/docs/implementation-guides/performance.md +57 -1
  284. package/docs/implementation-guides/permission-enforcement.md +81 -8
  285. package/docs/implementation-guides/public-pages.md +560 -14
  286. package/docs/migration/MIGRATION_GUIDE.md +409 -50
  287. package/docs/migration/README.md +37 -3
  288. package/docs/migration/organisation-context-timing-fix.md +39 -4
  289. package/docs/migration/quick-migration-guide.md +41 -5
  290. package/docs/migration/rbac-migration.md +59 -3
  291. package/docs/migration/service-architecture.md +77 -14
  292. package/docs/rbac/README.md +79 -3
  293. package/docs/rbac/advanced-patterns.md +47 -3
  294. package/docs/rbac/api-reference.md +77 -8
  295. package/docs/rbac/event-based-apps.md +50 -5
  296. package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
  297. package/docs/rbac/examples.md +39 -3
  298. package/docs/rbac/getting-started.md +63 -4
  299. package/docs/rbac/quick-start.md +57 -5
  300. package/docs/rbac/rbac-rls-integration.md +68 -6
  301. package/docs/rbac/super-admin-guide.md +47 -3
  302. package/docs/rbac/troubleshooting.md +3 -3
  303. package/docs/security/README.md +68 -3
  304. package/docs/security/checklist.md +50 -3
  305. package/docs/standards/01-architecture-standard.md +39 -0
  306. package/docs/standards/02-api-and-rpc-standard.md +39 -0
  307. package/docs/standards/03-component-standard.md +32 -0
  308. package/docs/standards/04-code-style-standard.md +32 -0
  309. package/docs/standards/05-security-standard.md +30 -0
  310. package/docs/standards/06-testing-and-docs-standard.md +29 -0
  311. package/docs/standards/README.md +35 -0
  312. package/docs/styles/README.md +89 -8
  313. package/docs/testing/README.md +175 -24
  314. package/docs/troubleshooting/README.md +50 -3
  315. package/docs/troubleshooting/common-issues.md +271 -5
  316. package/docs/troubleshooting/debugging.md +54 -1
  317. package/docs/troubleshooting/migration.md +54 -1
  318. package/docs/troubleshooting/organisation-context-setup.md +29 -3
  319. package/docs/troubleshooting/styling-issues.md +246 -4
  320. package/{src/components/DataTable/examples → examples/DataTable}/GroupingAggregationExample.tsx +1 -1
  321. package/examples/{components 2/DataTable/HierarchicalActionsExample.tsx → DataTable/HierarchicalActionsExample.tsx} +7 -6
  322. package/{src/components/DataTable/examples → examples/DataTable}/HierarchicalExample.tsx +8 -6
  323. package/examples/{components 2/DataTable/PerformanceExample.tsx → DataTable/PerformanceExample.tsx} +2 -2
  324. package/examples/{components 2/DataTable/index.ts → DataTable/index.ts} +1 -0
  325. package/{src/components/Dialog/examples → examples/Dialog}/HtmlDialogExample.tsx +3 -3
  326. package/examples/{components 2/Dialog/ScrollableDialogExample.tsx → Dialog/ScrollableDialogExample.tsx} +1 -1
  327. package/{src/components/Dialog/examples → examples/Dialog}/SmartDialogExample.tsx +1 -1
  328. package/examples/{components 2/Dialog/index.ts → Dialog/index.ts} +0 -3
  329. package/examples/{features/public-pages → PublicPages}/CorrectPublicPageImplementation.tsx +52 -17
  330. package/examples/{features/public-pages → PublicPages}/PublicEventPage.tsx +65 -35
  331. package/examples/{features/public-pages → PublicPages}/PublicPageApp.tsx +52 -18
  332. package/examples/{features/public-pages → PublicPages}/PublicPageUsageExample.tsx +28 -15
  333. package/examples/README.md +81 -33
  334. package/examples/index.ts +14 -12
  335. package/examples/{RBAC → rbac}/CompleteRBACExample.tsx +1 -1
  336. package/examples/{features/rbac → rbac}/EventBasedApp.tsx +4 -4
  337. package/examples/{features/rbac → rbac}/PermissionExample.tsx +5 -3
  338. package/package.json +21 -27
  339. package/src/__tests__/helpers/test-utils.tsx +29 -3
  340. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +7 -5
  341. package/src/components/Alert/Alert.test.tsx +2 -2
  342. package/src/components/Alert/Alert.tsx +4 -4
  343. package/src/components/Avatar/Avatar.test.tsx +17 -6
  344. package/src/components/Badge/Badge.test.tsx +1 -1
  345. package/src/components/Badge/Badge.tsx +2 -2
  346. package/src/components/Button/Button.test.tsx +2 -2
  347. package/src/components/Button/Button.tsx +11 -7
  348. package/src/components/Calendar/Calendar.test.tsx +41 -8
  349. package/src/components/Calendar/Calendar.tsx +39 -36
  350. package/src/components/Card/Card.tsx +51 -13
  351. package/src/components/Checkbox/Checkbox.test.tsx +36 -12
  352. package/src/components/DataTable/DataTable.test.tsx +1 -1
  353. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +13 -7
  354. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +14 -42
  355. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +13 -10
  356. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +14 -11
  357. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +4 -2
  358. package/src/components/DataTable/__tests__/DataTable.test.tsx +13 -7
  359. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +13 -10
  360. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +15 -11
  361. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +12 -6
  362. package/src/components/DataTable/__tests__/keyboard.test.tsx +12 -6
  363. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +10 -6
  364. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +1 -1
  365. package/src/components/DataTable/components/DataTableBody.tsx +10 -25
  366. package/src/components/DataTable/components/DataTableCore.tsx +1 -1
  367. package/src/components/DataTable/components/FilterRow.tsx +3 -1
  368. package/src/components/DataTable/components/ImportModal.tsx +1 -1
  369. package/src/components/DataTable/components/VirtualizedDataTable.tsx +9 -9
  370. package/src/components/DataTable/core/ColumnFactory.ts +6 -6
  371. package/src/components/DataTable/core/DataTableContext.tsx +14 -10
  372. package/src/components/DataTable/core/LocalDataAdapter.ts +2 -1
  373. package/src/components/DataTable/core/PluginRegistry.ts +3 -3
  374. package/src/components/DataTable/core/StateManager.ts +12 -11
  375. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +104 -0
  376. package/src/components/DataTable/core/__tests__/DataManager.test.ts +101 -0
  377. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +84 -0
  378. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +102 -0
  379. package/src/components/DataTable/core/__tests__/StateManager.test.ts +104 -0
  380. package/src/components/DataTable/core/interfaces.ts +17 -17
  381. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +124 -0
  382. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +117 -0
  383. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +102 -0
  384. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +53 -0
  385. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +0 -2
  386. package/src/components/DataTable/hooks/useDataTablePermissions.ts +9 -8
  387. package/src/components/DataTable/types.ts +5 -5
  388. package/src/components/DataTable/utils/aggregationUtils.ts +4 -4
  389. package/src/components/DataTable/utils/columnUtils.ts +3 -2
  390. package/src/components/DataTable/utils/debugTools.ts +1 -1
  391. package/src/components/DataTable/utils/exportUtils.ts +6 -6
  392. package/src/components/DataTable/utils/hierarchicalSorting.ts +6 -6
  393. package/src/components/DataTable/utils/hierarchicalUtils.ts +0 -8
  394. package/src/components/DataTable/utils/index.ts +0 -1
  395. package/src/components/DataTable/utils/performanceUtils.ts +9 -4
  396. package/src/components/Dialog/Dialog.test.tsx +49 -27
  397. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +13 -8
  398. package/src/components/EventSelector/EventSelector.test.tsx +60 -12
  399. package/src/components/EventSelector/EventSelector.tsx +38 -15
  400. package/src/components/EventSelector/index.ts +2 -2
  401. package/src/components/FileDisplay/FileDisplay.test.tsx +143 -85
  402. package/src/components/FileDisplay/FileDisplay.tsx +1 -0
  403. package/src/components/FileUpload/FileUpload.test.tsx +532 -152
  404. package/src/components/FileUpload/FileUpload.tsx +43 -8
  405. package/src/components/Footer/Footer.test.tsx +19 -14
  406. package/src/components/Form/Form.test.tsx +96 -14
  407. package/src/components/Form/Form.tsx +210 -1
  408. package/src/components/Form/index.ts +3 -7
  409. package/src/components/Header/Header.test.tsx +24 -17
  410. package/src/components/Header/Header.tsx +3 -1
  411. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -4
  412. package/src/components/Input/Input.test.tsx +61 -36
  413. package/src/components/Label/{__tests__/Label.test.tsx → Label.test.tsx} +2 -2
  414. package/src/components/Label/Label.tsx +2 -3
  415. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +6 -5
  416. package/src/components/LoadingSpinner/LoadingSpinner.tsx +6 -2
  417. package/src/components/LoginForm/LoginForm.test.tsx +14 -13
  418. package/src/components/LoginForm/LoginForm.tsx +1 -1
  419. package/src/components/LoginForm/index.ts +7 -0
  420. package/src/components/NavigationMenu/NavigationMenu.test.tsx +233 -20
  421. package/src/components/NavigationMenu/NavigationMenu.tsx +191 -55
  422. package/src/components/NavigationMenu/index.ts +1 -1
  423. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +20 -11
  424. package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
  425. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.integration.test.tsx → PaceAppLayout.integration.test.tsx} +272 -79
  426. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.performance.test.tsx → PaceAppLayout.performance.test.tsx} +155 -32
  427. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.security.test.tsx → PaceAppLayout.security.test.tsx} +211 -65
  428. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +498 -210
  429. package/src/components/PaceAppLayout/PaceAppLayout.tsx +63 -64
  430. package/src/components/PaceAppLayout/test-setup.tsx +192 -0
  431. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +193 -39
  432. package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.test.tsx +2 -2
  433. package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.tsx +10 -4
  434. package/src/components/PasswordChange/index.ts +2 -0
  435. package/src/components/Progress/Progress.test.tsx +11 -0
  436. package/src/components/Progress/Progress.tsx +1 -1
  437. package/src/components/Progress/index.ts +10 -0
  438. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +2 -1
  439. package/src/components/PublicLayout/PublicLayout.test.tsx +1210 -0
  440. package/src/components/PublicLayout/PublicPageLayout.tsx +190 -36
  441. package/src/components/PublicLayout/PublicPageProvider.tsx +8 -7
  442. package/src/components/PublicLayout/index.ts +10 -28
  443. package/src/components/Select/Select.test.tsx +7 -7
  444. package/src/components/Select/Select.tsx +277 -11
  445. package/src/components/Select/index.ts +1 -2
  446. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +232 -0
  447. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +40 -19
  448. package/src/components/Table/{__tests__/Table.test.tsx → Table.test.tsx} +94 -41
  449. package/src/components/Tabs/Tabs.test.tsx +10 -9
  450. package/src/components/Tabs/Tabs.tsx +61 -33
  451. package/src/components/Textarea/Textarea.test.tsx +31 -18
  452. package/src/components/Toast/Toast.tsx +2 -2
  453. package/src/components/Tooltip/Tooltip.test.tsx +1 -1
  454. package/src/components/UserMenu/UserMenu.test.tsx +7 -6
  455. package/src/components/UserMenu/UserMenu.tsx +2 -2
  456. package/src/components/index.ts +5 -4
  457. package/src/constants/performance.ts +19 -8
  458. package/src/hooks/__tests__/useAppConfig.unit.test.ts +21 -22
  459. package/src/hooks/__tests__/useEvents.unit.test.ts +5 -4
  460. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
  461. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -0
  462. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +16 -11
  463. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -3
  464. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +1 -3
  465. package/src/hooks/__tests__/useRBAC.unit.test.ts +24 -2
  466. package/src/hooks/index.ts +4 -0
  467. package/src/hooks/public/index.ts +2 -0
  468. package/src/hooks/public/usePublicEvent.ts +4 -6
  469. package/src/hooks/public/usePublicRouteParams.ts +1 -1
  470. package/src/hooks/services/useAuth.ts +2 -4
  471. package/src/hooks/services/useCurrentEvent.ts +1 -1
  472. package/src/hooks/useAppConfig.ts +1 -1
  473. package/src/hooks/useDataTablePerformance.ts +2 -2
  474. package/src/hooks/useEventTheme.ts +1 -1
  475. package/src/hooks/useEvents.ts +51 -10
  476. package/src/hooks/useOrganisationPermissions.test.ts +3 -3
  477. package/src/hooks/useOrganisationPermissions.ts +1 -1
  478. package/src/hooks/useOrganisationSecurity.ts +2 -2
  479. package/src/hooks/usePermissionCache.test.ts +9 -9
  480. package/src/hooks/usePermissionCache.ts +2 -2
  481. package/src/index.ts +19 -12
  482. package/src/providers/OrganisationProvider.tsx +73 -9
  483. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +113 -13
  484. package/src/providers/__tests__/AuthProvider.test.tsx +2 -1
  485. package/src/providers/__tests__/EventProvider.test.tsx +24 -15
  486. package/src/providers/__tests__/OrganisationProvider.test.tsx +87 -36
  487. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +80 -24
  488. package/src/providers/index.ts +0 -3
  489. package/src/providers/services/AuthServiceProvider.tsx +2 -17
  490. package/src/providers/services/EventServiceProvider.tsx +11 -16
  491. package/src/providers/services/InactivityServiceProvider.tsx +9 -12
  492. package/src/providers/services/OrganisationServiceProvider.tsx +9 -12
  493. package/src/providers/services/UnifiedAuthProvider.tsx +85 -18
  494. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +11 -4
  495. package/src/rbac/__tests__/scenarios.user-role.test.tsx +105 -21
  496. package/src/rbac/adapters.tsx +1 -1
  497. package/src/rbac/api.ts +20 -4
  498. package/src/rbac/audit-enhanced.ts +47 -2
  499. package/src/rbac/audit.ts +47 -2
  500. package/src/rbac/components/NavigationGuard.tsx +1 -1
  501. package/src/rbac/components/NavigationProvider.test.tsx +7 -6
  502. package/src/rbac/components/NavigationProvider.tsx +1 -1
  503. package/src/rbac/components/PagePermissionGuard.tsx +1 -1
  504. package/src/rbac/components/PagePermissionProvider.test.tsx +7 -6
  505. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  506. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  507. package/src/rbac/components/RoleBasedRouter.tsx +1 -1
  508. package/src/rbac/components/SecureDataProvider.test.tsx +7 -6
  509. package/src/rbac/components/SecureDataProvider.tsx +1 -1
  510. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +6 -6
  511. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +11 -10
  512. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +10 -11
  513. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +19 -15
  514. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +13 -12
  515. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +19 -15
  516. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +18 -18
  517. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +11 -10
  518. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +8 -7
  519. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +10 -11
  520. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +48 -19
  521. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +476 -0
  522. package/src/rbac/hooks/index.ts +3 -0
  523. package/src/rbac/hooks/usePermissions.ts +31 -85
  524. package/src/rbac/hooks/useRBAC.test.ts +13 -1
  525. package/src/rbac/hooks/useRBAC.ts +13 -67
  526. package/src/rbac/hooks/useResolvedScope.ts +11 -0
  527. package/src/rbac/hooks/useSecureSupabase.ts +308 -0
  528. package/src/rbac/index.ts +3 -0
  529. package/src/rbac/secureClient.ts +53 -6
  530. package/src/rbac/security.ts +37 -1
  531. package/src/{types/rbac-functions.ts → rbac/types/functions.ts} +30 -30
  532. package/src/rbac/types.ts +3 -2
  533. package/src/services/AuthService.ts +33 -25
  534. package/src/services/EventService.ts +56 -44
  535. package/src/services/InactivityService.ts +33 -53
  536. package/src/services/OrganisationService.ts +36 -40
  537. package/src/services/__tests__/AuthService.restoreSession.test.ts +6 -2
  538. package/src/services/__tests__/EventService.test.ts +67 -33
  539. package/src/services/interfaces/IEventService.ts +1 -1
  540. package/src/styles/core.css +2 -2
  541. package/src/styles/index.ts +1 -5
  542. package/src/types/__tests__/guards.test.ts +1 -1
  543. package/src/types/__tests__/type-validation.test.ts +0 -1
  544. package/src/types/auth.ts +42 -2
  545. package/src/types/core.ts +251 -0
  546. package/src/types/database.ts +11 -496
  547. package/src/types/event.ts +102 -0
  548. package/src/types/file-reference.ts +6 -4
  549. package/src/types/guards.ts +2 -1
  550. package/src/types/index.ts +48 -14
  551. package/src/types/lodash.debounce.d.ts +15 -0
  552. package/src/types/organisation.ts +14 -10
  553. package/src/types/supabase.ts +15 -17
  554. package/src/utils/__tests__/secureErrors.unit.test.ts +1 -1
  555. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -29
  556. package/src/utils/app/appNameResolver.ts +1 -1
  557. package/src/utils/dynamic/dynamicUtils.ts +3 -2
  558. package/src/utils/file-reference/index.ts +25 -6
  559. package/src/utils/security/secureErrors.ts +1 -1
  560. package/src/utils/validation/index.ts +6 -12
  561. package/src/utils/validation/validationUtils.ts +0 -13
  562. package/dist/UnifiedAuthProvider-B37ATQHE.js +0 -16
  563. package/dist/auth-DReDSLq9.d.ts +0 -16
  564. package/dist/chunk-3JI76CYK.js +0 -2444
  565. package/dist/chunk-3JI76CYK.js.map +0 -1
  566. package/dist/chunk-56XJ3TU6.js +0 -11
  567. package/dist/chunk-56XJ3TU6.js.map +0 -1
  568. package/dist/chunk-5MT24GKJ.js.map +0 -1
  569. package/dist/chunk-7QCC6MCP.js +0 -288
  570. package/dist/chunk-BESYRHQM.js.map +0 -1
  571. package/dist/chunk-BJPBT3CU.js +0 -21
  572. package/dist/chunk-BJPBT3CU.js.map +0 -1
  573. package/dist/chunk-BVYWGZVV.js.map +0 -1
  574. package/dist/chunk-CX5M4ZAG.js.map +0 -1
  575. package/dist/chunk-D7LCGMVS.js.map +0 -1
  576. package/dist/chunk-EGI6MUL6.js +0 -27
  577. package/dist/chunk-EGI6MUL6.js.map +0 -1
  578. package/dist/chunk-ERISIBYU.js.map +0 -1
  579. package/dist/chunk-HRO5HWN2.js.map +0 -1
  580. package/dist/chunk-HZLDFOE4.js.map +0 -1
  581. package/dist/chunk-JISYG63F.js +0 -70
  582. package/dist/chunk-JISYG63F.js.map +0 -1
  583. package/dist/chunk-LIMSTKYD.js +0 -61
  584. package/dist/chunk-LIMSTKYD.js.map +0 -1
  585. package/dist/chunk-OWAG3GSU.js.map +0 -1
  586. package/dist/chunk-PPMP5J6T.js.map +0 -1
  587. package/dist/chunk-Q5QRDWKI.js.map +0 -1
  588. package/dist/chunk-S5OFRT4M.js.map +0 -1
  589. package/dist/chunk-SBVILCCA.js.map +0 -1
  590. package/dist/chunk-TUMEWN34.js +0 -15
  591. package/dist/chunk-TUMEWN34.js.map +0 -1
  592. package/dist/chunk-XDNLUEXI.js +0 -138
  593. package/dist/chunk-XJ2HZOBU.js.map +0 -1
  594. package/dist/chunk-ZYTYSTO5.js.map +0 -1
  595. package/dist/chunk-ZZ2SS7NI.js +0 -237
  596. package/dist/chunk-ZZ2SS7NI.js.map +0 -1
  597. package/dist/database-C6jy7EOu.d.ts +0 -500
  598. package/dist/organisation-D6qRDtbF.d.ts +0 -93
  599. package/dist/schema-DTDZQe2u.d.ts +0 -28
  600. package/dist/unified-DQ4VcT7H.d.ts +0 -198
  601. package/dist/useInactivityTracker-TO6ZOF35.js +0 -11
  602. package/dist/validation.d.ts +0 -47
  603. package/dist/validation.js +0 -24
  604. package/dist/validation.js.map +0 -1
  605. package/docs/DOCUMENTATION_AUDIT.md +0 -172
  606. package/docs/DOCUMENTATION_STANDARD.md +0 -137
  607. package/docs/api/classes/PublicErrorBoundary.md +0 -132
  608. package/docs/api/interfaces/EventLogoProps.md +0 -152
  609. package/docs/api/interfaces/PublicErrorBoundaryProps.md +0 -94
  610. package/docs/api/interfaces/PublicErrorBoundaryState.md +0 -68
  611. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +0 -86
  612. package/docs/architecture/rpc-function-standards.md +0 -1106
  613. package/docs/getting-started/consuming-app-vite-config.md +0 -239
  614. package/docs/implementation-guides/event-theming-summary.md +0 -226
  615. package/docs/implementation-guides/public-pages-advanced.md +0 -1038
  616. package/docs/migration/v0.4.15-tailwind-scanning.md +0 -278
  617. package/docs/migration/v0.4.16-css-first-approach.md +0 -312
  618. package/docs/migration/v0.4.17-source-path-fix.md +0 -235
  619. package/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +0 -222
  620. package/docs/rbac/RBAC_LOGIN_SAFETY_FIX.md +0 -95
  621. package/docs/rbac/RBAC_V0.5.147_FIX.md +0 -117
  622. package/docs/rbac/README-rbac-rls-integration.md +0 -374
  623. package/docs/styles/usage.md +0 -227
  624. package/docs/testing/visual-testing.md +0 -120
  625. package/docs/troubleshooting/DEBUG_NETWORK_ERROR.md +0 -152
  626. package/docs/troubleshooting/FIX_SUPABASE_CORS.md +0 -184
  627. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +0 -193
  628. package/docs/troubleshooting/database-view-compatibility.md +0 -125
  629. package/docs/troubleshooting/react-hooks-issue-analysis.md +0 -172
  630. package/docs/troubleshooting/tailwind-content-scanning.md +0 -219
  631. package/examples/RBAC/EventBasedApp.tsx +0 -239
  632. package/examples/RBAC/PermissionExample.tsx +0 -151
  633. package/examples/STRUCTURE.md +0 -125
  634. package/examples/components 2/DataTable/HierarchicalExample.tsx +0 -475
  635. package/examples/components 2/Dialog/BasicHtmlTest.tsx +0 -55
  636. package/examples/components 2/Dialog/DebugHtmlExample.tsx +0 -68
  637. package/examples/components 2/Dialog/HtmlDialogExample.tsx +0 -202
  638. package/examples/components 2/Dialog/SimpleHtmlTest.tsx +0 -61
  639. package/examples/components 2/Dialog/SmartDialogExample.tsx +0 -322
  640. package/examples/components 2/index.ts +0 -11
  641. package/examples/features/index.ts +0 -12
  642. package/examples/features/rbac/CompleteRBACExample.tsx +0 -324
  643. package/examples/features/rbac/index.ts +0 -13
  644. package/examples/public-pages/CorrectPublicPageImplementation.tsx +0 -301
  645. package/examples/public-pages/PublicEventPage.tsx +0 -274
  646. package/examples/public-pages/PublicPageApp.tsx +0 -308
  647. package/examples/public-pages/PublicPageUsageExample.tsx +0 -216
  648. package/examples/public-pages/index.ts +0 -14
  649. package/src/__tests__/TEST_STANDARD.md +0 -1008
  650. package/src/components/Checkbox/__mocks__/Checkbox.tsx +0 -2
  651. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +0 -421
  652. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +0 -177
  653. package/src/components/DataTable/examples/PerformanceExample.tsx +0 -506
  654. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +0 -316
  655. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +0 -45
  656. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +0 -211
  657. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +0 -126
  658. package/src/components/Dialog/README.md +0 -804
  659. package/src/components/Dialog/examples/BasicHtmlTest.tsx +0 -55
  660. package/src/components/Dialog/examples/DebugHtmlExample.tsx +0 -68
  661. package/src/components/Dialog/examples/ScrollableDialogExample.tsx +0 -290
  662. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +0 -61
  663. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +0 -71
  664. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +0 -122
  665. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -147
  666. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
  667. package/src/components/Dialog/utils/safeHtml.ts +0 -185
  668. package/src/components/EventSelector/types.ts +0 -79
  669. package/src/components/Form/FormErrorSummary.tsx +0 -113
  670. package/src/components/Form/FormField.tsx +0 -249
  671. package/src/components/Form/FormFieldset.tsx +0 -127
  672. package/src/components/Form/FormLiveRegion.tsx +0 -198
  673. package/src/components/Input/__mocks__/Input.tsx +0 -2
  674. package/src/components/NavigationMenu/types.ts +0 -85
  675. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -326
  676. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -1078
  677. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  678. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  679. package/src/components/PasswordReset/index.ts +0 -2
  680. package/src/components/ProtectedRoute/README.md +0 -164
  681. package/src/components/PublicLayout/EventLogo.tsx +0 -175
  682. package/src/components/PublicLayout/PublicErrorBoundary.tsx +0 -282
  683. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +0 -216
  684. package/src/components/PublicLayout/PublicPageContextChecker.tsx +0 -131
  685. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  686. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  687. package/src/components/PublicLayout/PublicPageFooter.tsx +0 -124
  688. package/src/components/PublicLayout/PublicPageHeader.tsx +0 -209
  689. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -449
  690. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -393
  691. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +0 -192
  692. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -351
  693. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -402
  694. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -460
  695. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -313
  696. package/src/components/Select/hooks.ts +0 -289
  697. package/src/hooks/useCounter.test.ts +0 -131
  698. package/src/hooks/useDebounce.test.ts +0 -375
  699. package/src/providers/AuthProvider.tsx +0 -15
  700. package/src/providers/EventProvider.tsx +0 -16
  701. package/src/providers/InactivityProvider.tsx +0 -15
  702. package/src/providers/OrganisationProvider.context.test.tsx +0 -169
  703. package/src/providers/UnifiedAuthProvider.tsx +0 -15
  704. package/src/types/theme.ts +0 -6
  705. package/src/types/unified.ts +0 -265
  706. package/src/utils/appConfig.ts +0 -47
  707. package/src/utils/appIdResolver.test.ts +0 -499
  708. package/src/utils/appIdResolver.ts +0 -130
  709. package/src/utils/appNameResolver.simple.test.ts +0 -212
  710. package/src/utils/appNameResolver.test.ts +0 -121
  711. package/src/utils/appNameResolver.ts +0 -191
  712. package/src/utils/audit.ts +0 -127
  713. package/src/utils/auth-utils.ts +0 -96
  714. package/src/utils/bundleAnalysis.ts +0 -129
  715. package/src/utils/debugLogger.ts +0 -67
  716. package/src/utils/deviceFingerprint.ts +0 -215
  717. package/src/utils/dynamicUtils.ts +0 -105
  718. package/src/utils/file-reference.test.ts +0 -788
  719. package/src/utils/file-reference.ts +0 -519
  720. package/src/utils/formatDate.test.ts +0 -237
  721. package/src/utils/formatting.ts +0 -170
  722. package/src/utils/lazyLoad.tsx +0 -44
  723. package/src/utils/logger.ts +0 -179
  724. package/src/utils/organisationContext.test.ts +0 -322
  725. package/src/utils/organisationContext.ts +0 -153
  726. package/src/utils/performanceBenchmark.ts +0 -64
  727. package/src/utils/performanceBudgets.ts +0 -110
  728. package/src/utils/permissionTypes.ts +0 -37
  729. package/src/utils/permissionUtils.test.ts +0 -393
  730. package/src/utils/permissionUtils.ts +0 -34
  731. package/src/utils/sanitization.ts +0 -264
  732. package/src/utils/schemaUtils.ts +0 -37
  733. package/src/utils/secureDataAccess.test.ts +0 -711
  734. package/src/utils/secureDataAccess.ts +0 -377
  735. package/src/utils/secureErrors.ts +0 -79
  736. package/src/utils/security.ts +0 -156
  737. package/src/utils/securityMonitor.ts +0 -45
  738. package/src/utils/sessionTracking.ts +0 -126
  739. package/src/utils/validation.ts +0 -111
  740. package/src/utils/validationUtils.ts +0 -120
  741. package/src/validation/index.ts +0 -12
  742. /package/dist/{DataTable-UA6CL4JI.js.map → DataTable-QAB34V6K.js.map} +0 -0
  743. /package/dist/{UnifiedAuthProvider-B37ATQHE.js.map → UnifiedAuthProvider-7F6T4B6K.js.map} +0 -0
  744. /package/dist/{api-45XYYO2A.js.map → api-ROMBCNKU.js.map} +0 -0
  745. /package/dist/{audit-64X3VJXB.js.map → audit-WRS3KJKI.js.map} +0 -0
  746. /package/dist/{chunk-PLDDJCW6.js.map → chunk-7D4SUZUM.js.map} +0 -0
  747. /package/dist/{useInactivityTracker-TO6ZOF35.js.map → chunk-KQCRWDSA.js.map} +0 -0
  748. /package/examples/{components 2/DataTable → DataTable}/InitialPageSizeExample.tsx +0 -0
  749. /package/examples/{features/public-pages → PublicPages}/index.ts +0 -0
  750. /package/examples/{RBAC → rbac}/index.ts +0 -0
@@ -2,6 +2,11 @@
2
2
  * @file PaceAppLayout Component Tests
3
3
  * @description Comprehensive test suite for PaceAppLayout component
4
4
  * @package @jmruthers/pace-core
5
+ * @module Components/PaceAppLayout
6
+ * @since 0.1.0
7
+ *
8
+ * Comprehensive test suite for PaceAppLayout component following testing guidelines.
9
+ * Tests cover all major functionality, edge cases, and user interactions.
5
10
  */
6
11
 
7
12
  import React from 'react';
@@ -11,11 +16,27 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
11
16
  import { MemoryRouter } from 'react-router-dom';
12
17
  import { PaceAppLayout } from './PaceAppLayout';
13
18
  import { renderWithProviders } from '../../__tests__/helpers/test-utils';
14
- import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
19
+ import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
20
+ import {
21
+ mockNavigate,
22
+ mockLocation,
23
+ mockUser,
24
+ mockSignOut,
25
+ mockUpdatePassword,
26
+ mockOrganisation,
27
+ mockOrganisationContext,
28
+ mockIsPermitted,
29
+ mockHasPermissionRBAC,
30
+ mockUseRBAC,
31
+ mockUseCan,
32
+ resetPaceAppLayoutMocks,
33
+ } from './test-setup.tsx';
15
34
 
16
- // Mock React Router hooks
17
- const mockNavigate = vi.fn();
18
- const mockLocation = { pathname: '/dashboard' };
35
+ // Import the hoisted mock for isSuperAdmin
36
+ let mockIsSuperAdmin: ReturnType<typeof vi.fn>;
37
+
38
+ // Override mockLocation pathname for this test file
39
+ mockLocation.pathname = '/dashboard';
19
40
 
20
41
  vi.mock('react-router-dom', async () => {
21
42
  const actual = await vi.importActual('react-router-dom');
@@ -28,62 +49,27 @@ vi.mock('react-router-dom', async () => {
28
49
  });
29
50
 
30
51
  // Mock UnifiedAuth hook
31
- const mockUser = {
32
- id: 'user-123',
33
- email: 'test@example.com',
34
- user_metadata: {
35
- organisationId: 'org-123',
36
- eventId: 'event-123',
37
- appId: 'app-123',
38
- is_admin: false,
39
- },
40
- app_metadata: {
41
- organisationId: 'org-123',
42
- eventId: 'event-123',
43
- appId: 'app-123',
44
- },
45
- };
46
-
47
52
  const mockUnifiedAuth = {
48
- user: mockUser,
49
- signOut: vi.fn().mockResolvedValue(undefined),
50
- updatePassword: vi.fn().mockResolvedValue({ error: null }),
53
+ user: { ...mockUser, id: 'user-123', user_metadata: { ...mockUser.user_metadata, is_admin: false }, app_metadata: { organisationId: 'org-123', eventId: 'event-123', appId: 'app-123' } },
54
+ signOut: mockSignOut,
55
+ updatePassword: mockUpdatePassword,
51
56
  };
52
57
 
53
- vi.mock('../../providers/UnifiedAuthProvider', () => ({
54
- useUnifiedAuth: vi.fn(() => mockUnifiedAuth),
58
+ const mockUseUnifiedAuthFn = vi.fn(() => mockUnifiedAuth);
59
+ vi.mock('../../providers/services/UnifiedAuthProvider', () => ({
60
+ useUnifiedAuth: () => mockUseUnifiedAuthFn(),
61
+ UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
55
62
  }));
56
63
 
57
64
  // Mock useOrganisations hook
58
- const mockSelectedOrganisation = {
59
- id: 'org-123',
60
- name: 'Test Organisation',
61
- display_name: 'Test Organisation',
62
- slug: 'test-org',
63
- description: 'Test organisation',
64
- subscription_tier: 'basic',
65
- settings: {},
66
- is_active: true,
67
- created_at: '2023-01-01T00:00:00Z',
68
- updated_at: '2023-01-01T00:00:00Z',
69
- };
65
+ const mockSelectedOrganisation = { ...mockOrganisation, id: 'org-123', slug: 'test-org' };
70
66
 
71
67
  vi.mock('../../hooks/useOrganisations', () => ({
72
68
  useOrganisations: vi.fn(() => ({
69
+ ...mockOrganisationContext,
73
70
  selectedOrganisation: mockSelectedOrganisation,
74
71
  organisations: [mockSelectedOrganisation],
75
72
  userMemberships: [],
76
- isLoading: false,
77
- error: null,
78
- hasValidOrganisationContext: true,
79
- setSelectedOrganisation: vi.fn(),
80
- switchOrganisation: vi.fn().mockResolvedValue(undefined),
81
- getUserRole: vi.fn().mockReturnValue('member'),
82
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
83
- ensureOrganisationContext: vi.fn().mockReturnValue(mockSelectedOrganisation),
84
- refreshOrganisations: vi.fn().mockResolvedValue(undefined),
85
- getPrimaryOrganisation: vi.fn().mockReturnValue(mockSelectedOrganisation),
86
- isOrganisationSecure: vi.fn().mockReturnValue(true),
87
73
  })),
88
74
  }));
89
75
 
@@ -102,48 +88,108 @@ vi.mock('../../hooks/useEventTheme', () => ({
102
88
  useEventTheme: vi.fn(),
103
89
  }));
104
90
 
91
+ // Mock logger
92
+ // Note: Must define mock inside factory to avoid hoisting issues
93
+ vi.mock('../../utils/core/logger', () => {
94
+ const mockLogger = {
95
+ debug: vi.fn(),
96
+ info: vi.fn(),
97
+ warn: vi.fn(),
98
+ error: vi.fn(),
99
+ createScopedLogger: vi.fn(() => mockLogger),
100
+ configure: vi.fn(),
101
+ };
102
+
103
+ return {
104
+ logger: mockLogger,
105
+ createLogger: () => mockLogger,
106
+ Logger: {
107
+ debug: vi.fn(),
108
+ info: vi.fn(),
109
+ warn: vi.fn(),
110
+ error: vi.fn(),
111
+ configure: vi.fn(),
112
+ createScopedLogger: vi.fn(() => mockLogger),
113
+ },
114
+ LogLevel: {
115
+ DEBUG: 0,
116
+ INFO: 1,
117
+ WARN: 2,
118
+ ERROR: 3,
119
+ },
120
+ };
121
+ });
122
+
123
+ // Mock EventServiceProvider to avoid context requirement
124
+ vi.mock('../../providers/services/EventServiceProvider', () => ({
125
+ EventServiceProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
126
+ useEventService: vi.fn(() => ({
127
+ getEvent: vi.fn(),
128
+ getEvents: vi.fn(),
129
+ createEvent: vi.fn(),
130
+ updateEvent: vi.fn(),
131
+ deleteEvent: vi.fn(),
132
+ })),
133
+ }));
134
+
135
+ // Mock Supabase client for RBAC engine
136
+ // Note: Must define mock inside factory to avoid hoisting issues
137
+ vi.mock('@supabase/supabase-js', () => {
138
+ const createMockQueryBuilder = () => ({
139
+ select: vi.fn().mockReturnThis(),
140
+ eq: vi.fn().mockReturnThis(),
141
+ single: vi.fn().mockResolvedValue({ data: null, error: null }),
142
+ });
143
+
144
+ const mockSupabaseClient = {
145
+ from: vi.fn(() => createMockQueryBuilder()),
146
+ rpc: vi.fn().mockResolvedValue({ data: null, error: null }),
147
+ };
148
+
149
+ return {
150
+ createClient: vi.fn(() => mockSupabaseClient),
151
+ };
152
+ });
153
+
105
154
  // Mock RBAC functions
106
- const mockIsPermitted = vi.fn().mockResolvedValue(true);
107
- const mockIsPermittedCached = vi.fn().mockResolvedValue(true);
108
- const mockIsSuperAdmin = vi.fn().mockResolvedValue(false);
155
+ // Use hoisted mock for isSuperAdmin so it can be accessed in tests
156
+ const mockIsSuperAdminAPI = vi.hoisted(() => vi.fn().mockResolvedValue(false));
109
157
 
110
158
  vi.mock('../../rbac/api', () => ({
111
- isPermitted: vi.fn(),
112
- isPermittedCached: vi.fn(),
113
- isSuperAdmin: (...args: any[]) => mockIsSuperAdmin(...args),
159
+ isPermitted: vi.fn().mockResolvedValue(true),
160
+ isPermittedCached: vi.fn().mockResolvedValue(true),
161
+ isSuperAdmin: mockIsSuperAdminAPI,
114
162
  setupRBAC: vi.fn(),
115
- }));
116
-
117
- // Mock useCan hook - this is what PaceAppLayout actually uses
118
- const mockUseCan = vi.fn(() => ({
119
- can: true,
120
- isLoading: false,
121
- error: null,
122
- refetch: vi.fn().mockResolvedValue(undefined),
163
+ getPermissionMap: vi.fn().mockResolvedValue({}),
164
+ getAccessLevel: vi.fn().mockResolvedValue('viewer'),
123
165
  }));
124
166
 
125
167
  // Mock RBAC hooks
126
- const mockHasPermissionFn = vi.fn().mockResolvedValue(true);
127
- vi.mock('../../rbac/hooks', () => ({
128
- useRBAC: vi.fn(() => ({
129
- hasPermission: mockHasPermissionFn,
130
- isLoading: false,
131
- error: null,
132
- hasGlobalPermission: vi.fn().mockResolvedValue(true),
133
- hasOrganisationPermission: vi.fn().mockResolvedValue(true),
134
- hasEventPermission: vi.fn().mockResolvedValue(true),
135
- globalRole: null,
136
- organisationRoles: [],
137
- eventRoles: [],
138
- permissionMap: {},
139
- })),
140
- useCan: (...args: any[]) => mockUseCan(...args),
141
- useResolvedScope: vi.fn(() => ({
142
- resolvedScope: { organisationId: 'org-123', eventId: 'event-123', appId: 'app-123' },
143
- isLoading: false,
144
- error: null,
145
- })),
146
- }));
168
+ // Note: Must use function syntax in factory to avoid hoisting issues
169
+ // Import mockUseCan from test-setup so tests can control it
170
+ vi.mock('../../rbac/hooks', async () => {
171
+ const testSetup = await import('./test-setup.tsx');
172
+ return {
173
+ useRBAC: vi.fn(() => ({
174
+ hasPermission: vi.fn().mockResolvedValue(true),
175
+ isLoading: false,
176
+ error: null,
177
+ hasGlobalPermission: vi.fn().mockResolvedValue(true),
178
+ hasOrganisationPermission: vi.fn().mockResolvedValue(true),
179
+ hasEventPermission: vi.fn().mockResolvedValue(true),
180
+ globalRole: null,
181
+ organisationRoles: [],
182
+ eventRoles: [],
183
+ permissionMap: {},
184
+ })),
185
+ useCan: (...args: any[]) => testSetup.mockUseCan(...args),
186
+ useResolvedScope: vi.fn(() => ({
187
+ resolvedScope: { organisationId: 'org-123', eventId: 'event-123', appId: 'app-123' },
188
+ isLoading: false,
189
+ error: null,
190
+ })),
191
+ };
192
+ });
147
193
 
148
194
  // Mock Header component
149
195
  vi.mock('../Header', () => ({
@@ -232,27 +278,18 @@ describe('PaceAppLayout Component', () => {
232
278
  };
233
279
 
234
280
  beforeEach(async () => {
235
- vi.clearAllMocks();
236
- // Reset location mock
281
+ resetPaceAppLayoutMocks();
282
+ // Reset location mock for this test file
237
283
  mockLocation.pathname = '/dashboard';
238
- // Reset RBAC hook mocks
239
- mockHasPermissionFn.mockClear();
240
- mockHasPermissionFn.mockResolvedValue(true);
241
- mockUseCan.mockReturnValue({
242
- can: true,
243
- isLoading: false,
244
- error: null,
245
- refetch: vi.fn().mockResolvedValue(undefined),
246
- });
284
+ // Get the mocked isSuperAdmin function
285
+ const rbacApi = await import('../../rbac/api');
286
+ mockIsSuperAdmin = vi.mocked(rbacApi.isSuperAdmin);
247
287
  // Reset RBAC API mocks
248
288
  const { isPermitted, isPermittedCached } = await import('../../rbac/api');
249
289
  vi.mocked(isPermitted).mockReset();
250
290
  vi.mocked(isPermitted).mockResolvedValue(true);
251
291
  vi.mocked(isPermittedCached).mockReset();
252
292
  vi.mocked(isPermittedCached).mockResolvedValue(true);
253
- // Reset super admin mock (use module-level mockIsSuperAdmin)
254
- mockIsSuperAdmin.mockReset();
255
- mockIsSuperAdmin.mockResolvedValue(false);
256
293
  });
257
294
 
258
295
  describe('Basic Rendering', () => {
@@ -260,7 +297,8 @@ describe('PaceAppLayout Component', () => {
260
297
  renderWithProviders(
261
298
  <TestWrapper>
262
299
  <PaceAppLayout {...defaultProps} />
263
- </TestWrapper>
300
+ </TestWrapper>,
301
+ { withRouter: false }
264
302
  );
265
303
 
266
304
  expect(screen.getByTestId('header')).toBeInTheDocument();
@@ -272,7 +310,8 @@ describe('PaceAppLayout Component', () => {
272
310
  renderWithProviders(
273
311
  <TestWrapper>
274
312
  <PaceAppLayout {...defaultProps} appName="Custom App" />
275
- </TestWrapper>
313
+ </TestWrapper>,
314
+ { withRouter: false }
276
315
  );
277
316
 
278
317
  expect(screen.getByTestId('header-logo')).toHaveAttribute('data-logo-alt', 'Custom App Logo');
@@ -287,7 +326,8 @@ describe('PaceAppLayout Component', () => {
287
326
  renderWithProviders(
288
327
  <TestWrapper>
289
328
  <PaceAppLayout {...defaultProps} navItems={customNavItems} />
290
- </TestWrapper>
329
+ </TestWrapper>,
330
+ { withRouter: false }
291
331
  );
292
332
 
293
333
  expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
@@ -298,7 +338,8 @@ describe('PaceAppLayout Component', () => {
298
338
  renderWithProviders(
299
339
  <TestWrapper>
300
340
  <PaceAppLayout {...defaultProps} />
301
- </TestWrapper>
341
+ </TestWrapper>,
342
+ { withRouter: false }
302
343
  );
303
344
 
304
345
  expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
@@ -312,7 +353,8 @@ describe('PaceAppLayout Component', () => {
312
353
  renderWithProviders(
313
354
  <TestWrapper>
314
355
  <PaceAppLayout {...defaultProps} headerActions={headerActions} />
315
- </TestWrapper>
356
+ </TestWrapper>,
357
+ { withRouter: false }
316
358
  );
317
359
 
318
360
  expect(screen.getByTestId('custom-actions')).toBeInTheDocument();
@@ -324,7 +366,8 @@ describe('PaceAppLayout Component', () => {
324
366
  renderWithProviders(
325
367
  <TestWrapper>
326
368
  <PaceAppLayout {...defaultProps} customLogo={customLogo} />
327
- </TestWrapper>
369
+ </TestWrapper>,
370
+ { withRouter: false }
328
371
  );
329
372
 
330
373
  expect(screen.getByTestId('custom-logo')).toBeInTheDocument();
@@ -336,7 +379,8 @@ describe('PaceAppLayout Component', () => {
336
379
  renderWithProviders(
337
380
  <TestWrapper>
338
381
  <PaceAppLayout {...defaultProps} customUserMenu={customUserMenu} />
339
- </TestWrapper>
382
+ </TestWrapper>,
383
+ { withRouter: false }
340
384
  );
341
385
 
342
386
  expect(screen.getByTestId('custom-user-menu')).toBeInTheDocument();
@@ -346,10 +390,25 @@ describe('PaceAppLayout Component', () => {
346
390
  renderWithProviders(
347
391
  <TestWrapper>
348
392
  <PaceAppLayout {...defaultProps} headerClassName="custom-header" />
349
- </TestWrapper>
393
+ </TestWrapper>,
394
+ { withRouter: false }
395
+ );
396
+
397
+ const header = screen.getByTestId('header');
398
+ expect(header).toBeInTheDocument();
399
+ expect(header).toBeVisible();
400
+ });
401
+
402
+ it('uses default header className when not provided', () => {
403
+ renderWithProviders(
404
+ <TestWrapper>
405
+ <PaceAppLayout {...defaultProps} />
406
+ </TestWrapper>,
407
+ { withRouter: false }
350
408
  );
351
409
 
352
- expect(screen.getByTestId('header')).toHaveClass('custom-header');
410
+ const header = screen.getByTestId('header');
411
+ expect(header).toHaveClass('sticky', 'top-0', 'z-[40]', 'w-full');
353
412
  });
354
413
  });
355
414
 
@@ -358,7 +417,8 @@ describe('PaceAppLayout Component', () => {
358
417
  renderWithProviders(
359
418
  <TestWrapper>
360
419
  <PaceAppLayout {...defaultProps} />
361
- </TestWrapper>
420
+ </TestWrapper>,
421
+ { withRouter: false }
362
422
  );
363
423
 
364
424
  expect(screen.getByTestId('header')).toHaveAttribute('data-show-event-selector', 'true');
@@ -368,11 +428,23 @@ describe('PaceAppLayout Component', () => {
368
428
  renderWithProviders(
369
429
  <TestWrapper>
370
430
  <PaceAppLayout {...defaultProps} showEventSelector={false} />
371
- </TestWrapper>
431
+ </TestWrapper>,
432
+ { withRouter: false }
372
433
  );
373
434
 
374
435
  expect(screen.getByTestId('header')).toHaveAttribute('data-show-event-selector', 'false');
375
436
  });
437
+
438
+ it('shows event selector when showEventSelector is explicitly true', () => {
439
+ renderWithProviders(
440
+ <TestWrapper>
441
+ <PaceAppLayout {...defaultProps} showEventSelector={true} />
442
+ </TestWrapper>,
443
+ { withRouter: false }
444
+ );
445
+
446
+ expect(screen.getByTestId('header')).toHaveAttribute('data-show-event-selector', 'true');
447
+ });
376
448
  });
377
449
 
378
450
  describe('User Menu Control', () => {
@@ -380,7 +452,8 @@ describe('PaceAppLayout Component', () => {
380
452
  renderWithProviders(
381
453
  <TestWrapper>
382
454
  <PaceAppLayout {...defaultProps} />
383
- </TestWrapper>
455
+ </TestWrapper>,
456
+ { withRouter: false }
384
457
  );
385
458
 
386
459
  expect(screen.getByTestId('header')).toHaveAttribute('data-show-user-menu', 'true');
@@ -390,7 +463,8 @@ describe('PaceAppLayout Component', () => {
390
463
  renderWithProviders(
391
464
  <TestWrapper>
392
465
  <PaceAppLayout {...defaultProps} showUserMenu={false} />
393
- </TestWrapper>
466
+ </TestWrapper>,
467
+ { withRouter: false }
394
468
  );
395
469
 
396
470
  expect(screen.getByTestId('header')).toHaveAttribute('data-show-user-menu', 'false');
@@ -403,7 +477,8 @@ describe('PaceAppLayout Component', () => {
403
477
  renderWithProviders(
404
478
  <TestWrapper>
405
479
  <PaceAppLayout {...defaultProps} />
406
- </TestWrapper>
480
+ </TestWrapper>,
481
+ { withRouter: false }
407
482
  );
408
483
 
409
484
  await user.click(screen.getByTestId('sign-out-btn'));
@@ -415,7 +490,8 @@ describe('PaceAppLayout Component', () => {
415
490
  renderWithProviders(
416
491
  <TestWrapper>
417
492
  <PaceAppLayout {...defaultProps} />
418
- </TestWrapper>
493
+ </TestWrapper>,
494
+ { withRouter: false }
419
495
  );
420
496
 
421
497
  await user.click(screen.getByTestId('change-password-btn'));
@@ -432,7 +508,8 @@ describe('PaceAppLayout Component', () => {
432
508
  renderWithProviders(
433
509
  <TestWrapper>
434
510
  <PaceAppLayout {...defaultProps} navItems={customNavItems} />
435
- </TestWrapper>
511
+ </TestWrapper>,
512
+ { withRouter: false }
436
513
  );
437
514
 
438
515
  await user.click(screen.getByTestId('nav-item-home'));
@@ -441,6 +518,18 @@ describe('PaceAppLayout Component', () => {
441
518
  await user.click(screen.getByTestId('nav-item-about'));
442
519
  expect(mockNavigate).toHaveBeenCalledWith('/about');
443
520
  });
521
+
522
+ it('passes current path to header', () => {
523
+ renderWithProviders(
524
+ <TestWrapper>
525
+ <PaceAppLayout {...defaultProps} />
526
+ </TestWrapper>,
527
+ { withRouter: false }
528
+ );
529
+
530
+ // The header mock doesn't show current path in this test setup, but we can verify it's rendered
531
+ expect(screen.getByTestId('header')).toBeInTheDocument();
532
+ });
444
533
  });
445
534
 
446
535
  describe('Permission Enforcement', () => {
@@ -448,7 +537,8 @@ describe('PaceAppLayout Component', () => {
448
537
  renderWithProviders(
449
538
  <TestWrapper>
450
539
  <PaceAppLayout {...defaultProps} enforcePermissions={false} />
451
- </TestWrapper>
540
+ </TestWrapper>,
541
+ { withRouter: false }
452
542
  );
453
543
 
454
544
  expect(screen.getByTestId('header')).toBeInTheDocument();
@@ -467,7 +557,8 @@ describe('PaceAppLayout Component', () => {
467
557
  renderWithProviders(
468
558
  <TestWrapper>
469
559
  <PaceAppLayout {...defaultProps} enforcePermissions={true} />
470
- </TestWrapper>
560
+ </TestWrapper>,
561
+ { withRouter: false }
471
562
  );
472
563
 
473
564
  expect(screen.getByText('Checking permissions...')).toBeInTheDocument();
@@ -475,8 +566,8 @@ describe('PaceAppLayout Component', () => {
475
566
  });
476
567
 
477
568
  it('shows permission error when check fails', async () => {
478
- // Ensure super admin check completes first
479
- mockIsSuperAdmin.mockResolvedValueOnce(false);
569
+ // Ensure super admin check completes first - resolve immediately
570
+ mockIsSuperAdmin.mockResolvedValue(false);
480
571
 
481
572
  // Mock useCan to return an error state
482
573
  mockUseCan.mockReturnValue({
@@ -489,26 +580,27 @@ describe('PaceAppLayout Component', () => {
489
580
  renderWithProviders(
490
581
  <TestWrapper>
491
582
  <PaceAppLayout {...defaultProps} enforcePermissions={true} />
492
- </TestWrapper>
583
+ </TestWrapper>,
584
+ { withRouter: false }
493
585
  );
494
586
 
495
587
  // Wait for super admin check to complete and component to re-render
588
+ // The component calls isSuperAdmin in a useEffect, so we need to wait for it
496
589
  await waitFor(() => {
497
590
  expect(mockIsSuperAdmin).toHaveBeenCalled();
498
- }, { timeout: 1000 });
499
-
500
- // Wait a bit for the component to process the super admin check result
501
- await new Promise(resolve => setTimeout(resolve, 100));
591
+ }, { timeout: 2000 });
502
592
 
593
+ // Wait for the component to process the super admin check result and render error
594
+ // Need to wait for both checks to complete (super admin + permission)
503
595
  await waitFor(() => {
504
596
  expect(screen.getByText('Permission Error')).toBeInTheDocument();
505
597
  expect(screen.getByText('Permission check failed')).toBeInTheDocument();
506
- });
598
+ }, { timeout: 3000 });
507
599
  });
508
600
 
509
601
  it('shows access denied when user lacks permission', async () => {
510
- // Ensure super admin check completes first
511
- mockIsSuperAdmin.mockResolvedValueOnce(false);
602
+ // Ensure super admin check completes first - resolve immediately
603
+ mockIsSuperAdmin.mockResolvedValue(false);
512
604
 
513
605
  // Mock useCan to return false (no permission)
514
606
  mockUseCan.mockReturnValue({
@@ -521,26 +613,98 @@ describe('PaceAppLayout Component', () => {
521
613
  renderWithProviders(
522
614
  <TestWrapper>
523
615
  <PaceAppLayout {...defaultProps} enforcePermissions={true} />
524
- </TestWrapper>
616
+ </TestWrapper>,
617
+ { withRouter: false }
525
618
  );
526
619
 
527
620
  // Wait for super admin check to complete and component to re-render
528
621
  await waitFor(() => {
529
622
  expect(mockIsSuperAdmin).toHaveBeenCalled();
530
- }, { timeout: 1000 });
531
-
532
- // Wait a bit for the component to process the super admin check result
533
- await new Promise(resolve => setTimeout(resolve, 100));
623
+ }, { timeout: 2000 });
534
624
 
625
+ // Wait for the component to process the super admin check result and render access denied
626
+ // Need to wait for both checks to complete (super admin + permission)
535
627
  await waitFor(() => {
536
628
  expect(screen.getByText('Access Denied')).toBeInTheDocument();
537
629
  expect(screen.getByText("You don't have permission to access this page.")).toBeInTheDocument();
630
+ }, { timeout: 3000 });
631
+ });
632
+
633
+ it('provides go home button in access denied state', async () => {
634
+ // Ensure super admin check completes first - resolve immediately
635
+ mockIsSuperAdmin.mockResolvedValue(false);
636
+
637
+ // Mock useCan to return false (no permission)
638
+ mockUseCan.mockReturnValue({
639
+ can: false,
640
+ isLoading: false,
641
+ error: null,
642
+ refetch: vi.fn().mockResolvedValue(undefined),
538
643
  });
644
+
645
+ renderWithProviders(
646
+ <TestWrapper>
647
+ <PaceAppLayout {...defaultProps} enforcePermissions={true} />
648
+ </TestWrapper>,
649
+ { withRouter: false }
650
+ );
651
+
652
+ // Wait for super admin check to complete and component to re-render
653
+ await waitFor(() => {
654
+ expect(mockIsSuperAdmin).toHaveBeenCalled();
655
+ }, { timeout: 2000 });
656
+
657
+ // Wait for the component to process the super admin check result and render access denied
658
+ await waitFor(() => {
659
+ const goHomeButton = screen.getByText('Go Home');
660
+ expect(goHomeButton).toBeInTheDocument();
661
+ }, { timeout: 3000 });
662
+
663
+ const user = userEvent.setup();
664
+ await user.click(screen.getByText('Go Home'));
665
+ expect(mockNavigate).toHaveBeenCalledWith('/');
666
+ });
667
+
668
+ it('provides go home button in permission error state', async () => {
669
+ const mockError = new Error('Permission check failed');
670
+
671
+ // Ensure super admin check completes first - resolve immediately
672
+ mockIsSuperAdmin.mockResolvedValue(false);
673
+
674
+ // Mock useCan to return an error state
675
+ mockUseCan.mockReturnValue({
676
+ can: false,
677
+ isLoading: false,
678
+ error: mockError,
679
+ refetch: vi.fn().mockResolvedValue(undefined),
680
+ });
681
+
682
+ renderWithProviders(
683
+ <TestWrapper>
684
+ <PaceAppLayout {...defaultProps} enforcePermissions={true} />
685
+ </TestWrapper>,
686
+ { withRouter: false }
687
+ );
688
+
689
+ // Wait for super admin check to complete and component to re-render
690
+ await waitFor(() => {
691
+ expect(mockIsSuperAdmin).toHaveBeenCalled();
692
+ }, { timeout: 2000 });
693
+
694
+ // Wait for the component to process the super admin check result and render error
695
+ await waitFor(() => {
696
+ const goHomeButton = screen.getByText('Go Home');
697
+ expect(goHomeButton).toBeInTheDocument();
698
+ }, { timeout: 3000 });
699
+
700
+ const user = userEvent.setup();
701
+ await user.click(screen.getByText('Go Home'));
702
+ expect(mockNavigate).toHaveBeenCalledWith('/');
539
703
  });
540
704
 
541
705
  it('shows custom permission fallback when provided', async () => {
542
- // Ensure super admin check completes first
543
- mockIsSuperAdmin.mockResolvedValueOnce(false);
706
+ // Ensure super admin check completes first - resolve immediately
707
+ mockIsSuperAdmin.mockResolvedValue(false);
544
708
 
545
709
  // Arrange
546
710
  mockUseCan.mockReturnValue({
@@ -559,26 +723,24 @@ describe('PaceAppLayout Component', () => {
559
723
  enforcePermissions={true}
560
724
  permissionFallback={customFallback}
561
725
  />
562
- </TestWrapper>
726
+ </TestWrapper>,
727
+ { withRouter: false }
563
728
  );
564
729
 
565
730
  // Wait for super admin check to complete and component to re-render
566
731
  await waitFor(() => {
567
732
  expect(mockIsSuperAdmin).toHaveBeenCalled();
568
- }, { timeout: 1000 });
569
-
570
- // Wait a bit for the component to process the super admin check result
571
- await new Promise(resolve => setTimeout(resolve, 100));
733
+ }, { timeout: 2000 });
572
734
 
573
- // Assert - No need to wait for loading since mock returns immediately
735
+ // Wait for the component to process the super admin check result and render fallback
574
736
  await waitFor(() => {
575
737
  expect(screen.getByTestId('custom-fallback')).toBeInTheDocument();
576
- });
738
+ }, { timeout: 3000 });
577
739
  });
578
740
 
579
741
  it('shows page permission fallback when enforcePagePermissions is true', async () => {
580
- // Ensure super admin check completes first
581
- mockIsSuperAdmin.mockResolvedValueOnce(false);
742
+ // Ensure super admin check completes first - resolve immediately
743
+ mockIsSuperAdmin.mockResolvedValue(false);
582
744
 
583
745
  // Arrange
584
746
  mockUseCan.mockReturnValue({
@@ -598,21 +760,19 @@ describe('PaceAppLayout Component', () => {
598
760
  enforcePagePermissions={true}
599
761
  pagePermissionFallback={pageFallback}
600
762
  />
601
- </TestWrapper>
763
+ </TestWrapper>,
764
+ { withRouter: false }
602
765
  );
603
766
 
604
767
  // Wait for super admin check to complete and component to re-render
605
768
  await waitFor(() => {
606
769
  expect(mockIsSuperAdmin).toHaveBeenCalled();
607
- }, { timeout: 1000 });
608
-
609
- // Wait a bit for the component to process the super admin check result
610
- await new Promise(resolve => setTimeout(resolve, 100));
770
+ }, { timeout: 2000 });
611
771
 
612
- // Assert - No need to wait for loading since mock returns immediately
772
+ // Wait for the component to process the super admin check result and render fallback
613
773
  await waitFor(() => {
614
774
  expect(screen.getByTestId('page-fallback')).toBeInTheDocument();
615
- });
775
+ }, { timeout: 3000 });
616
776
  });
617
777
  });
618
778
 
@@ -634,14 +794,14 @@ describe('PaceAppLayout Component', () => {
634
794
  {...defaultProps}
635
795
  navItems={customNavItems}
636
796
  enforcePermissions={true}
637
- filterNavigationByPermissions={true}
638
797
  routePermissions={{
639
798
  '/': 'read',
640
799
  '/dashboard': 'read',
641
800
  '/settings': 'read',
642
801
  }}
643
802
  />
644
- </TestWrapper>
803
+ </TestWrapper>,
804
+ { withRouter: false }
645
805
  );
646
806
 
647
807
  // Wait for the component to render initially
@@ -657,25 +817,33 @@ describe('PaceAppLayout Component', () => {
657
817
  }, { timeout: 2000 });
658
818
  });
659
819
 
660
- it('shows all navigation items when filterNavigationByPermissions is false', () => {
820
+ it('always filters navigation items by permissions (filtering cannot be disabled)', async () => {
661
821
  const customNavItems = [
662
822
  { id: 'home', label: 'Home', href: '/', icon: 'Home' },
663
823
  { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },
664
824
  ];
665
825
 
826
+ // Permission filtering is always enabled - this test verifies that items are filtered based on permissions
666
827
  renderWithProviders(
667
828
  <TestWrapper>
668
829
  <PaceAppLayout
669
830
  {...defaultProps}
670
831
  navItems={customNavItems}
671
832
  enforcePermissions={false}
672
- filterNavigationByPermissions={false}
833
+ routePermissions={{
834
+ '/': 'read',
835
+ '/dashboard': 'read',
836
+ }}
673
837
  />
674
- </TestWrapper>
838
+ </TestWrapper>,
839
+ { withRouter: false }
675
840
  );
676
841
 
677
- expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
678
- expect(screen.getByTestId('nav-item-dashboard')).toBeInTheDocument();
842
+ // Wait for permission checks to complete
843
+ await waitFor(() => {
844
+ expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
845
+ expect(screen.getByTestId('nav-item-dashboard')).toBeInTheDocument();
846
+ }, { timeout: 2000 });
679
847
  });
680
848
  });
681
849
 
@@ -693,7 +861,8 @@ describe('PaceAppLayout Component', () => {
693
861
  '/dashboard': 'dashboard-page',
694
862
  }}
695
863
  />
696
- </TestWrapper>
864
+ </TestWrapper>,
865
+ { withRouter: false }
697
866
  );
698
867
 
699
868
  await waitFor(() => {
@@ -719,7 +888,8 @@ describe('PaceAppLayout Component', () => {
719
888
  '/other': 'read',
720
889
  }}
721
890
  />
722
- </TestWrapper>
891
+ </TestWrapper>,
892
+ { withRouter: false }
723
893
  );
724
894
 
725
895
  await waitFor(() => {
@@ -747,7 +917,8 @@ describe('PaceAppLayout Component', () => {
747
917
  {...defaultProps}
748
918
  enforcePermissions={true}
749
919
  />
750
- </TestWrapper>
920
+ </TestWrapper>,
921
+ { withRouter: false }
751
922
  );
752
923
 
753
924
  await waitFor(() => {
@@ -776,7 +947,8 @@ describe('PaceAppLayout Component', () => {
776
947
  enforcePermissions={true}
777
948
  onPageAccessDenied={onPageAccessDenied}
778
949
  />
779
- </TestWrapper>
950
+ </TestWrapper>,
951
+ { withRouter: false }
780
952
  );
781
953
 
782
954
  // Assert - Callback should be called immediately when can is false
@@ -804,7 +976,8 @@ describe('PaceAppLayout Component', () => {
804
976
  strictMode={true}
805
977
  onStrictModeViolation={onStrictModeViolation}
806
978
  />
807
- </TestWrapper>
979
+ </TestWrapper>,
980
+ { withRouter: false }
808
981
  );
809
982
 
810
983
  // Assert - Callback should be called immediately when can is false
@@ -835,7 +1008,8 @@ describe('PaceAppLayout Component', () => {
835
1008
  routeConfig={routeConfig}
836
1009
  onRouteAccessDenied={onRouteAccessDenied}
837
1010
  />
838
- </TestWrapper>
1011
+ </TestWrapper>,
1012
+ { withRouter: false }
839
1013
  );
840
1014
 
841
1015
  // Should render normally since route is in config
@@ -864,13 +1038,61 @@ describe('PaceAppLayout Component', () => {
864
1038
  strictMode={true}
865
1039
  onRouteStrictModeViolation={onRouteStrictModeViolation}
866
1040
  />
867
- </TestWrapper>
1041
+ </TestWrapper>,
1042
+ { withRouter: false }
868
1043
  );
869
1044
 
870
1045
  await waitFor(() => {
871
1046
  expect(onRouteStrictModeViolation).toHaveBeenCalledWith('/unknown', 'Route not found in configuration');
872
1047
  });
873
1048
  });
1049
+
1050
+ it('navigates to fallback route when route access is denied', async () => {
1051
+ const onRouteAccessDenied = vi.fn();
1052
+ const onRouteStrictModeViolation = vi.fn();
1053
+ const routeConfig = [
1054
+ {
1055
+ path: '/secure',
1056
+ component: () => <div>Secure</div>,
1057
+ permissions: ['read:page.secure'],
1058
+ pageId: 'secure',
1059
+ },
1060
+ ];
1061
+
1062
+ mockLocation.pathname = '/secure';
1063
+ mockNavigate.mockClear();
1064
+
1065
+ const { isPermittedCached } = await import('../../rbac/api');
1066
+ vi.mocked(isPermittedCached).mockResolvedValueOnce(false);
1067
+
1068
+ const FallbackWrapper = ({ children }: { children: React.ReactNode }) => (
1069
+ <MemoryRouter initialEntries={['/secure']}>
1070
+ {children}
1071
+ </MemoryRouter>
1072
+ );
1073
+
1074
+ renderWithProviders(
1075
+ <FallbackWrapper>
1076
+ <PaceAppLayout
1077
+ {...defaultProps}
1078
+ roleBasedRouting={true}
1079
+ strictMode={true}
1080
+ fallbackRoute="/no-access"
1081
+ routeConfig={routeConfig}
1082
+ onRouteAccessDenied={onRouteAccessDenied}
1083
+ onRouteStrictModeViolation={onRouteStrictModeViolation}
1084
+ />
1085
+ </FallbackWrapper>,
1086
+ { withRouter: false }
1087
+ );
1088
+
1089
+ await waitFor(() => {
1090
+ expect(mockNavigate).toHaveBeenCalledWith('/no-access', { replace: true });
1091
+ });
1092
+
1093
+ expect(onRouteAccessDenied).toHaveBeenCalledWith('/secure', 'Insufficient permissions');
1094
+ expect(onRouteStrictModeViolation).toHaveBeenCalledWith('/secure', 'Insufficient permissions');
1095
+ });
874
1096
  });
875
1097
 
876
1098
  describe('Error Handling', () => {
@@ -882,11 +1104,11 @@ describe('PaceAppLayout Component', () => {
882
1104
  };
883
1105
 
884
1106
  // Mock the useUnifiedAuth hook to return null user
885
- vi.mocked(useUnifiedAuth).mockReturnValue(mockAuthWithoutUser);
1107
+ mockUseUnifiedAuthFn.mockReturnValue(mockAuthWithoutUser);
886
1108
 
887
- // When there's no user, useCan is called with empty string userId
888
- // and will return false (no permission)
889
- mockUseCan.mockReturnValueOnce({
1109
+ // When there's no user, isSuperAdmin won't be called (it checks user?.id first)
1110
+ // and useCan is called with empty string userId, which will return false (no permission)
1111
+ mockUseCan.mockReturnValue({
890
1112
  can: false,
891
1113
  isLoading: false,
892
1114
  error: null,
@@ -899,17 +1121,20 @@ describe('PaceAppLayout Component', () => {
899
1121
  {...defaultProps}
900
1122
  enforcePermissions={true}
901
1123
  />
902
- </TestWrapper>
1124
+ </TestWrapper>,
1125
+ { withRouter: false }
903
1126
  );
904
1127
 
1128
+ // When user is null, isSuperAdmin won't be called (early return in useEffect)
1129
+ // So we should see "Access Denied" immediately after useCan returns false
905
1130
  await waitFor(() => {
906
1131
  expect(screen.getByText('Access Denied')).toBeInTheDocument();
907
1132
  }, { timeout: 3000 });
908
1133
  });
909
1134
 
910
1135
  it('handles missing organisation context', async () => {
911
- // Ensure super admin check completes first
912
- mockIsSuperAdmin.mockResolvedValueOnce(false);
1136
+ // Ensure super admin check completes first - resolve immediately
1137
+ mockIsSuperAdmin.mockResolvedValue(false);
913
1138
 
914
1139
  // Arrange
915
1140
  const mockUserWithoutOrg = {
@@ -923,7 +1148,7 @@ describe('PaceAppLayout Component', () => {
923
1148
  user: mockUserWithoutOrg,
924
1149
  };
925
1150
 
926
- vi.mocked(useUnifiedAuth).mockReturnValue(mockAuthWithoutOrg);
1151
+ mockUseUnifiedAuthFn.mockReturnValue(mockAuthWithoutOrg);
927
1152
  mockUseCan.mockReturnValue({
928
1153
  can: false,
929
1154
  isLoading: false,
@@ -938,57 +1163,117 @@ describe('PaceAppLayout Component', () => {
938
1163
  {...defaultProps}
939
1164
  enforcePermissions={true}
940
1165
  />
941
- </TestWrapper>
1166
+ </TestWrapper>,
1167
+ { withRouter: false }
942
1168
  );
943
1169
 
944
1170
  // Wait for super admin check to complete and component to re-render
945
1171
  await waitFor(() => {
946
1172
  expect(mockIsSuperAdmin).toHaveBeenCalled();
947
- }, { timeout: 1000 });
948
-
949
- // Wait a bit for the component to process the super admin check result
950
- await new Promise(resolve => setTimeout(resolve, 100));
1173
+ }, { timeout: 2000 });
951
1174
 
952
- // Assert - Component should show access denied
1175
+ // Wait for the component to process the super admin check result and render access denied
953
1176
  await waitFor(() => {
954
1177
  expect(screen.getByRole('heading', { name: 'Access Denied' })).toBeInTheDocument();
955
- });
1178
+ }, { timeout: 3000 });
956
1179
  });
957
1180
  });
958
1181
 
959
1182
  describe('Accessibility', () => {
960
- it('has proper semantic structure', () => {
961
- renderWithProviders(
962
- <TestWrapper>
963
- <PaceAppLayout {...defaultProps} />
964
- </TestWrapper>
965
- );
966
-
967
- expect(screen.getByTestId('header')).toBeInTheDocument();
968
- expect(screen.getByRole('main')).toBeInTheDocument();
969
- expect(screen.getByTestId('footer')).toBeInTheDocument();
1183
+ describe('Semantic HTML Structure', () => {
1184
+ it('renders with proper semantic HTML elements', () => {
1185
+ renderWithProviders(
1186
+ <TestWrapper>
1187
+ <PaceAppLayout {...defaultProps} />
1188
+ </TestWrapper>,
1189
+ { withRouter: false }
1190
+ );
1191
+
1192
+ expect(screen.getByTestId('header')).toBeInTheDocument();
1193
+ expect(screen.getByRole('main')).toBeInTheDocument();
1194
+ expect(screen.getByTestId('footer')).toBeInTheDocument();
1195
+ });
1196
+
1197
+ it('provides proper main content area', () => {
1198
+ renderWithProviders(
1199
+ <TestWrapper>
1200
+ <PaceAppLayout {...defaultProps} />
1201
+ </TestWrapper>,
1202
+ { withRouter: false }
1203
+ );
1204
+
1205
+ const main = screen.getByRole('main');
1206
+ expect(main).toBeInTheDocument();
1207
+ expect(main).toHaveClass('px-4', 'w-[min(var(--app-width),100%)]', 'mx-auto', 'py-8');
1208
+ });
1209
+
1210
+ it('renders main content area with proper styling', () => {
1211
+ renderWithProviders(
1212
+ <TestWrapper>
1213
+ <PaceAppLayout {...defaultProps} />
1214
+ </TestWrapper>,
1215
+ { withRouter: false }
1216
+ );
1217
+
1218
+ const main = screen.getByTestId('outlet').parentElement;
1219
+ expect(main).toHaveClass('px-4', 'w-[min(var(--app-width),100%)]', 'mx-auto', 'py-8');
1220
+ });
970
1221
  });
971
1222
 
972
- it('has accessible navigation', () => {
973
- renderWithProviders(
974
- <TestWrapper>
975
- <PaceAppLayout {...defaultProps} />
976
- </TestWrapper>
977
- );
978
-
979
- expect(screen.getByTestId('header-nav')).toBeInTheDocument();
980
- expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
1223
+ describe('ARIA Attributes and Labels', () => {
1224
+ it('has accessible navigation', () => {
1225
+ renderWithProviders(
1226
+ <TestWrapper>
1227
+ <PaceAppLayout {...defaultProps} />
1228
+ </TestWrapper>,
1229
+ { withRouter: false }
1230
+ );
1231
+
1232
+ expect(screen.getByTestId('header-nav')).toBeInTheDocument();
1233
+ expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
1234
+ });
1235
+
1236
+ it('has accessible user menu', () => {
1237
+ renderWithProviders(
1238
+ <TestWrapper>
1239
+ <PaceAppLayout {...defaultProps} />
1240
+ </TestWrapper>,
1241
+ { withRouter: false }
1242
+ );
1243
+
1244
+ expect(screen.getByTestId('header-user-menu')).toBeInTheDocument();
1245
+ expect(screen.getByTestId('user-email')).toHaveTextContent('test@example.com');
1246
+ });
981
1247
  });
982
1248
 
983
- it('has accessible user menu', () => {
984
- renderWithProviders(
985
- <TestWrapper>
986
- <PaceAppLayout {...defaultProps} />
987
- </TestWrapper>
988
- );
989
-
990
- expect(screen.getByTestId('header-user-menu')).toBeInTheDocument();
991
- expect(screen.getByTestId('user-email')).toHaveTextContent('test@example.com');
1249
+ describe('Screen Reader Support', () => {
1250
+ it('provides meaningful text for screen readers', () => {
1251
+ renderWithProviders(
1252
+ <TestWrapper>
1253
+ <PaceAppLayout {...defaultProps} />
1254
+ </TestWrapper>,
1255
+ { withRouter: false }
1256
+ );
1257
+
1258
+ expect(screen.getByTestId('header')).toBeInTheDocument();
1259
+ expect(screen.getByTestId('user-email')).toHaveTextContent('test@example.com');
1260
+ });
1261
+ });
1262
+
1263
+ describe('Keyboard Navigation', () => {
1264
+ it('provides proper focus management', async () => {
1265
+ const user = userEvent.setup();
1266
+ renderWithProviders(
1267
+ <TestWrapper>
1268
+ <PaceAppLayout {...defaultProps} />
1269
+ </TestWrapper>,
1270
+ { withRouter: false }
1271
+ );
1272
+
1273
+ const signOutButton = screen.getByTestId('sign-out-btn');
1274
+ await user.tab();
1275
+ expect(signOutButton).toBeInTheDocument();
1276
+ });
992
1277
  });
993
1278
  });
994
1279
 
@@ -997,7 +1282,8 @@ describe('PaceAppLayout Component', () => {
997
1282
  renderWithProviders(
998
1283
  <TestWrapper>
999
1284
  <PaceAppLayout {...defaultProps} navItems={[]} />
1000
- </TestWrapper>
1285
+ </TestWrapper>,
1286
+ { withRouter: false }
1001
1287
  );
1002
1288
 
1003
1289
  expect(screen.getByTestId('header')).toBeInTheDocument();
@@ -1015,10 +1301,10 @@ describe('PaceAppLayout Component', () => {
1015
1301
  <PaceAppLayout
1016
1302
  {...defaultProps}
1017
1303
  navItems={navItemsWithoutHref}
1018
- filterNavigationByPermissions={false}
1019
1304
  enforcePermissions={false}
1020
1305
  />
1021
- </TestWrapper>
1306
+ </TestWrapper>,
1307
+ { withRouter: false }
1022
1308
  );
1023
1309
 
1024
1310
  expect(screen.getByTestId('nav-item-home')).toBeInTheDocument();
@@ -1031,7 +1317,8 @@ describe('PaceAppLayout Component', () => {
1031
1317
  const { rerender } = renderWithProviders(
1032
1318
  <TestWrapper>
1033
1319
  <PaceAppLayout {...defaultProps} enforcePermissions={false} />
1034
- </TestWrapper>
1320
+ </TestWrapper>,
1321
+ { withRouter: false }
1035
1322
  );
1036
1323
 
1037
1324
  // Wait for initial render
@@ -1065,7 +1352,8 @@ describe('PaceAppLayout Component', () => {
1065
1352
  const { rerender } = renderWithProviders(
1066
1353
  <TestWrapper>
1067
1354
  <PaceAppLayout {...stableProps} />
1068
- </TestWrapper>
1355
+ </TestWrapper>,
1356
+ { withRouter: false }
1069
1357
  );
1070
1358
 
1071
1359
  const initialHeader = screen.getByTestId('header');