@jmruthers/pace-core 0.5.181 → 0.5.183

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 (756) 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/usePublicEventLogo.test.ts +147 -0
  470. package/src/hooks/public/usePublicRouteParams.ts +1 -1
  471. package/src/hooks/services/useAuth.ts +2 -4
  472. package/src/hooks/services/useCurrentEvent.ts +1 -1
  473. package/src/hooks/useAppConfig.ts +1 -1
  474. package/src/hooks/useDataTablePerformance.ts +2 -2
  475. package/src/hooks/useEventTheme.ts +1 -1
  476. package/src/hooks/useEvents.ts +51 -10
  477. package/src/hooks/useOrganisationPermissions.test.ts +3 -3
  478. package/src/hooks/useOrganisationPermissions.ts +1 -1
  479. package/src/hooks/useOrganisationSecurity.ts +2 -2
  480. package/src/hooks/usePermissionCache.test.ts +9 -9
  481. package/src/hooks/usePermissionCache.ts +2 -2
  482. package/src/index.ts +19 -12
  483. package/src/providers/OrganisationProvider.tsx +73 -9
  484. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +113 -13
  485. package/src/providers/__tests__/AuthProvider.test.tsx +2 -1
  486. package/src/providers/__tests__/EventProvider.test.tsx +24 -15
  487. package/src/providers/__tests__/OrganisationProvider.test.tsx +87 -36
  488. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +80 -24
  489. package/src/providers/index.ts +0 -3
  490. package/src/providers/services/AuthServiceProvider.tsx +2 -17
  491. package/src/providers/services/EventServiceProvider.tsx +11 -16
  492. package/src/providers/services/InactivityServiceProvider.tsx +9 -12
  493. package/src/providers/services/OrganisationServiceProvider.tsx +9 -12
  494. package/src/providers/services/UnifiedAuthProvider.tsx +85 -18
  495. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +11 -4
  496. package/src/rbac/__tests__/scenarios.user-role.test.tsx +105 -21
  497. package/src/rbac/adapters.tsx +1 -1
  498. package/src/rbac/api.ts +20 -4
  499. package/src/rbac/audit-enhanced.ts +47 -2
  500. package/src/rbac/audit.ts +47 -2
  501. package/src/rbac/components/NavigationGuard.tsx +1 -1
  502. package/src/rbac/components/NavigationProvider.test.tsx +7 -6
  503. package/src/rbac/components/NavigationProvider.tsx +1 -1
  504. package/src/rbac/components/PagePermissionGuard.tsx +1 -1
  505. package/src/rbac/components/PagePermissionProvider.test.tsx +7 -6
  506. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  507. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  508. package/src/rbac/components/RoleBasedRouter.tsx +1 -1
  509. package/src/rbac/components/SecureDataProvider.test.tsx +7 -6
  510. package/src/rbac/components/SecureDataProvider.tsx +1 -1
  511. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +6 -6
  512. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +11 -10
  513. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +10 -11
  514. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +19 -15
  515. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +13 -12
  516. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +19 -15
  517. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +18 -18
  518. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +11 -10
  519. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +8 -7
  520. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +10 -11
  521. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +48 -19
  522. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +476 -0
  523. package/src/rbac/hooks/index.ts +3 -0
  524. package/src/rbac/hooks/usePermissions.ts +31 -85
  525. package/src/rbac/hooks/useRBAC.test.ts +13 -1
  526. package/src/rbac/hooks/useRBAC.ts +13 -67
  527. package/src/rbac/hooks/useResolvedScope.ts +11 -0
  528. package/src/rbac/hooks/useSecureSupabase.ts +308 -0
  529. package/src/rbac/index.ts +3 -0
  530. package/src/rbac/secureClient.ts +53 -6
  531. package/src/rbac/security.ts +37 -1
  532. package/src/{types/rbac-functions.ts → rbac/types/functions.ts} +30 -30
  533. package/src/rbac/types.ts +3 -2
  534. package/src/services/AuthService.ts +33 -25
  535. package/src/services/EventService.ts +56 -44
  536. package/src/services/InactivityService.ts +33 -53
  537. package/src/services/OrganisationService.ts +36 -40
  538. package/src/services/__tests__/AuthService.restoreSession.test.ts +6 -2
  539. package/src/services/__tests__/EventService.test.ts +67 -33
  540. package/src/services/interfaces/IEventService.ts +1 -1
  541. package/src/styles/core.css +2 -2
  542. package/src/styles/index.test.ts +21 -0
  543. package/src/styles/index.ts +1 -5
  544. package/src/types/__tests__/guards.test.ts +1 -1
  545. package/src/types/__tests__/organisation.roles.test.ts +55 -0
  546. package/src/types/__tests__/type-validation.test.ts +0 -1
  547. package/src/types/auth.ts +42 -2
  548. package/src/types/core.ts +251 -0
  549. package/src/types/database.ts +11 -496
  550. package/src/types/event.ts +102 -0
  551. package/src/types/file-reference.ts +6 -4
  552. package/src/types/guards.ts +2 -1
  553. package/src/types/index.ts +48 -14
  554. package/src/types/lodash.debounce.d.ts +15 -0
  555. package/src/types/organisation.ts +14 -10
  556. package/src/types/supabase.ts +15 -17
  557. package/src/utils/__tests__/secureErrors.unit.test.ts +1 -1
  558. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -29
  559. package/src/utils/app/appNameResolver.ts +1 -1
  560. package/src/utils/audit/audit.test.ts +65 -0
  561. package/src/utils/device/deviceFingerprint.test.ts +171 -0
  562. package/src/utils/dynamic/dynamicUtils.ts +3 -2
  563. package/src/utils/file-reference/index.ts +25 -6
  564. package/src/utils/security/secureErrors.ts +1 -1
  565. package/src/utils/validation/__tests__/validationUtils.test.ts +72 -0
  566. package/src/utils/validation/index.ts +6 -12
  567. package/src/utils/validation/validationUtils.ts +0 -13
  568. package/dist/UnifiedAuthProvider-B37ATQHE.js +0 -16
  569. package/dist/auth-DReDSLq9.d.ts +0 -16
  570. package/dist/chunk-3JI76CYK.js +0 -2444
  571. package/dist/chunk-3JI76CYK.js.map +0 -1
  572. package/dist/chunk-56XJ3TU6.js +0 -11
  573. package/dist/chunk-56XJ3TU6.js.map +0 -1
  574. package/dist/chunk-5MT24GKJ.js.map +0 -1
  575. package/dist/chunk-7QCC6MCP.js +0 -288
  576. package/dist/chunk-BESYRHQM.js.map +0 -1
  577. package/dist/chunk-BJPBT3CU.js +0 -21
  578. package/dist/chunk-BJPBT3CU.js.map +0 -1
  579. package/dist/chunk-BVYWGZVV.js.map +0 -1
  580. package/dist/chunk-CX5M4ZAG.js.map +0 -1
  581. package/dist/chunk-D7LCGMVS.js.map +0 -1
  582. package/dist/chunk-EGI6MUL6.js +0 -27
  583. package/dist/chunk-EGI6MUL6.js.map +0 -1
  584. package/dist/chunk-ERISIBYU.js.map +0 -1
  585. package/dist/chunk-HRO5HWN2.js.map +0 -1
  586. package/dist/chunk-HZLDFOE4.js.map +0 -1
  587. package/dist/chunk-JISYG63F.js +0 -70
  588. package/dist/chunk-JISYG63F.js.map +0 -1
  589. package/dist/chunk-LIMSTKYD.js +0 -61
  590. package/dist/chunk-LIMSTKYD.js.map +0 -1
  591. package/dist/chunk-OWAG3GSU.js.map +0 -1
  592. package/dist/chunk-PPMP5J6T.js.map +0 -1
  593. package/dist/chunk-Q5QRDWKI.js.map +0 -1
  594. package/dist/chunk-S5OFRT4M.js.map +0 -1
  595. package/dist/chunk-SBVILCCA.js.map +0 -1
  596. package/dist/chunk-TUMEWN34.js +0 -15
  597. package/dist/chunk-TUMEWN34.js.map +0 -1
  598. package/dist/chunk-XDNLUEXI.js +0 -138
  599. package/dist/chunk-XJ2HZOBU.js.map +0 -1
  600. package/dist/chunk-ZYTYSTO5.js.map +0 -1
  601. package/dist/chunk-ZZ2SS7NI.js +0 -237
  602. package/dist/chunk-ZZ2SS7NI.js.map +0 -1
  603. package/dist/database-C6jy7EOu.d.ts +0 -500
  604. package/dist/organisation-D6qRDtbF.d.ts +0 -93
  605. package/dist/schema-DTDZQe2u.d.ts +0 -28
  606. package/dist/unified-DQ4VcT7H.d.ts +0 -198
  607. package/dist/useInactivityTracker-TO6ZOF35.js +0 -11
  608. package/dist/validation.d.ts +0 -47
  609. package/dist/validation.js +0 -24
  610. package/dist/validation.js.map +0 -1
  611. package/docs/DOCUMENTATION_AUDIT.md +0 -172
  612. package/docs/DOCUMENTATION_STANDARD.md +0 -137
  613. package/docs/api/classes/PublicErrorBoundary.md +0 -132
  614. package/docs/api/interfaces/EventLogoProps.md +0 -152
  615. package/docs/api/interfaces/PublicErrorBoundaryProps.md +0 -94
  616. package/docs/api/interfaces/PublicErrorBoundaryState.md +0 -68
  617. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +0 -86
  618. package/docs/architecture/rpc-function-standards.md +0 -1106
  619. package/docs/getting-started/consuming-app-vite-config.md +0 -239
  620. package/docs/implementation-guides/event-theming-summary.md +0 -226
  621. package/docs/implementation-guides/public-pages-advanced.md +0 -1038
  622. package/docs/migration/v0.4.15-tailwind-scanning.md +0 -278
  623. package/docs/migration/v0.4.16-css-first-approach.md +0 -312
  624. package/docs/migration/v0.4.17-source-path-fix.md +0 -235
  625. package/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +0 -222
  626. package/docs/rbac/RBAC_LOGIN_SAFETY_FIX.md +0 -95
  627. package/docs/rbac/RBAC_V0.5.147_FIX.md +0 -117
  628. package/docs/rbac/README-rbac-rls-integration.md +0 -374
  629. package/docs/styles/usage.md +0 -227
  630. package/docs/testing/visual-testing.md +0 -120
  631. package/docs/troubleshooting/DEBUG_NETWORK_ERROR.md +0 -152
  632. package/docs/troubleshooting/FIX_SUPABASE_CORS.md +0 -184
  633. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +0 -193
  634. package/docs/troubleshooting/database-view-compatibility.md +0 -125
  635. package/docs/troubleshooting/react-hooks-issue-analysis.md +0 -172
  636. package/docs/troubleshooting/tailwind-content-scanning.md +0 -219
  637. package/examples/RBAC/EventBasedApp.tsx +0 -239
  638. package/examples/RBAC/PermissionExample.tsx +0 -151
  639. package/examples/STRUCTURE.md +0 -125
  640. package/examples/components 2/DataTable/HierarchicalExample.tsx +0 -475
  641. package/examples/components 2/Dialog/BasicHtmlTest.tsx +0 -55
  642. package/examples/components 2/Dialog/DebugHtmlExample.tsx +0 -68
  643. package/examples/components 2/Dialog/HtmlDialogExample.tsx +0 -202
  644. package/examples/components 2/Dialog/SimpleHtmlTest.tsx +0 -61
  645. package/examples/components 2/Dialog/SmartDialogExample.tsx +0 -322
  646. package/examples/components 2/index.ts +0 -11
  647. package/examples/features/index.ts +0 -12
  648. package/examples/features/rbac/CompleteRBACExample.tsx +0 -324
  649. package/examples/features/rbac/index.ts +0 -13
  650. package/examples/public-pages/CorrectPublicPageImplementation.tsx +0 -301
  651. package/examples/public-pages/PublicEventPage.tsx +0 -274
  652. package/examples/public-pages/PublicPageApp.tsx +0 -308
  653. package/examples/public-pages/PublicPageUsageExample.tsx +0 -216
  654. package/examples/public-pages/index.ts +0 -14
  655. package/src/__tests__/TEST_STANDARD.md +0 -1008
  656. package/src/components/Checkbox/__mocks__/Checkbox.tsx +0 -2
  657. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +0 -421
  658. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +0 -177
  659. package/src/components/DataTable/examples/PerformanceExample.tsx +0 -506
  660. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +0 -316
  661. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +0 -45
  662. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +0 -211
  663. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +0 -126
  664. package/src/components/Dialog/README.md +0 -804
  665. package/src/components/Dialog/examples/BasicHtmlTest.tsx +0 -55
  666. package/src/components/Dialog/examples/DebugHtmlExample.tsx +0 -68
  667. package/src/components/Dialog/examples/ScrollableDialogExample.tsx +0 -290
  668. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +0 -61
  669. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +0 -71
  670. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +0 -122
  671. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -147
  672. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
  673. package/src/components/Dialog/utils/safeHtml.ts +0 -185
  674. package/src/components/EventSelector/types.ts +0 -79
  675. package/src/components/Form/FormErrorSummary.tsx +0 -113
  676. package/src/components/Form/FormField.tsx +0 -249
  677. package/src/components/Form/FormFieldset.tsx +0 -127
  678. package/src/components/Form/FormLiveRegion.tsx +0 -198
  679. package/src/components/Input/__mocks__/Input.tsx +0 -2
  680. package/src/components/NavigationMenu/types.ts +0 -85
  681. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -326
  682. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -1078
  683. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  684. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  685. package/src/components/PasswordReset/index.ts +0 -2
  686. package/src/components/ProtectedRoute/README.md +0 -164
  687. package/src/components/PublicLayout/EventLogo.tsx +0 -175
  688. package/src/components/PublicLayout/PublicErrorBoundary.tsx +0 -282
  689. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +0 -216
  690. package/src/components/PublicLayout/PublicPageContextChecker.tsx +0 -131
  691. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  692. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  693. package/src/components/PublicLayout/PublicPageFooter.tsx +0 -124
  694. package/src/components/PublicLayout/PublicPageHeader.tsx +0 -209
  695. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -449
  696. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -393
  697. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +0 -192
  698. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -351
  699. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -402
  700. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -460
  701. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -313
  702. package/src/components/Select/hooks.ts +0 -289
  703. package/src/hooks/useCounter.test.ts +0 -131
  704. package/src/hooks/useDebounce.test.ts +0 -375
  705. package/src/providers/AuthProvider.tsx +0 -15
  706. package/src/providers/EventProvider.tsx +0 -16
  707. package/src/providers/InactivityProvider.tsx +0 -15
  708. package/src/providers/OrganisationProvider.context.test.tsx +0 -169
  709. package/src/providers/UnifiedAuthProvider.tsx +0 -15
  710. package/src/types/theme.ts +0 -6
  711. package/src/types/unified.ts +0 -265
  712. package/src/utils/appConfig.ts +0 -47
  713. package/src/utils/appIdResolver.test.ts +0 -499
  714. package/src/utils/appIdResolver.ts +0 -130
  715. package/src/utils/appNameResolver.simple.test.ts +0 -212
  716. package/src/utils/appNameResolver.test.ts +0 -121
  717. package/src/utils/appNameResolver.ts +0 -191
  718. package/src/utils/audit.ts +0 -127
  719. package/src/utils/auth-utils.ts +0 -96
  720. package/src/utils/bundleAnalysis.ts +0 -129
  721. package/src/utils/debugLogger.ts +0 -67
  722. package/src/utils/deviceFingerprint.ts +0 -215
  723. package/src/utils/dynamicUtils.ts +0 -105
  724. package/src/utils/file-reference.test.ts +0 -788
  725. package/src/utils/file-reference.ts +0 -519
  726. package/src/utils/formatDate.test.ts +0 -237
  727. package/src/utils/formatting.ts +0 -170
  728. package/src/utils/lazyLoad.tsx +0 -44
  729. package/src/utils/logger.ts +0 -179
  730. package/src/utils/organisationContext.test.ts +0 -322
  731. package/src/utils/organisationContext.ts +0 -153
  732. package/src/utils/performanceBenchmark.ts +0 -64
  733. package/src/utils/performanceBudgets.ts +0 -110
  734. package/src/utils/permissionTypes.ts +0 -37
  735. package/src/utils/permissionUtils.test.ts +0 -393
  736. package/src/utils/permissionUtils.ts +0 -34
  737. package/src/utils/sanitization.ts +0 -264
  738. package/src/utils/schemaUtils.ts +0 -37
  739. package/src/utils/secureDataAccess.test.ts +0 -711
  740. package/src/utils/secureDataAccess.ts +0 -377
  741. package/src/utils/secureErrors.ts +0 -79
  742. package/src/utils/security.ts +0 -156
  743. package/src/utils/securityMonitor.ts +0 -45
  744. package/src/utils/sessionTracking.ts +0 -126
  745. package/src/utils/validation.ts +0 -111
  746. package/src/utils/validationUtils.ts +0 -120
  747. package/src/validation/index.ts +0 -12
  748. /package/dist/{DataTable-UA6CL4JI.js.map → DataTable-QAB34V6K.js.map} +0 -0
  749. /package/dist/{UnifiedAuthProvider-B37ATQHE.js.map → UnifiedAuthProvider-7F6T4B6K.js.map} +0 -0
  750. /package/dist/{api-45XYYO2A.js.map → api-ROMBCNKU.js.map} +0 -0
  751. /package/dist/{audit-64X3VJXB.js.map → audit-WRS3KJKI.js.map} +0 -0
  752. /package/dist/{chunk-PLDDJCW6.js.map → chunk-7D4SUZUM.js.map} +0 -0
  753. /package/dist/{useInactivityTracker-TO6ZOF35.js.map → chunk-KQCRWDSA.js.map} +0 -0
  754. /package/examples/{components 2/DataTable → DataTable}/InitialPageSizeExample.tsx +0 -0
  755. /package/examples/{features/public-pages → PublicPages}/index.ts +0 -0
  756. /package/examples/{RBAC → rbac}/index.ts +0 -0
@@ -0,0 +1,1210 @@
1
+ /**
2
+ * @file PublicLayout Component Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/PublicLayout
5
+ * @since 1.0.0
6
+ *
7
+ * Comprehensive test suite for all PublicLayout components following testing standards.
8
+ * Tests cover all major functionality, edge cases, user interactions, and accessibility.
9
+ */
10
+
11
+ import React from 'react';
12
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
13
+ import userEvent from '@testing-library/user-event';
14
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
15
+ import {
16
+ PublicPageLayout,
17
+ PublicPageHeader,
18
+ PublicPageFooter
19
+ } from './PublicPageLayout';
20
+ import { PublicPageProvider, usePublicPageContext, useIsPublicPage } from './PublicPageProvider';
21
+ import { useEventTheme } from '../../hooks/useEventTheme';
22
+ import type { Event } from '../../types/event';
23
+ import { assertOrganisationId } from '../../types/core';
24
+
25
+ // === SHARED MOCKS ===
26
+
27
+ vi.mock('../ErrorBoundary', () => ({
28
+ ErrorBoundary: vi.fn(({ children }) => <div data-testid="error-boundary">{children}</div>)
29
+ }));
30
+
31
+ vi.mock('../LoadingSpinner', () => ({
32
+ LoadingSpinner: vi.fn(({ size, className }) => (
33
+ <div data-testid="loading-spinner" data-size={size} className={className}>
34
+ Loading...
35
+ </div>
36
+ ))
37
+ }));
38
+
39
+ vi.mock('../../Button', () => ({
40
+ Button: vi.fn(({ children, onClick, ...props }) => (
41
+ <button onClick={onClick} {...props}>
42
+ {children}
43
+ </button>
44
+ ))
45
+ }));
46
+
47
+ vi.mock('../../hooks/useEventTheme', () => ({
48
+ useEventTheme: vi.fn()
49
+ }));
50
+
51
+ // Don't mock PublicPageProvider - let tests use the actual implementation
52
+ // Instead, mock useAppConfig to work with public page context
53
+
54
+ // Use vi.hoisted() to avoid hoisting issues
55
+ // Mock useAppConfig to return a default config without requiring UnifiedAuthProvider
56
+ const mockUseAppConfig = vi.hoisted(() => vi.fn(() => ({
57
+ appName: 'Test App',
58
+ supportsDirectAccess: false,
59
+ requiresEvent: true,
60
+ isLoading: false,
61
+ })));
62
+
63
+ vi.mock('../../hooks/useAppConfig', () => ({
64
+ useAppConfig: mockUseAppConfig
65
+ }));
66
+
67
+ vi.mock('../FileDisplay/FileDisplay', () => ({
68
+ FileDisplay: vi.fn(({ table_name, record_id, organisation_id, category, className, generateFallbackText }) => (
69
+ <div
70
+ data-testid="event-logo"
71
+ data-table-name={table_name}
72
+ data-record-id={record_id}
73
+ data-organisation-id={organisation_id}
74
+ data-category={category}
75
+ className={className}
76
+ >
77
+ Event Logo
78
+ </div>
79
+ ))
80
+ }));
81
+
82
+ vi.mock('../../utils/core/cn', () => ({
83
+ cn: vi.fn((...classes) => classes.filter(Boolean).join(' '))
84
+ }));
85
+
86
+ // Mock Supabase client - use vi.hoisted to make it accessible in tests
87
+ const mockCreateClient = vi.hoisted(() => vi.fn(() => ({
88
+ from: vi.fn(),
89
+ rpc: vi.fn(),
90
+ })));
91
+
92
+ vi.mock('@supabase/supabase-js', () => ({
93
+ createClient: mockCreateClient
94
+ }));
95
+
96
+ // Mock logger
97
+ // Note: Must define mock inside factory to avoid hoisting issues
98
+ vi.mock('../../utils/core/logger', () => {
99
+ const mockLogger = {
100
+ debug: vi.fn(),
101
+ info: vi.fn(),
102
+ warn: vi.fn(),
103
+ error: vi.fn(),
104
+ createScopedLogger: vi.fn(() => mockLogger),
105
+ configure: vi.fn(),
106
+ };
107
+
108
+ return {
109
+ logger: mockLogger,
110
+ createLogger: () => mockLogger,
111
+ Logger: {
112
+ debug: vi.fn(),
113
+ info: vi.fn(),
114
+ warn: vi.fn(),
115
+ error: vi.fn(),
116
+ configure: vi.fn(),
117
+ createScopedLogger: vi.fn(() => mockLogger),
118
+ },
119
+ LogLevel: {
120
+ DEBUG: 0,
121
+ INFO: 1,
122
+ WARN: 2,
123
+ ERROR: 3,
124
+ },
125
+ };
126
+ });
127
+
128
+ // Mock event data
129
+ const mockEvent: Event = {
130
+ event_id: 'event-123',
131
+ event_name: 'Test Event',
132
+ event_venue: 'Test Venue',
133
+ organisation_id: assertOrganisationId('org-123'),
134
+ event_start_date: '2024-01-01',
135
+ event_end_date: '2024-01-02',
136
+ event_description: 'Test event description',
137
+ event_status: 'active',
138
+ created_at: '2024-01-01T00:00:00Z',
139
+ updated_at: '2024-01-01T00:00:00Z'
140
+ };
141
+
142
+ const mockEventWithoutVenue: Event = {
143
+ ...mockEvent,
144
+ event_venue: undefined
145
+ };
146
+
147
+ // === PUBLIC PAGE LAYOUT TESTS ===
148
+
149
+ describe('[component] PublicPageLayout', () => {
150
+ const mockUseEventTheme = vi.mocked(useEventTheme);
151
+
152
+ beforeEach(() => {
153
+ vi.clearAllMocks();
154
+ });
155
+
156
+ describe('Event Theming', () => {
157
+ it('applies event theme when event is provided', () => {
158
+ const eventWithColours: Event = {
159
+ ...mockEvent,
160
+ event_colours: {
161
+ main: { '500': { L: 0.5, C: 0.2, H: 0 } },
162
+ sec: { '500': { L: 0.5, C: 0.2, H: 120 } },
163
+ acc: { '500': { L: 0.5, C: 0.2, H: 240 } }
164
+ }
165
+ };
166
+
167
+ render(
168
+ <PublicPageLayout eventCode="EVENT123" event={eventWithColours}>
169
+ <div>Test Content</div>
170
+ </PublicPageLayout>
171
+ );
172
+
173
+ expect(mockUseEventTheme).toHaveBeenCalledWith(eventWithColours);
174
+ });
175
+
176
+ it('applies theme with null event', () => {
177
+ render(
178
+ <PublicPageLayout eventCode="EVENT123" event={null}>
179
+ <div>Test Content</div>
180
+ </PublicPageLayout>
181
+ );
182
+
183
+ expect(mockUseEventTheme).toHaveBeenCalledWith(null);
184
+ });
185
+
186
+ it('applies theme with undefined event', () => {
187
+ render(
188
+ <PublicPageLayout eventCode="EVENT123" event={undefined} showValidationErrors={false}>
189
+ <div>Test Content</div>
190
+ </PublicPageLayout>
191
+ );
192
+
193
+ // When event is undefined, it gets defaulted to null in the function signature
194
+ // But useEventTheme is called before the early return, so it should be called
195
+ expect(mockUseEventTheme).toHaveBeenCalled();
196
+ });
197
+ });
198
+
199
+ describe('Loading States', () => {
200
+ it('shows loading spinner when isLoading is true', () => {
201
+ render(
202
+ <PublicPageLayout eventCode="EVENT123" isLoading={true}>
203
+ <div>Test Content</div>
204
+ </PublicPageLayout>
205
+ );
206
+
207
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
208
+ expect(screen.queryByText('Test Content')).not.toBeInTheDocument();
209
+ });
210
+
211
+ it('shows custom loading message when provided', () => {
212
+ render(
213
+ <PublicPageLayout
214
+ eventCode="EVENT123"
215
+ isLoading={true}
216
+ loadingMessage="Loading event data..."
217
+ >
218
+ <div>Test Content</div>
219
+ </PublicPageLayout>
220
+ );
221
+
222
+ expect(screen.getByText('Loading event data...')).toBeInTheDocument();
223
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
224
+ });
225
+
226
+ it('uses custom loading fallback when provided', () => {
227
+ const CustomLoading = () => <div data-testid="custom-loading">Custom Loading</div>;
228
+
229
+ render(
230
+ <PublicPageLayout
231
+ eventCode="EVENT123"
232
+ isLoading={true}
233
+ loadingFallback={CustomLoading}
234
+ >
235
+ <div>Test Content</div>
236
+ </PublicPageLayout>
237
+ );
238
+
239
+ expect(screen.getByTestId('custom-loading')).toBeInTheDocument();
240
+ expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
241
+ });
242
+
243
+ it('renders loading state with proper layout classes', () => {
244
+ const { container } = render(
245
+ <PublicPageLayout eventCode="EVENT123" isLoading={true}>
246
+ <div>Test Content</div>
247
+ </PublicPageLayout>
248
+ );
249
+
250
+ const loadingContainer = container.querySelector('.min-h-screen');
251
+ expect(loadingContainer).toBeInTheDocument();
252
+ expect(loadingContainer).toHaveClass('bg-background', 'flex', 'items-center', 'justify-center');
253
+ });
254
+ });
255
+
256
+ describe('Error States', () => {
257
+ it('renders error state when error is provided', () => {
258
+ const error = new Error('Event not found');
259
+
260
+ render(
261
+ <PublicPageLayout eventCode="EVENT123" error={error}>
262
+ <div>Test Content</div>
263
+ </PublicPageLayout>
264
+ );
265
+
266
+ expect(screen.getByText('Event Not Found')).toBeInTheDocument();
267
+ expect(screen.getByText(/The event code "EVENT123" is invalid/)).toBeInTheDocument();
268
+ expect(screen.getByText('Try Again')).toBeInTheDocument();
269
+ });
270
+
271
+ it('calls refetch when Try Again button is clicked', async () => {
272
+ const user = userEvent.setup();
273
+ const mockRefetch = vi.fn().mockResolvedValue(undefined);
274
+ const error = new Error('Event not found');
275
+
276
+ render(
277
+ <PublicPageLayout eventCode="EVENT123" error={error} refetch={mockRefetch}>
278
+ <div>Test Content</div>
279
+ </PublicPageLayout>
280
+ );
281
+
282
+ const tryAgainButton = screen.getByText('Try Again');
283
+ await user.click(tryAgainButton);
284
+
285
+ expect(mockRefetch).toHaveBeenCalledTimes(1);
286
+ });
287
+
288
+ it('uses custom error fallback when provided', () => {
289
+ const CustomError = ({ error, retry }: { error: Error; retry: () => void }) => (
290
+ <div data-testid="custom-error">
291
+ Custom Error: {error.message}
292
+ <button onClick={retry}>Retry</button>
293
+ </div>
294
+ );
295
+ const error = new Error('Custom error');
296
+
297
+ render(
298
+ <PublicPageLayout
299
+ eventCode="EVENT123"
300
+ error={error}
301
+ errorFallback={CustomError}
302
+ >
303
+ <div>Test Content</div>
304
+ </PublicPageLayout>
305
+ );
306
+
307
+ expect(screen.getByTestId('custom-error')).toBeInTheDocument();
308
+ expect(screen.getByText('Custom Error: Custom error')).toBeInTheDocument();
309
+ expect(screen.queryByText('Event Not Found')).not.toBeInTheDocument();
310
+ });
311
+
312
+ it('hides error state when showValidationErrors is false', () => {
313
+ const error = new Error('Event not found');
314
+
315
+ render(
316
+ <PublicPageLayout
317
+ eventCode="EVENT123"
318
+ error={error}
319
+ showValidationErrors={false}
320
+ >
321
+ <div data-testid="content">Test Content</div>
322
+ </PublicPageLayout>
323
+ );
324
+
325
+ expect(screen.getByTestId('content')).toBeInTheDocument();
326
+ expect(screen.queryByText('Event Not Found')).not.toBeInTheDocument();
327
+ });
328
+
329
+ it('handles refetch function that returns void', async () => {
330
+ const user = userEvent.setup();
331
+ const mockRefetch = vi.fn();
332
+ const error = new Error('Event not found');
333
+
334
+ render(
335
+ <PublicPageLayout eventCode="EVENT123" error={error} refetch={mockRefetch}>
336
+ <div>Test Content</div>
337
+ </PublicPageLayout>
338
+ );
339
+
340
+ const tryAgainButton = screen.getByText('Try Again');
341
+ await user.click(tryAgainButton);
342
+
343
+ expect(mockRefetch).toHaveBeenCalledTimes(1);
344
+ });
345
+ });
346
+
347
+ describe('Missing Event State', () => {
348
+ it('renders missing event state when no event is provided', () => {
349
+ render(
350
+ <PublicPageLayout eventCode="EVENT123">
351
+ <div>Test Content</div>
352
+ </PublicPageLayout>
353
+ );
354
+
355
+ expect(screen.getByText('Event Not Available')).toBeInTheDocument();
356
+ expect(screen.getByText('This event is not available for public viewing.')).toBeInTheDocument();
357
+ expect(screen.getByText('Try Again')).toBeInTheDocument();
358
+ });
359
+
360
+ it('calls refetch when Try Again is clicked in missing event state', async () => {
361
+ const user = userEvent.setup();
362
+ const mockRefetch = vi.fn().mockResolvedValue(undefined);
363
+
364
+ render(
365
+ <PublicPageLayout eventCode="EVENT123" refetch={mockRefetch}>
366
+ <div>Test Content</div>
367
+ </PublicPageLayout>
368
+ );
369
+
370
+ const tryAgainButton = screen.getByText('Try Again');
371
+ await user.click(tryAgainButton);
372
+
373
+ expect(mockRefetch).toHaveBeenCalledTimes(1);
374
+ });
375
+
376
+ it('hides validation errors when showValidationErrors is false', () => {
377
+ render(
378
+ <PublicPageLayout eventCode="EVENT123" showValidationErrors={false}>
379
+ <div data-testid="content">Test Content</div>
380
+ </PublicPageLayout>
381
+ );
382
+
383
+ expect(screen.getByTestId('content')).toBeInTheDocument();
384
+ expect(screen.queryByText('Event Not Available')).not.toBeInTheDocument();
385
+ });
386
+
387
+ it('does not show Try Again button when refetch is not provided', () => {
388
+ render(
389
+ <PublicPageLayout eventCode="EVENT123">
390
+ <div>Test Content</div>
391
+ </PublicPageLayout>
392
+ );
393
+
394
+ // Should still show Try Again button (default refetch is provided)
395
+ expect(screen.getByText('Try Again')).toBeInTheDocument();
396
+ });
397
+ });
398
+
399
+ describe('Rendering', () => {
400
+ it('renders with basic props', () => {
401
+ render(
402
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent}>
403
+ <div data-testid="content">Test Content</div>
404
+ </PublicPageLayout>
405
+ );
406
+
407
+ expect(screen.getByTestId('error-boundary')).toBeInTheDocument();
408
+ expect(screen.getByTestId('content')).toBeInTheDocument();
409
+ });
410
+
411
+ it('renders header by default', () => {
412
+ render(
413
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent}>
414
+ <div>Test Content</div>
415
+ </PublicPageLayout>
416
+ );
417
+
418
+ expect(screen.getByRole('banner')).toBeInTheDocument();
419
+ });
420
+
421
+ it('renders footer by default when event exists', () => {
422
+ render(
423
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent}>
424
+ <div>Test Content</div>
425
+ </PublicPageLayout>
426
+ );
427
+
428
+ expect(screen.getByRole('contentinfo')).toBeInTheDocument();
429
+ });
430
+
431
+ it('does not render footer when showFooter is false', () => {
432
+ render(
433
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent} showFooter={false}>
434
+ <div data-testid="content">Test Content</div>
435
+ </PublicPageLayout>
436
+ );
437
+
438
+ expect(screen.getByRole('banner')).toBeInTheDocument();
439
+ expect(screen.queryByRole('contentinfo')).not.toBeInTheDocument();
440
+ });
441
+
442
+ it('does not render footer when event is null', () => {
443
+ render(
444
+ <PublicPageLayout eventCode="EVENT123" event={null} showValidationErrors={false}>
445
+ <div data-testid="content">Test Content</div>
446
+ </PublicPageLayout>
447
+ );
448
+
449
+ expect(screen.queryByRole('contentinfo')).not.toBeInTheDocument();
450
+ });
451
+
452
+ it('renders with custom header', () => {
453
+ const customHeader = <div data-testid="custom-header">Custom Header</div>;
454
+
455
+ render(
456
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent} customHeader={customHeader}>
457
+ <div data-testid="content">Test Content</div>
458
+ </PublicPageLayout>
459
+ );
460
+
461
+ expect(screen.getByTestId('custom-header')).toBeInTheDocument();
462
+ expect(screen.queryByRole('banner')).not.toBeInTheDocument();
463
+ });
464
+
465
+ it('renders with custom footer', () => {
466
+ const customFooter = <div data-testid="custom-footer">Custom Footer</div>;
467
+
468
+ render(
469
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent} customFooter={customFooter}>
470
+ <div data-testid="content">Test Content</div>
471
+ </PublicPageLayout>
472
+ );
473
+
474
+ expect(screen.getByTestId('custom-footer')).toBeInTheDocument();
475
+ });
476
+
477
+ it('renders main content with correct classes', () => {
478
+ const { container } = render(
479
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent}>
480
+ <div>Test Content</div>
481
+ </PublicPageLayout>
482
+ );
483
+
484
+ const main = container.querySelector('main');
485
+ expect(main).toBeInTheDocument();
486
+ expect(main).toHaveClass('px-4', 'w-[min(var(--app-width),100%)]', 'mx-auto', 'py-8');
487
+ });
488
+
489
+ it('wraps content in error boundary', () => {
490
+ render(
491
+ <PublicPageLayout eventCode="EVENT123" event={mockEvent}>
492
+ <div>Test Content</div>
493
+ </PublicPageLayout>
494
+ );
495
+
496
+ expect(screen.getByTestId('error-boundary')).toBeInTheDocument();
497
+ });
498
+ });
499
+
500
+ describe('Edge Cases', () => {
501
+ it('handles empty eventCode', () => {
502
+ render(
503
+ <PublicPageLayout eventCode="" event={mockEvent}>
504
+ <div data-testid="content">Test Content</div>
505
+ </PublicPageLayout>
506
+ );
507
+
508
+ expect(screen.getByTestId('content')).toBeInTheDocument();
509
+ });
510
+
511
+ it('handles event without venue', () => {
512
+ render(
513
+ <PublicPageLayout eventCode="EVENT123" event={mockEventWithoutVenue}>
514
+ <div data-testid="content">Test Content</div>
515
+ </PublicPageLayout>
516
+ );
517
+
518
+ expect(screen.getByTestId('content')).toBeInTheDocument();
519
+ expect(screen.queryByText('Test Venue')).not.toBeInTheDocument();
520
+ });
521
+
522
+ it('handles deprecated className prop gracefully', () => {
523
+ const { container } = render(
524
+ <PublicPageLayout
525
+ eventCode="EVENT123"
526
+ event={mockEvent}
527
+ className="deprecated-class"
528
+ >
529
+ <div>Test Content</div>
530
+ </PublicPageLayout>
531
+ );
532
+
533
+ // Component should still render even with deprecated prop
534
+ expect(container).toBeInTheDocument();
535
+ });
536
+ });
537
+ });
538
+
539
+ // === PUBLIC PAGE HEADER TESTS ===
540
+
541
+ describe('[component] PublicPageHeader', () => {
542
+ beforeEach(() => {
543
+ vi.clearAllMocks();
544
+ mockUseAppConfig.mockReturnValue({
545
+ appName: 'Test App'
546
+ });
547
+ });
548
+
549
+ describe('Rendering', () => {
550
+ it('renders with basic props', () => {
551
+ render(
552
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
553
+ );
554
+
555
+ expect(screen.getByRole('banner')).toBeInTheDocument();
556
+ expect(screen.getByText('Test Event')).toBeInTheDocument();
557
+ expect(screen.getByText('Test Venue')).toBeInTheDocument();
558
+ });
559
+
560
+ it('renders with custom className', () => {
561
+ const { container } = render(
562
+ <PublicPageHeader
563
+ event={mockEvent}
564
+ eventCode="EVENT123"
565
+ className="custom-header-class"
566
+ />
567
+ );
568
+
569
+ const header = container.firstChild as HTMLElement;
570
+ expect(header).toHaveClass('custom-header-class');
571
+ });
572
+
573
+ it('renders with title and description', () => {
574
+ render(
575
+ <PublicPageHeader
576
+ event={mockEvent}
577
+ eventCode="EVENT123"
578
+ title="Page Title"
579
+ description="Page Description"
580
+ />
581
+ );
582
+
583
+ expect(screen.getByText('Page Title')).toBeInTheDocument();
584
+ expect(screen.getByText('Page Description')).toBeInTheDocument();
585
+ });
586
+
587
+ it('renders with custom children', () => {
588
+ render(
589
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123">
590
+ <div data-testid="custom-content">Custom Content</div>
591
+ </PublicPageHeader>
592
+ );
593
+
594
+ expect(screen.getByTestId('custom-content')).toBeInTheDocument();
595
+ });
596
+
597
+ it('renders without event', () => {
598
+ render(
599
+ <PublicPageHeader event={undefined} eventCode="EVENT123" />
600
+ );
601
+
602
+ expect(screen.getByRole('banner')).toBeInTheDocument();
603
+ expect(screen.queryByText('Test Event')).not.toBeInTheDocument();
604
+ });
605
+ });
606
+
607
+ describe('Logo Display', () => {
608
+ it('shows app logo by default', () => {
609
+ render(
610
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
611
+ );
612
+
613
+ const appLogo = screen.getByAltText('Test App');
614
+ expect(appLogo).toBeInTheDocument();
615
+ expect(appLogo).toHaveAttribute('src', '/test app_logo_wide.svg');
616
+ });
617
+
618
+ it('hides app logo when showAppLogo is false', () => {
619
+ render(
620
+ <PublicPageHeader
621
+ event={mockEvent}
622
+ eventCode="EVENT123"
623
+ showAppLogo={false}
624
+ />
625
+ );
626
+
627
+ expect(screen.queryByAltText('Test App')).not.toBeInTheDocument();
628
+ });
629
+
630
+ it('hides app logo when appName is not available', () => {
631
+ mockUseAppConfig.mockReturnValueOnce({
632
+ appName: null
633
+ });
634
+
635
+ render(
636
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
637
+ );
638
+
639
+ expect(screen.queryByAltText('Test App')).not.toBeInTheDocument();
640
+ });
641
+
642
+ it('shows event logo by default', () => {
643
+ render(
644
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
645
+ );
646
+
647
+ expect(screen.getByTestId('event-logo')).toBeInTheDocument();
648
+ expect(screen.getByTestId('event-logo')).toHaveAttribute('data-table-name', 'event');
649
+ expect(screen.getByTestId('event-logo')).toHaveAttribute('data-record-id', 'event-123');
650
+ });
651
+
652
+ it('hides event logo when showEventLogo is false', () => {
653
+ render(
654
+ <PublicPageHeader
655
+ event={mockEvent}
656
+ eventCode="EVENT123"
657
+ showEventLogo={false}
658
+ />
659
+ );
660
+
661
+ expect(screen.queryByTestId('event-logo')).not.toBeInTheDocument();
662
+ });
663
+
664
+ it('uses custom event logo when provided', () => {
665
+ const customLogo = <div data-testid="custom-event-logo">Custom Logo</div>;
666
+
667
+ render(
668
+ <PublicPageHeader
669
+ event={mockEvent}
670
+ eventCode="EVENT123"
671
+ customEventLogo={customLogo}
672
+ />
673
+ );
674
+
675
+ expect(screen.getByTestId('custom-event-logo')).toBeInTheDocument();
676
+ expect(screen.queryByTestId('event-logo')).not.toBeInTheDocument();
677
+ });
678
+
679
+ it('does not show event logo when event is not provided', () => {
680
+ render(
681
+ <PublicPageHeader event={undefined} eventCode="EVENT123" />
682
+ );
683
+
684
+ expect(screen.queryByTestId('event-logo')).not.toBeInTheDocument();
685
+ });
686
+ });
687
+
688
+ describe('Event Information', () => {
689
+ it('displays event name as main heading', () => {
690
+ render(
691
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
692
+ );
693
+
694
+ const heading = screen.getByRole('heading', { level: 1 });
695
+ expect(heading).toHaveTextContent('Test Event');
696
+ });
697
+
698
+ it('displays event venue when available', () => {
699
+ render(
700
+ <PublicPageHeader event={mockEvent} eventCode="EVENT123" />
701
+ );
702
+
703
+ expect(screen.getByText('Test Venue')).toBeInTheDocument();
704
+ });
705
+
706
+ it('does not display venue when event has no venue', () => {
707
+ render(
708
+ <PublicPageHeader event={mockEventWithoutVenue} eventCode="EVENT123" />
709
+ );
710
+
711
+ expect(screen.queryByText('Test Venue')).not.toBeInTheDocument();
712
+ });
713
+
714
+ it('displays event name even when venue is missing', () => {
715
+ render(
716
+ <PublicPageHeader event={mockEventWithoutVenue} eventCode="EVENT123" />
717
+ );
718
+
719
+ expect(screen.getByText('Test Event')).toBeInTheDocument();
720
+ });
721
+ });
722
+
723
+ describe('Title and Description', () => {
724
+ it('prioritizes title over event name when both are provided', () => {
725
+ render(
726
+ <PublicPageHeader
727
+ event={mockEvent}
728
+ eventCode="EVENT123"
729
+ title="Custom Title"
730
+ />
731
+ );
732
+
733
+ const headings = screen.getAllByRole('heading', { level: 1 });
734
+ expect(headings.some(h => h.textContent === 'Custom Title')).toBe(true);
735
+ });
736
+
737
+ it('renders description when provided with title', () => {
738
+ render(
739
+ <PublicPageHeader
740
+ event={mockEvent}
741
+ eventCode="EVENT123"
742
+ title="Page Title"
743
+ description="Page Description"
744
+ />
745
+ );
746
+
747
+ expect(screen.getByText('Page Description')).toBeInTheDocument();
748
+ });
749
+
750
+ it('does not render description without title', () => {
751
+ render(
752
+ <PublicPageHeader
753
+ event={mockEvent}
754
+ eventCode="EVENT123"
755
+ description="Page Description"
756
+ />
757
+ );
758
+
759
+ expect(screen.queryByText('Page Description')).not.toBeInTheDocument();
760
+ });
761
+ });
762
+ });
763
+
764
+ // === PUBLIC PAGE FOOTER TESTS ===
765
+
766
+ describe('[component] PublicPageFooter', () => {
767
+ beforeEach(() => {
768
+ vi.clearAllMocks();
769
+ });
770
+
771
+ describe('Rendering', () => {
772
+ it('renders with basic props', () => {
773
+ render(<PublicPageFooter event={mockEvent} />);
774
+
775
+ expect(screen.getByRole('contentinfo')).toBeInTheDocument();
776
+ expect(screen.getByText(/© Copyright 2022–/)).toBeInTheDocument();
777
+ expect(screen.getByText(/Solvera Solutions Pty Ltd/)).toBeInTheDocument();
778
+ });
779
+
780
+ it('renders with custom company name', () => {
781
+ render(
782
+ <PublicPageFooter
783
+ event={mockEvent}
784
+ companyName="Custom Company"
785
+ />
786
+ );
787
+
788
+ expect(screen.getByText(/Custom Company/)).toBeInTheDocument();
789
+ });
790
+
791
+ it('renders with custom copyright text', () => {
792
+ render(
793
+ <PublicPageFooter
794
+ event={mockEvent}
795
+ copyright="Custom copyright text"
796
+ />
797
+ );
798
+
799
+ expect(screen.getByText('Custom copyright text')).toBeInTheDocument();
800
+ });
801
+
802
+ it('renders with custom year', () => {
803
+ render(
804
+ <PublicPageFooter
805
+ event={mockEvent}
806
+ year={2025}
807
+ />
808
+ );
809
+
810
+ expect(screen.getByText(/© Copyright 2022–2025/)).toBeInTheDocument();
811
+ });
812
+
813
+ it('renders with logo when provided', () => {
814
+ render(
815
+ <PublicPageFooter
816
+ event={mockEvent}
817
+ logo="/path/to/logo.png"
818
+ />
819
+ );
820
+
821
+ const logo = screen.getByAltText('Logo');
822
+ expect(logo).toBeInTheDocument();
823
+ expect(logo).toHaveAttribute('src', '/path/to/logo.png');
824
+ });
825
+
826
+ it('renders with custom children', () => {
827
+ render(
828
+ <PublicPageFooter event={mockEvent}>
829
+ <div data-testid="footer-content">Footer Content</div>
830
+ </PublicPageFooter>
831
+ );
832
+
833
+ expect(screen.getByTestId('footer-content')).toBeInTheDocument();
834
+ });
835
+
836
+ it('renders with custom className', () => {
837
+ const { container } = render(
838
+ <PublicPageFooter
839
+ event={mockEvent}
840
+ className="custom-footer-class"
841
+ />
842
+ );
843
+
844
+ const footer = container.firstChild as HTMLElement;
845
+ expect(footer).toHaveClass('custom-footer-class');
846
+ });
847
+ });
848
+
849
+ describe('Navigation Links', () => {
850
+ it('renders navigation links when provided', () => {
851
+ const links = [
852
+ { label: 'Home', href: '/' },
853
+ { label: 'About', href: '/about' }
854
+ ];
855
+
856
+ render(
857
+ <PublicPageFooter
858
+ event={mockEvent}
859
+ links={links}
860
+ />
861
+ );
862
+
863
+ const homeLink = screen.getByText('Home');
864
+ const aboutLink = screen.getByText('About');
865
+
866
+ expect(homeLink).toBeInTheDocument();
867
+ expect(aboutLink).toBeInTheDocument();
868
+ expect(homeLink.closest('a')).toHaveAttribute('href', '/');
869
+ expect(aboutLink.closest('a')).toHaveAttribute('href', '/about');
870
+ });
871
+
872
+ it('does not render links when empty array is provided', () => {
873
+ render(
874
+ <PublicPageFooter
875
+ event={mockEvent}
876
+ links={[]}
877
+ />
878
+ );
879
+
880
+ expect(screen.queryByRole('list')).not.toBeInTheDocument();
881
+ });
882
+
883
+ it('renders multiple links correctly', () => {
884
+ const links = [
885
+ { label: 'Home', href: '/' },
886
+ { label: 'About', href: '/about' },
887
+ { label: 'Contact', href: '/contact' }
888
+ ];
889
+
890
+ render(
891
+ <PublicPageFooter
892
+ event={mockEvent}
893
+ links={links}
894
+ />
895
+ );
896
+
897
+ expect(screen.getByText('Home')).toBeInTheDocument();
898
+ expect(screen.getByText('About')).toBeInTheDocument();
899
+ expect(screen.getByText('Contact')).toBeInTheDocument();
900
+ });
901
+ });
902
+
903
+ describe('Copyright Text', () => {
904
+ it('uses default copyright format', () => {
905
+ const currentYear = new Date().getFullYear();
906
+ render(<PublicPageFooter event={mockEvent} />);
907
+
908
+ expect(screen.getByText(new RegExp(`© Copyright 2022–${currentYear}`))).toBeInTheDocument();
909
+ });
910
+
911
+ it('uses custom copyright when provided', () => {
912
+ render(
913
+ <PublicPageFooter
914
+ event={mockEvent}
915
+ copyright="All rights reserved"
916
+ />
917
+ );
918
+
919
+ expect(screen.getByText('All rights reserved')).toBeInTheDocument();
920
+ expect(screen.queryByText(/© Copyright/)).not.toBeInTheDocument();
921
+ });
922
+ });
923
+ });
924
+
925
+ // === PUBLIC PAGE PROVIDER TESTS ===
926
+
927
+ describe('[component] PublicPageProvider', () => {
928
+ const originalEnv = import.meta.env;
929
+ const originalProcess = process.env;
930
+
931
+ beforeEach(() => {
932
+ vi.clearAllMocks();
933
+ Object.defineProperty(import.meta, 'env', {
934
+ value: {},
935
+ writable: true,
936
+ configurable: true
937
+ });
938
+ process.env = {};
939
+ });
940
+
941
+ afterEach(() => {
942
+ Object.defineProperty(import.meta, 'env', {
943
+ value: originalEnv,
944
+ writable: true,
945
+ configurable: true
946
+ });
947
+ process.env = originalProcess;
948
+ });
949
+
950
+ describe('Rendering', () => {
951
+ it('renders children without crashing', () => {
952
+ render(
953
+ <PublicPageProvider>
954
+ <div>Test Content</div>
955
+ </PublicPageProvider>
956
+ );
957
+
958
+ expect(screen.getByText('Test Content')).toBeInTheDocument();
959
+ });
960
+
961
+ it('wraps children in error boundary', () => {
962
+ render(
963
+ <PublicPageProvider>
964
+ <div>Test Content</div>
965
+ </PublicPageProvider>
966
+ );
967
+
968
+ expect(screen.getByTestId('error-boundary')).toBeInTheDocument();
969
+ });
970
+ });
971
+
972
+ describe('Context API', () => {
973
+ it('provides context with isPublicPage flag', () => {
974
+ const TestComponent = () => {
975
+ const context = usePublicPageContext();
976
+ return <div>{context.isPublicPage ? 'true' : 'false'}</div>;
977
+ };
978
+
979
+ render(
980
+ <PublicPageProvider>
981
+ <TestComponent />
982
+ </PublicPageProvider>
983
+ );
984
+
985
+ expect(screen.getByText('true')).toBeInTheDocument();
986
+ });
987
+
988
+ it('provides appName in context', () => {
989
+ const TestComponent = () => {
990
+ const context = usePublicPageContext();
991
+ return <div>{context.appName || 'no-app-name'}</div>;
992
+ };
993
+
994
+ render(
995
+ <PublicPageProvider appName="TestApp">
996
+ <TestComponent />
997
+ </PublicPageProvider>
998
+ );
999
+
1000
+ expect(screen.getByText('TestApp')).toBeInTheDocument();
1001
+ });
1002
+
1003
+ it('provides null appName when not specified', () => {
1004
+ const TestComponent = () => {
1005
+ const context = usePublicPageContext();
1006
+ return <div>{context.appName === null ? 'null' : 'not-null'}</div>;
1007
+ };
1008
+
1009
+ render(
1010
+ <PublicPageProvider>
1011
+ <TestComponent />
1012
+ </PublicPageProvider>
1013
+ );
1014
+
1015
+ expect(screen.getByText('null')).toBeInTheDocument();
1016
+ });
1017
+
1018
+ it('provides environment variables in context', () => {
1019
+ // Set environment variables - need to set both import.meta.env and process.env
1020
+ // since the component checks both
1021
+ const mockEnv = {
1022
+ VITE_SUPABASE_URL: 'https://test.supabase.co',
1023
+ VITE_SUPABASE_ANON_KEY: 'test-key'
1024
+ };
1025
+
1026
+ Object.defineProperty(import.meta, 'env', {
1027
+ value: mockEnv,
1028
+ writable: true,
1029
+ configurable: true
1030
+ });
1031
+
1032
+ // Also set process.env as fallback
1033
+ const originalProcessEnv = process.env;
1034
+ process.env = {
1035
+ ...originalProcessEnv,
1036
+ VITE_SUPABASE_URL: 'https://test.supabase.co',
1037
+ VITE_SUPABASE_ANON_KEY: 'test-key'
1038
+ };
1039
+
1040
+ const TestComponent = () => {
1041
+ const context = usePublicPageContext();
1042
+ return (
1043
+ <div>
1044
+ <span data-testid="url">{context.environment.supabaseUrl || 'no-url'}</span>
1045
+ <span data-testid="key">{context.environment.supabaseKey || 'no-key'}</span>
1046
+ </div>
1047
+ );
1048
+ };
1049
+
1050
+ render(
1051
+ <PublicPageProvider>
1052
+ <TestComponent />
1053
+ </PublicPageProvider>
1054
+ );
1055
+
1056
+ expect(screen.getByTestId('url')).toHaveTextContent('https://test.supabase.co');
1057
+ expect(screen.getByTestId('key')).toHaveTextContent('test-key');
1058
+ });
1059
+ });
1060
+
1061
+ describe('Supabase Client Creation', () => {
1062
+ beforeEach(() => {
1063
+ mockCreateClient.mockClear();
1064
+ });
1065
+
1066
+ it('creates Supabase client when environment variables are available', () => {
1067
+ const originalEnv = import.meta.env;
1068
+ const originalProcessEnv = process.env;
1069
+
1070
+ // Set environment variables - need to set both import.meta.env and process.env
1071
+ const mockEnv = {
1072
+ VITE_SUPABASE_URL: 'https://test.supabase.co',
1073
+ VITE_SUPABASE_ANON_KEY: 'test-key'
1074
+ };
1075
+
1076
+ Object.defineProperty(import.meta, 'env', {
1077
+ value: mockEnv,
1078
+ writable: true,
1079
+ configurable: true
1080
+ });
1081
+
1082
+ process.env = {
1083
+ ...originalProcessEnv,
1084
+ VITE_SUPABASE_URL: 'https://test.supabase.co',
1085
+ VITE_SUPABASE_ANON_KEY: 'test-key'
1086
+ };
1087
+
1088
+ render(
1089
+ <PublicPageProvider>
1090
+ <div>Test</div>
1091
+ </PublicPageProvider>
1092
+ );
1093
+
1094
+ expect(mockCreateClient).toHaveBeenCalledWith('https://test.supabase.co', 'test-key');
1095
+
1096
+ // Restore
1097
+ Object.defineProperty(import.meta, 'env', {
1098
+ value: originalEnv,
1099
+ writable: true,
1100
+ configurable: true
1101
+ });
1102
+ process.env = originalProcessEnv;
1103
+ });
1104
+
1105
+ it('handles missing environment variables gracefully', () => {
1106
+ const TestComponent = () => {
1107
+ const context = usePublicPageContext();
1108
+ return <div>{context.supabase === null ? 'no-client' : 'has-client'}</div>;
1109
+ };
1110
+
1111
+ render(
1112
+ <PublicPageProvider>
1113
+ <TestComponent />
1114
+ </PublicPageProvider>
1115
+ );
1116
+
1117
+ expect(screen.getByText('no-client')).toBeInTheDocument();
1118
+ });
1119
+
1120
+ it('supports NEXT_PUBLIC_ prefixed environment variables', () => {
1121
+ mockCreateClient.mockClear();
1122
+
1123
+ const originalEnv = import.meta.env;
1124
+ const originalProcessEnv = process.env;
1125
+
1126
+ const mockEnv = {
1127
+ NEXT_PUBLIC_SUPABASE_URL: 'https://next.supabase.co',
1128
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: 'next-key'
1129
+ };
1130
+
1131
+ Object.defineProperty(import.meta, 'env', {
1132
+ value: mockEnv,
1133
+ writable: true,
1134
+ configurable: true
1135
+ });
1136
+
1137
+ process.env = {
1138
+ ...originalProcessEnv,
1139
+ NEXT_PUBLIC_SUPABASE_URL: 'https://next.supabase.co',
1140
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: 'next-key'
1141
+ };
1142
+
1143
+ render(
1144
+ <PublicPageProvider>
1145
+ <div>Test</div>
1146
+ </PublicPageProvider>
1147
+ );
1148
+
1149
+ expect(mockCreateClient).toHaveBeenCalledWith('https://next.supabase.co', 'next-key');
1150
+
1151
+ // Restore
1152
+ Object.defineProperty(import.meta, 'env', {
1153
+ value: originalEnv,
1154
+ writable: true,
1155
+ configurable: true
1156
+ });
1157
+ process.env = originalProcessEnv;
1158
+ });
1159
+ });
1160
+
1161
+ describe('usePublicPageContext Hook', () => {
1162
+ it('throws error when used outside provider', () => {
1163
+ const consoleError = console.error;
1164
+ console.error = vi.fn();
1165
+
1166
+ const TestComponent = () => {
1167
+ try {
1168
+ const context = usePublicPageContext();
1169
+ return <div>{context.isPublicPage ? 'true' : 'false'}</div>;
1170
+ } catch (error) {
1171
+ return <div>{(error as Error).message}</div>;
1172
+ }
1173
+ };
1174
+
1175
+ render(<TestComponent />);
1176
+
1177
+ expect(screen.getByText('usePublicPageContext must be used within a PublicPageProvider')).toBeInTheDocument();
1178
+
1179
+ console.error = consoleError;
1180
+ });
1181
+ });
1182
+
1183
+ describe('useIsPublicPage Hook', () => {
1184
+ it('returns false when used outside provider', () => {
1185
+ const TestComponent = () => {
1186
+ const isPublic = useIsPublicPage();
1187
+ return <div>{isPublic ? 'true' : 'false'}</div>;
1188
+ };
1189
+
1190
+ render(<TestComponent />);
1191
+ expect(screen.getByText('false')).toBeInTheDocument();
1192
+ });
1193
+
1194
+ it('returns true when used inside provider', () => {
1195
+ const TestComponent = () => {
1196
+ const isPublic = useIsPublicPage();
1197
+ return <div>{isPublic ? 'true' : 'false'}</div>;
1198
+ };
1199
+
1200
+ render(
1201
+ <PublicPageProvider>
1202
+ <TestComponent />
1203
+ </PublicPageProvider>
1204
+ );
1205
+
1206
+ expect(screen.getByText('true')).toBeInTheDocument();
1207
+ });
1208
+ });
1209
+ });
1210
+