@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,279 +0,0 @@
1
- /**
2
- * @file Page Permission Provider Component
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Components/PagePermissionProvider
5
- * @since 2.0.0
6
- *
7
- * A context provider that manages page-level permissions across the entire application.
8
- * This component ensures that all pages are properly protected and provides centralized
9
- * page permission management.
10
- *
11
- * Features:
12
- * - App-wide page permission management
13
- * - Strict mode to prevent bypassing
14
- * - Automatic audit logging
15
- * - Integration with existing RBAC system
16
- * - Page permission tracking
17
- * - Error handling and recovery
18
- *
19
- * @example
20
- * ```tsx
21
- * // Basic app setup with page permissions
22
- * <PagePermissionProvider strictMode={true} auditLog={true}>
23
- * <App />
24
- * </PagePermissionProvider>
25
- *
26
- * // With custom configuration
27
- * <PagePermissionProvider
28
- * strictMode={true}
29
- * auditLog={true}
30
- * onPageAccess={(pageName, operation, allowed) => {
31
- * console.log(`Page access: ${pageName} ${operation} - ${allowed ? 'allowed' : 'denied'}`);
32
- * }}
33
- * >
34
- * <App />
35
- * </PagePermissionProvider>
36
- * ```
37
- *
38
- * @security
39
- * - Enforces page-level permissions across the app
40
- * - Prevents apps from bypassing permission checks
41
- * - Automatic audit logging for all page access attempts
42
- * - Integration with existing RBAC system
43
- * - Page permission tracking and monitoring
44
- *
45
- * @performance
46
- * - Optimized with useMemo and useCallback
47
- * - Efficient context updates
48
- * - Minimal re-renders
49
- * - Cached permission checks
50
- *
51
- * @dependencies
52
- * - React 19+ - Context and hooks
53
- * - useUnifiedAuth - Authentication context
54
- * - RBAC types - Type definitions
55
- */
56
-
57
- import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
58
- import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
59
- import { useResolvedScope } from '../hooks/useResolvedScope';
60
- import { UUID, Scope, Permission } from '../types';
61
- import { createLogger } from '../../utils/core/logger';
62
-
63
- const log = createLogger('PagePermissionProvider');
64
-
65
- export interface PagePermissionContextType {
66
- /** Check if user has permission for a page */
67
- hasPagePermission: (pageName: string, operation: string, pageId?: string, scope?: Scope) => boolean;
68
-
69
- /** Get all page permissions for current user */
70
- getPagePermissions: () => Record<string, string[]>;
71
-
72
- /** Check if page permission checking is enabled */
73
- isEnabled: boolean;
74
-
75
- /** Check if strict mode is enabled */
76
- isStrictMode: boolean;
77
-
78
- /** Check if audit logging is enabled */
79
- isAuditLogEnabled: boolean;
80
-
81
- /** Get page access history */
82
- getPageAccessHistory: () => PageAccessRecord[];
83
-
84
- /** Clear page access history */
85
- clearPageAccessHistory: () => void;
86
- }
87
-
88
- export interface PageAccessRecord {
89
- pageName: string;
90
- operation: string;
91
- userId: UUID;
92
- scope: Scope;
93
- allowed: boolean;
94
- timestamp: string;
95
- pageId?: string;
96
- }
97
-
98
- export interface PagePermissionProviderProps {
99
- /** Child components */
100
- children: React.ReactNode;
101
-
102
- /** Enable strict mode to prevent bypassing (default: true) */
103
- strictMode?: boolean;
104
-
105
- /** Enable audit logging (default: true) */
106
- auditLog?: boolean;
107
-
108
- /** Callback when page access is attempted */
109
- onPageAccess?: (pageName: string, operation: string, allowed: boolean, record: PageAccessRecord) => void;
110
-
111
- /** Callback when strict mode violation occurs */
112
- onStrictModeViolation?: (pageName: string, operation: string, record: PageAccessRecord) => void;
113
-
114
- /** Maximum number of access records to keep in history */
115
- maxHistorySize?: number;
116
- }
117
-
118
- const PagePermissionContext = createContext<PagePermissionContextType | null>(null);
119
-
120
- /**
121
- * PagePermissionProvider - Manages page-level permissions across the app
122
- *
123
- * This provider ensures that all pages are properly protected and provides
124
- * centralized page permission management with strict enforcement.
125
- *
126
- * @param props - Provider props
127
- * @returns React element with page permission context
128
- */
129
- export function PagePermissionProvider({
130
- children,
131
- strictMode = true,
132
- auditLog = true,
133
- onPageAccess,
134
- onStrictModeViolation,
135
- maxHistorySize = 1000
136
- }: PagePermissionProviderProps) {
137
- const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
138
- const [pageAccessHistory, setPageAccessHistory] = useState<PageAccessRecord[]>([]);
139
- const [isEnabled, setIsEnabled] = useState(true);
140
-
141
- // Use useResolvedScope to get proper scope (org derived from event if needed)
142
- const { resolvedScope } = useResolvedScope({
143
- supabase,
144
- selectedOrganisationId: selectedOrganisation?.id || null,
145
- selectedEventId: selectedEvent?.event_id || null
146
- });
147
-
148
- // Get current scope from resolved scope
149
- // For event-required apps: org is derived from event
150
- // For org-required apps: org comes from selectedOrganisation
151
- const currentScope = resolvedScope;
152
-
153
- // Check if user has permission for a page
154
- const hasPagePermission = useCallback((
155
- pageName: string,
156
- operation: string,
157
- pageId?: string,
158
- scope?: Scope
159
- ): boolean => {
160
- if (!isEnabled) return true;
161
- if (!user?.id) return false;
162
-
163
- const effectiveScope = scope || currentScope;
164
- if (!effectiveScope) return false;
165
-
166
- // Use the existing RBAC system to check permissions
167
- // This is a synchronous check for the context - actual permission checking
168
- // happens in the PagePermissionGuard component using useCan hook
169
- const permission = `${operation}:page.${pageName}` as Permission;
170
-
171
- // Return false by default (secure by default) - let individual PagePermissionGuard
172
- // components handle the actual permission checking asynchronously
173
- // This context is mainly for tracking and audit purposes
174
- return false;
175
- }, [isEnabled, user?.id, currentScope]);
176
-
177
- // Get all page permissions for current user
178
- const getPagePermissions = useCallback((): Record<string, string[]> => {
179
- if (!isEnabled || !user?.id) return {};
180
-
181
- // For now, return empty object - this will be enhanced with actual permission checking
182
- // when we integrate with the existing RBAC system
183
- return {};
184
- }, [isEnabled, user?.id]);
185
-
186
- // Get page access history
187
- const getPageAccessHistory = useCallback((): PageAccessRecord[] => {
188
- return [...pageAccessHistory];
189
- }, [pageAccessHistory]);
190
-
191
- // Clear page access history
192
- const clearPageAccessHistory = useCallback(() => {
193
- setPageAccessHistory([]);
194
- }, []);
195
-
196
- // Record page access attempt
197
- const recordPageAccess = useCallback((
198
- pageName: string,
199
- operation: string,
200
- allowed: boolean,
201
- pageId?: string,
202
- scope?: Scope
203
- ) => {
204
- if (!auditLog || !user?.id) return;
205
-
206
- const record: PageAccessRecord = {
207
- pageName,
208
- operation,
209
- userId: user.id,
210
- scope: scope || currentScope || { organisationId: '' },
211
- allowed,
212
- timestamp: new Date().toISOString(),
213
- pageId
214
- };
215
-
216
- setPageAccessHistory(prev => {
217
- const newHistory = [record, ...prev];
218
- return newHistory.slice(0, maxHistorySize);
219
- });
220
-
221
- if (onPageAccess) {
222
- onPageAccess(pageName, operation, allowed, record);
223
- }
224
-
225
- if (strictMode && !allowed && onStrictModeViolation) {
226
- onStrictModeViolation(pageName, operation, record);
227
- }
228
- }, [auditLog, user?.id, currentScope, maxHistorySize, onPageAccess, onStrictModeViolation, strictMode]);
229
-
230
- // Context value
231
- const contextValue = useMemo((): PagePermissionContextType => ({
232
- hasPagePermission,
233
- getPagePermissions,
234
- isEnabled,
235
- isStrictMode: strictMode,
236
- isAuditLogEnabled: auditLog,
237
- getPageAccessHistory,
238
- clearPageAccessHistory
239
- }), [
240
- hasPagePermission,
241
- getPagePermissions,
242
- isEnabled,
243
- strictMode,
244
- auditLog,
245
- getPageAccessHistory,
246
- clearPageAccessHistory
247
- ]);
248
-
249
- // Log strict mode violations
250
- useEffect(() => {
251
- if (strictMode && auditLog) {
252
- log.debug('Strict mode enabled - all page access attempts will be logged and enforced');
253
- }
254
- }, [strictMode, auditLog]);
255
-
256
- return (
257
- <PagePermissionContext.Provider value={contextValue}>
258
- {children}
259
- </PagePermissionContext.Provider>
260
- );
261
- }
262
-
263
- /**
264
- * Hook to use page permission context
265
- *
266
- * @returns Page permission context
267
- * @throws Error if used outside of PagePermissionProvider
268
- */
269
- export function usePagePermissions(): PagePermissionContextType {
270
- const context = useContext(PagePermissionContext);
271
-
272
- if (!context) {
273
- throw new Error('usePagePermissions must be used within a PagePermissionProvider');
274
- }
275
-
276
- return context;
277
- }
278
-
279
- export default PagePermissionProvider;
@@ -1,312 +0,0 @@
1
- /**
2
- * @file Permission Enforcer Component
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Components/PermissionEnforcer
5
- * @since 2.0.0
6
- *
7
- * A component that enforces permissions and prevents apps from bypassing permission checks.
8
- * This is a critical security component that provides centralized permission enforcement.
9
- *
10
- * Features:
11
- * - Centralized permission enforcement
12
- * - Strict mode to prevent bypassing
13
- * - Automatic audit logging
14
- * - Integration with existing RBAC system
15
- * - Multiple permission checking
16
- * - Clear error messages for unauthorized access
17
- *
18
- * @example
19
- * ```tsx
20
- * // Basic permission enforcement
21
- * <PermissionEnforcer
22
- * permissions={['read:events', 'update:events']}
23
- * operation="event-management"
24
- * fallback={<AccessDeniedPage />}
25
- * >
26
- * <EventManagementPage />
27
- * </PermissionEnforcer>
28
- *
29
- * // Strict mode (prevents bypassing)
30
- * <PermissionEnforcer
31
- * permissions={['admin:system']}
32
- * operation="system-administration"
33
- * strictMode={true}
34
- * fallback={<AccessDeniedPage />}
35
- * >
36
- * <SystemAdminPage />
37
- * </PermissionEnforcer>
38
- *
39
- * // With custom fallback
40
- * <PermissionEnforcer
41
- * permissions={['update:settings']}
42
- * operation="settings-update"
43
- * fallback={<div>You don't have permission to update settings</div>}
44
- * >
45
- * <SettingsUpdatePage />
46
- * </PermissionEnforcer>
47
- * ```
48
- *
49
- * @security
50
- * - Enforces permissions for all operations
51
- * - Prevents apps from bypassing permission checks
52
- * - Automatic audit logging for all permission checks
53
- * - Integration with existing RBAC system
54
- * - Clear error messages for unauthorized access
55
- *
56
- * @performance
57
- * - Optimized with useMemo and useCallback
58
- * - Cached permission checks
59
- * - Minimal re-renders
60
- * - Efficient error handling
61
- *
62
- * @dependencies
63
- * - React 19+ - Component framework
64
- * - useCan hook - Permission checking
65
- * - useUnifiedAuth - Authentication context
66
- * - RBAC types - Type definitions
67
- */
68
-
69
- import React, { useMemo, useCallback, useEffect, useState, useRef } from 'react';
70
- import { useMultiplePermissions } from '../hooks/usePermissions';
71
- import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
72
- import { useResolvedScope } from '../hooks/useResolvedScope';
73
- import { UUID, Permission, Scope } from '../types';
74
- import { getRBACLogger } from '../config';
75
- import { createLogger } from '../../utils/core/logger';
76
-
77
- const log = createLogger('PermissionEnforcer');
78
-
79
- export interface PermissionEnforcerProps {
80
- /** Permissions required for access */
81
- permissions: Permission[];
82
-
83
- /** Operation being performed */
84
- operation: string;
85
-
86
- /** Content to render when user has permission */
87
- children: React.ReactNode;
88
-
89
- /** Content to render when user lacks permission */
90
- fallback?: React.ReactNode;
91
-
92
- /** Enable strict mode to prevent bypassing (default: true) */
93
- strictMode?: boolean;
94
-
95
- /** Force audit logging for this operation (default: true) */
96
- auditLog?: boolean;
97
-
98
- /** Custom scope for permission checking */
99
- scope?: Scope;
100
-
101
- /** Callback when access is denied */
102
- onDenied?: (permissions: Permission[], operation: string) => void;
103
-
104
- /** Loading state content */
105
- loading?: React.ReactNode;
106
-
107
- /** Require all permissions (AND) or any permission (OR) */
108
- requireAll?: boolean;
109
- }
110
-
111
- /**
112
- * PermissionEnforcer - Enforces permissions for operations
113
- *
114
- * This component ensures that users can only perform operations they have permission for.
115
- * It integrates with the existing RBAC system and provides strict enforcement to
116
- * prevent apps from bypassing permission checks.
117
- *
118
- * @param props - Component props
119
- * @returns React element with permission enforcement
120
- */
121
- export function PermissionEnforcer({
122
- permissions,
123
- operation,
124
- children,
125
- fallback = <DefaultAccessDenied />,
126
- strictMode = true,
127
- auditLog = true,
128
- scope,
129
- onDenied,
130
- loading = <DefaultLoading />,
131
- requireAll = true
132
- }: PermissionEnforcerProps) {
133
- const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
134
- const [hasChecked, setHasChecked] = useState(false);
135
-
136
- // Use useResolvedScope hook for consistent scope resolution
137
- // For event-required apps: selectedOrganisation is null, org derived from event
138
- // For org-required apps: selectedOrganisation is available, event optional
139
- const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
140
- supabase,
141
- selectedOrganisationId: selectedOrganisation?.id || null,
142
- selectedEventId: selectedEvent?.event_id || null
143
- });
144
-
145
- // Use provided scope if available, otherwise use resolved scope
146
- // Extract primitive values to ensure stable reference comparison
147
- // This prevents useMultiplePermissions from re-checking when scope object reference changes but values are the same
148
- const scopeToUse = scope || resolvedScope;
149
- const scopeOrgId = scopeToUse?.organisationId || '';
150
- const scopeEventId = scopeToUse?.eventId || undefined;
151
- const scopeAppId = scopeToUse?.appId || undefined;
152
-
153
- // Memoize effectiveScope using primitive values to ensure stable reference
154
- // Always create a new scope object from primitive values to prevent reference changes
155
- const effectiveScope = useMemo(() => {
156
- const newScope: Scope = {};
157
- if (scopeOrgId) {
158
- newScope.organisationId = scopeOrgId;
159
- }
160
- if (scopeEventId) {
161
- newScope.eventId = scopeEventId;
162
- }
163
- if (scopeAppId) {
164
- newScope.appId = scopeAppId;
165
- }
166
- return newScope;
167
- }, [scopeOrgId, scopeEventId, scopeAppId]);
168
- const checkError = scopeError;
169
-
170
- // Check all permissions using useMultiplePermissions hook
171
- const { results: permissionResults, isLoading: permissionsLoading, error: permissionsError } = useMultiplePermissions(
172
- user?.id || '',
173
- effectiveScope || { eventId: selectedEvent?.event_id || undefined },
174
- permissions,
175
- true // Use cache
176
- );
177
-
178
- const isLoading = scopeLoading || permissionsLoading;
179
- const error = checkError || permissionsError;
180
-
181
- // Determine if user has required permissions based on requireAll prop
182
- const hasRequiredPermissions = useMemo((): boolean => {
183
- if (permissions.length === 0) return true;
184
-
185
- // If permissionResults is not yet available or empty, deny access
186
- if (!permissionResults || Object.keys(permissionResults).length === 0) {
187
- return false;
188
- }
189
-
190
- if (requireAll) {
191
- // User must have ALL permissions
192
- return Object.values(permissionResults).every(result => result === true);
193
- } else {
194
- // User must have ANY permission (default behavior)
195
- return Object.values(permissionResults).some(result => result === true);
196
- }
197
- }, [permissions, permissionResults, requireAll]);
198
-
199
- // Handle permission check completion
200
- useEffect(() => {
201
- if (!isLoading && !error) {
202
- setHasChecked(true);
203
-
204
- if (!hasRequiredPermissions && onDenied) {
205
- onDenied(permissions, operation);
206
- }
207
- } else if (error) {
208
- setHasChecked(true);
209
- }
210
- }, [hasRequiredPermissions, isLoading, error, permissions, operation, onDenied]);
211
-
212
- // Log permission check attempt for audit
213
- // Only log once per unique permission check result to prevent spam
214
- // Use the scope primitive values already extracted above
215
- const permissionsKey = permissions.join(',');
216
-
217
- const lastLoggedKeyRef = useRef<string | null>(null);
218
- useEffect(() => {
219
- if (auditLog && hasChecked && !isLoading) {
220
- // Create a stable key based on the permission check result values (not object references)
221
- const logKey = `${operation}-${user?.id}-${permissionsKey}-${hasRequiredPermissions}-${scopeOrgId}-${scopeEventId}-${scopeAppId}`;
222
-
223
- // Only log if this is a new result (different from last logged)
224
- if (lastLoggedKeyRef.current !== logKey) {
225
- lastLoggedKeyRef.current = logKey;
226
- log.debug('Permission check attempt:', {
227
- permissions,
228
- operation,
229
- userId: user?.id,
230
- scope: effectiveScope,
231
- allowed: hasRequiredPermissions,
232
- requireAll,
233
- timestamp: new Date().toISOString()
234
- });
235
- }
236
- }
237
- }, [auditLog, hasChecked, isLoading, permissionsKey, operation, user?.id, scopeOrgId, scopeEventId, scopeAppId, hasRequiredPermissions]);
238
-
239
- // Handle strict mode violations
240
- useEffect(() => {
241
- if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {
242
- const logger = getRBACLogger();
243
- logger.error(`STRICT MODE VIOLATION: User attempted to perform operation without permission`, {
244
- permissions,
245
- operation,
246
- userId: user?.id,
247
- scope: effectiveScope,
248
- requireAll,
249
- timestamp: new Date().toISOString()
250
- });
251
- }
252
- }, [strictMode, hasChecked, isLoading, hasRequiredPermissions, permissions, operation, user?.id, effectiveScope, requireAll]);
253
-
254
- // Show loading state
255
- if (isLoading || !hasChecked) {
256
- return <>{loading}</>;
257
- }
258
-
259
- // Show error state
260
- if (checkError) {
261
- const logger = getRBACLogger();
262
- logger.error(`Permission check failed for operation ${operation}:`, checkError);
263
- return <>{fallback}</>;
264
- }
265
-
266
- // Show access denied
267
- if (!hasRequiredPermissions) {
268
- return <>{fallback}</>;
269
- }
270
-
271
- // Show protected content
272
- return <>{children}</>;
273
- }
274
-
275
- /**
276
- * Default access denied component
277
- */
278
- function DefaultAccessDenied() {
279
- return (
280
- <div className="flex flex-col items-center justify-center min-h-[200px] p-8 text-center">
281
- <div className="mb-4">
282
- <svg className="w-16 h-16 text-acc-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
283
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
284
- </svg>
285
- </div>
286
- <h2 className="text-xl font-semibold text-sec-900 mb-2">Access Denied</h2>
287
- <p className="text-sec-600 mb-4">You don't have permission to perform this operation.</p>
288
- <button
289
- onClick={() => window.history.back()}
290
- className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
291
- >
292
- Go Back
293
- </button>
294
- </div>
295
- );
296
- }
297
-
298
- /**
299
- * Default loading component
300
- */
301
- function DefaultLoading() {
302
- return (
303
- <div className="flex items-center justify-center min-h-[200px] p-8">
304
- <div className="flex items-center space-x-2">
305
- <div className="animate-spin rounded-full size-8 border-b-2 border-main-600"></div>
306
- <span className="text-sec-600">Checking permissions...</span>
307
- </div>
308
- </div>
309
- );
310
- }
311
-
312
- export default PermissionEnforcer;