@jmruthers/pace-core 0.6.10 → 0.6.11
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.
- package/CHANGELOG.md +21 -0
- package/audit-tool/00-dependencies.cjs +46 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
- package/audit-tool/audits/02-project-structure.cjs +13 -3
- package/audit-tool/audits/03-architecture.cjs +78 -4
- package/audit-tool/audits/04-code-quality.cjs +9 -2
- package/audit-tool/audits/05-styling.cjs +19 -7
- package/audit-tool/audits/06-security-rbac.cjs +105 -14
- package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
- package/audit-tool/audits/08-testing-documentation.cjs +11 -3
- package/audit-tool/audits/09-operations.cjs +19 -7
- package/audit-tool/index.cjs +22 -11
- package/audit-tool/utils/report-utils.cjs +4 -0
- package/cursor-rules/01-pace-core-compliance.mdc +1 -0
- package/cursor-rules/02-project-structure.mdc +1 -0
- package/cursor-rules/03-architecture.mdc +3 -1
- package/cursor-rules/04-code-quality.mdc +1 -0
- package/cursor-rules/05-styling.mdc +41 -7
- package/cursor-rules/06-security-rbac.mdc +2 -1
- package/cursor-rules/07-api-tech-stack.mdc +1 -0
- package/cursor-rules/08-testing-documentation.mdc +1 -0
- package/cursor-rules/09-operations.mdc +1 -0
- package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
- package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
- package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
- package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
- package/dist/api-result-USV1Czr-.d.ts +51 -0
- package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
- package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
- package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
- package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
- package/dist/chunk-44CNXN4P.js +15 -0
- package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
- package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
- package/dist/chunk-CU2BU2MQ.js +2 -0
- package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
- package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
- package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
- package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
- package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
- package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
- package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
- package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
- package/dist/chunk-WY6Y7KC3.js +264 -0
- package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
- package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
- package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
- package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
- package/dist/components.d.ts +8 -7
- package/dist/components.js +17 -15
- package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
- package/dist/eslint-rules/index.cjs +3 -0
- package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
- package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
- package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
- package/dist/hooks.d.ts +22 -9
- package/dist/hooks.js +34 -25
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +66 -177
- package/dist/index.js +316 -340
- package/dist/pagination-BW1mqywp.d.ts +201 -0
- package/dist/providers.d.ts +6 -5
- package/dist/providers.js +5 -3
- package/dist/rbac/index.d.ts +123 -138
- package/dist/rbac/index.js +10 -8
- package/dist/theming/runtime.d.ts +19 -2
- package/dist/theming/runtime.js +1 -1
- package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
- package/dist/types.d.ts +17 -10
- package/dist/types.js +1 -0
- package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
- package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
- package/dist/utils.d.ts +163 -145
- package/dist/utils.js +42 -25
- package/docs/api/modules.md +782 -643
- package/docs/api-reference/rpc-functions.md +12 -3
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/getting-started/cursor-rules.md +17 -20
- package/docs/getting-started/dependencies.md +1 -1
- package/docs/getting-started/setup.md +235 -0
- package/docs/implementation-guides/authentication.md +27 -0
- package/docs/implementation-guides/data-tables.md +176 -3
- package/docs/migration/ApiResult-migration.md +25 -0
- package/docs/rbac/api-reference.md +33 -31
- package/docs/standards/0-standards-overview.md +50 -15
- package/docs/standards/1-pace-core-compliance-standards.md +62 -57
- package/docs/standards/2-project-structure-standards.md +33 -16
- package/docs/standards/3-architecture-standards.md +41 -1
- package/docs/standards/4-code-quality-standards.md +26 -6
- package/docs/standards/5-styling-standards.md +35 -1
- package/docs/standards/6-security-rbac-standards.md +66 -0
- package/docs/standards/7-api-tech-stack-standards.md +25 -14
- package/docs/standards/8-testing-documentation-standards.md +31 -0
- package/docs/standards/9-operations-standards.md +19 -0
- package/docs/standards/README.md +20 -201
- package/docs/testing/test-setup-for-consumers.md +2 -0
- package/docs/troubleshooting/common-issues.md +17 -1
- package/docs/troubleshooting/organisation-context-setup.md +8 -0
- package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
- package/eslint-config-pace-core.cjs +20 -0
- package/package.json +14 -20
- package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
- package/scripts/setup.cjs +536 -0
- package/scripts/validate.cjs +480 -0
- package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
- package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
- package/src/__tests__/helpers/test-providers.tsx +37 -39
- package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
- package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
- package/src/assets/app-icons/index.test.ts +304 -0
- package/src/components/AddressField/AddressField.test.tsx +1 -1
- package/src/components/AddressField/AddressField.tsx +238 -212
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.test.tsx +172 -17
- package/src/components/Card/Card.tsx +19 -10
- package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
- package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
- package/src/components/ContextSelector/ContextSelector.tsx +66 -280
- package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
- package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
- package/src/components/DataTable/AUDIT_REPORT.md +59 -44
- package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
- package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
- package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
- package/src/components/DataTable/DataTable.test.tsx +787 -416
- package/src/components/DataTable/DataTable.tsx +12 -12
- package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
- package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
- package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
- package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
- package/src/components/DataTable/TESTING.md +101 -0
- package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
- package/src/components/DataTable/components/DataTableCore.tsx +104 -864
- package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
- package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
- package/src/components/DataTable/components/ImportModal.tsx +61 -559
- package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
- package/src/components/DataTable/context/DataTableContext.tsx +7 -6
- package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
- package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
- package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
- package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
- package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
- package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
- package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
- package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
- package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
- package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
- package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
- package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
- package/src/components/DataTable/index.ts +18 -17
- package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
- package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
- package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
- package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
- package/src/components/DataTable/styles.ts +0 -1
- package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
- package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
- package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
- package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
- package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
- package/src/components/DataTable/types/actions.ts +71 -0
- package/src/components/DataTable/types/base.ts +39 -0
- package/src/components/DataTable/types/columns.ts +125 -0
- package/src/components/DataTable/types/export.ts +32 -0
- package/src/components/DataTable/types/features.ts +81 -0
- package/src/components/DataTable/types/hierarchical.ts +44 -0
- package/src/components/DataTable/types/index.ts +43 -0
- package/src/components/DataTable/types/pagination.ts +85 -0
- package/src/components/DataTable/types/performance.ts +47 -0
- package/src/components/DataTable/types/props.ts +62 -0
- package/src/components/DataTable/types/rbac.ts +45 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
- package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
- package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
- package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
- package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
- package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
- package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
- package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
- package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
- package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
- package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
- package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
- package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
- package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
- package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
- package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
- package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
- package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
- package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
- package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
- package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
- package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
- package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
- package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
- package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
- package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
- package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
- package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
- package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/csvParse.test.ts +74 -0
- package/src/components/DataTable/utils/csvParse.ts +65 -0
- package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
- package/src/components/DataTable/utils/flexibleImport.ts +3 -186
- package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
- package/src/components/DataTable/utils/importDateParser.ts +114 -0
- package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
- package/src/components/DataTable/utils/importValueParser.ts +91 -0
- package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/paginationUtils.ts +6 -3
- package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
- package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
- package/src/components/Dialog/Dialog.test-utils.ts +49 -0
- package/src/components/Dialog/Dialog.test.tsx +896 -89
- package/src/components/Dialog/Dialog.tsx +174 -882
- package/src/components/Dialog/dialogLock.test.ts +238 -0
- package/src/components/Dialog/dialogLock.ts +98 -0
- package/src/components/Dialog/index.ts +2 -0
- package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
- package/src/components/Dialog/useDialogDimensions.ts +140 -0
- package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
- package/src/components/Dialog/useDialogLifecycle.ts +135 -0
- package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
- package/src/components/Dialog/useDialogPersistence.ts +357 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
- package/src/components/FileDisplay/FileDisplay.tsx +24 -656
- package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
- package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
- package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
- package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
- package/src/components/FileDisplay/fallbackUtils.ts +44 -0
- package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
- package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
- package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
- package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
- package/src/components/FileDisplay/useFileDisplay.ts +515 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
- package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
- package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
- package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
- package/src/components/FileUpload/FileUpload.test.tsx +16 -10
- package/src/components/FileUpload/FileUpload.tsx +107 -525
- package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
- package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
- package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
- package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
- package/src/components/FileUpload/useFileUploadManager.ts +454 -0
- package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
- package/src/components/FileUpload/useResolvedAppId.ts +77 -0
- package/src/components/Footer/Footer.test.tsx +6 -292
- package/src/components/Footer/Footer.tsx +8 -125
- package/src/components/Form/Form.test.tsx +44 -27
- package/src/components/Form/Form.tsx +64 -287
- package/src/components/Form/useFormPersistence.ts +257 -0
- package/src/components/Header/Header.test.tsx +17 -18
- package/src/components/Header/Header.tsx +10 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.test.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
- package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
- package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
- package/src/components/NavigationMenu/index.ts +6 -1
- package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
- package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
- package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
- package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
- package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
- package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
- package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
- package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
- package/src/components/Progress/Progress.tsx +1 -2
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
- package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
- package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
- package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
- package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +28 -18
- package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
- package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
- package/src/components/Select/{utils/text.ts → text.ts} +1 -1
- package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
- package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
- package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
- package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
- package/src/components/Table/Table.test.tsx +348 -0
- package/src/components/Tabs/Tabs.test.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.test.tsx +420 -0
- package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
- package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
- package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
- package/src/hooks/index.ts +7 -4
- package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
- package/src/hooks/public/usePublicEvent.test.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
- package/src/hooks/services/useAuth.ts +9 -7
- package/src/hooks/useAddressAutocomplete.test.ts +22 -22
- package/src/hooks/useAddressAutocomplete.ts +90 -75
- package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
- package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
- package/src/hooks/useDataTablePerformance.ts +100 -120
- package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
- package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
- package/src/hooks/useEventTheme.test.ts +4 -1
- package/src/hooks/useEventTheme.ts +49 -21
- package/src/hooks/useEvents.ts +41 -1
- package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
- package/src/hooks/useFileReference.test.ts +44 -41
- package/src/hooks/useFileReference.ts +182 -173
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
- package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
- package/src/hooks/useFileUrlCache.ts +1 -1
- package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
- package/src/hooks/useInactivityTracker.ts +138 -131
- package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
- package/src/hooks/useIsPrint.ts +62 -0
- package/src/hooks/useIsPrint.unit.test.ts +545 -0
- package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
- package/src/hooks/useOrganisationSecurity.test.ts +3 -3
- package/src/hooks/useOrganisationSecurity.ts +190 -201
- package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
- package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
- package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
- package/src/hooks/usePermissionCache.ts +276 -271
- package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
- package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
- package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
- package/src/hooks/useQueryCache.ts +0 -2
- package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
- package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
- package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
- package/src/hooks/useStorage.ts +21 -16
- package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
- package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
- package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
- package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/icons/index.ts +2 -0
- package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
- package/src/index.ts +15 -7
- package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
- package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
- package/src/providers/InactivityProvider.test-helper.tsx +40 -0
- package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
- package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
- package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
- package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
- package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
- package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
- package/src/providers/services/UnifiedAuthContext.ts +30 -27
- package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
- package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
- package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
- package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
- package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
- package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
- package/src/providers/useInactivity.test-helper.ts +27 -0
- package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
- package/src/rbac/adapters.test.tsx +22 -22
- package/src/rbac/adapters.tsx +29 -29
- package/src/rbac/api.test.ts +973 -42
- package/src/rbac/api.ts +228 -253
- package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
- package/src/rbac/audit.ts +4 -1
- package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
- package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
- package/src/rbac/cache-invalidation.test.ts +715 -0
- package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
- package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
- package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
- package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
- package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
- package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
- package/src/rbac/components/PagePermissionGuard.tsx +177 -372
- package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
- package/src/rbac/config.ts +58 -18
- package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
- package/src/rbac/engine.test.ts +494 -0
- package/src/rbac/errors.ts +89 -55
- package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
- package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
- package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
- package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
- package/src/rbac/hooks/permissions/useCan.ts +170 -252
- package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
- package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
- package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
- package/src/rbac/hooks/useCan.test.ts +42 -42
- package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
- package/src/rbac/hooks/usePageGuardScope.ts +117 -0
- package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
- package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
- package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
- package/src/rbac/hooks/usePermissions.test.ts +54 -54
- package/src/rbac/hooks/useRBAC.test.ts +313 -217
- package/src/rbac/hooks/useRBAC.ts +145 -81
- package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
- package/src/rbac/hooks/useResourcePermissions.ts +68 -134
- package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
- package/src/rbac/hooks/useRoleManagement.ts +153 -585
- package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
- package/src/rbac/hooks/useSecureSupabase.ts +10 -2
- package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
- package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
- package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
- package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
- package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
- package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
- package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
- package/src/rbac/request-deduplication.test.ts +14 -9
- package/src/rbac/request-deduplication.ts +5 -4
- package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
- package/src/rbac/secureClient.test.ts +514 -83
- package/src/rbac/secureClient.ts +8 -2
- package/src/rbac/security.test.ts +323 -0
- package/src/rbac/types/roleManagement.ts +66 -0
- package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
- package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
- package/src/rbac/utils/contextValidator.ts +5 -1
- package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
- package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
- package/src/rbac/utils/eventContext.ts +37 -33
- package/src/rbac/utils/fetchPermissionMap.ts +13 -0
- package/src/rbac/utils/permissionMapHelpers.ts +34 -0
- package/src/rbac/utils/roleManagementRpc.ts +303 -0
- package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
- package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
- package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
- package/src/services/AuthService.ts +184 -205
- package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
- package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
- package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
- package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
- package/src/services/EventService.ts +242 -312
- package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
- package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
- package/src/services/InactivityService.ts +172 -213
- package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
- package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
- package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
- package/src/services/OrganisationService.ts +184 -238
- package/src/services/base/BaseService.test.ts +1 -1
- package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
- package/src/services/interfaces/IAuthService.ts +10 -9
- package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
- package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
- package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
- package/src/styles/core.css +243 -12
- package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
- package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
- package/src/theming/runtime.ts +71 -2
- package/src/types/api-result.ts +53 -0
- package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
- package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
- package/src/types/database.generated.ts +45 -10
- package/src/types/event.ts +38 -18
- package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
- package/src/types/file-reference.ts +37 -12
- package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
- package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/types/index.ts +3 -0
- package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
- package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
- package/src/types/organisation.ts +15 -15
- package/src/types/supabase.ts +13 -4
- package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
- package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
- package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/app/appIdResolver.test.ts +98 -71
- package/src/utils/app/appIdResolver.ts +31 -20
- package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
- package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
- package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
- package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
- package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
- package/src/utils/context/organisationContext.test.ts +105 -91
- package/src/utils/context/organisationContext.ts +29 -40
- package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
- package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
- package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
- package/src/utils/core/mergeRefs.ts +24 -0
- package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
- package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
- package/src/utils/dynamic/createLazyComponent.tsx +9 -1
- package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
- package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
- package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
- package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
- package/src/utils/file-reference/index.ts +330 -347
- package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
- package/src/utils/formatting/formatNumber.test.ts +1 -1
- package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
- package/src/utils/google-places/googlePlacesUtils.ts +67 -99
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
- package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
- package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
- package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
- package/src/utils/location/location.test.ts +1 -1
- package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
- package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
- package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
- package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
- package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
- package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
- package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
- package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
- package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
- package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
- package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
- package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
- package/src/utils/security/auth-utils.ts +34 -23
- package/src/utils/security/secureDataAccess.ts +241 -281
- package/src/utils/security/secureErrors.test.ts +1 -1
- package/src/utils/security/secureStorage.test.ts +1 -1
- package/src/utils/security/security.test.ts +25 -17
- package/src/utils/security/security.ts +15 -18
- package/src/utils/security/securityMonitor.test.ts +1 -1
- package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
- package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
- package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
- package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
- package/src/utils/storage/helpers.test.ts +88 -102
- package/src/utils/storage/helpers.ts +173 -251
- package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
- package/src/utils/storage/types.ts +7 -0
- package/src/utils/supabase/createBaseClient.test.ts +1 -1
- package/src/utils/timezone/timezone.test.ts +1 -1
- package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
- package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
- package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
- package/src/utils/validation/csrf.ts +42 -41
- package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
- package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
- package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
- package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
- package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
- package/dist/chunk-KPYQWGFQ.js +0 -183
- package/dist/types-D05dCGma.d.ts +0 -521
- package/scripts/eslint-audit.cjs +0 -222
- package/scripts/generate-docs.js +0 -157
- package/scripts/install-cursor-rules.cjs +0 -255
- package/scripts/install-eslint-config.cjs +0 -349
- package/scripts/setup-build-cache.js +0 -73
- package/scripts/validate-pre-publish.js +0 -145
- package/src/__tests__/integration/UserProfile.test.tsx +0 -124
- package/src/__tests__/public-recipe-view.test.ts +0 -228
- package/src/__tests__/rls-policies.test.ts +0 -472
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
- package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
- package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -204
- package/src/components/DataTable/core/DataManager.ts +0 -190
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -312
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/types.ts +0 -764
- package/src/hooks/public/usePublicFileDisplay.ts +0 -534
- package/src/hooks/useFileDisplay.ts +0 -748
- package/src/providers/OrganisationProvider.test.tsx +0 -40
- package/src/providers/OrganisationProvider.tsx +0 -92
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
- package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
- /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
- /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
- /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
- /package/src/providers/{__tests__/README.md → README.md} +0 -0
- /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
- /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
- /package/src/types/{__tests__/README.md → README.md} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file Unified Auth Provider Integration Tests
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module Providers/Services
|
|
4
|
+
* @module Providers/Services
|
|
5
5
|
* @since 0.1.0
|
|
6
6
|
*
|
|
7
7
|
* Integration tests for UnifiedAuthProvider.
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
12
12
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
13
|
-
import { UnifiedAuthProvider, useUnifiedAuth } from '
|
|
13
|
+
import { UnifiedAuthProvider, useUnifiedAuth } from './UnifiedAuthProvider';
|
|
14
14
|
import { type SupabaseClient } from '@supabase/supabase-js';
|
|
15
|
-
import { Logger, LogLevel } from '
|
|
15
|
+
import { Logger, LogLevel } from '../../utils/core/logger';
|
|
16
16
|
|
|
17
|
-
// Unmock
|
|
18
|
-
vi.unmock('
|
|
17
|
+
// Unmock so we test the real UnifiedAuthProvider (global setup mocks it with user-123 / Test App)
|
|
18
|
+
vi.unmock('./UnifiedAuthProvider');
|
|
19
19
|
|
|
20
|
-
// Mock Supabase client
|
|
20
|
+
// Mock Supabase client - getSession/getUser must return Promises so AuthService.restoreSession() gets null session
|
|
21
21
|
const createMockSupabaseClient = (): SupabaseClient => ({
|
|
22
22
|
auth: {
|
|
23
23
|
signInWithPassword: vi.fn(),
|
|
@@ -26,9 +26,12 @@ const createMockSupabaseClient = (): SupabaseClient => ({
|
|
|
26
26
|
resetPasswordForEmail: vi.fn(),
|
|
27
27
|
updateUser: vi.fn(),
|
|
28
28
|
refreshSession: vi.fn(),
|
|
29
|
-
getSession: vi.fn(),
|
|
30
|
-
getUser: vi.fn(),
|
|
31
|
-
onAuthStateChange: vi.fn()
|
|
29
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
30
|
+
getUser: vi.fn().mockResolvedValue({ data: { user: null }, error: null }),
|
|
31
|
+
onAuthStateChange: vi.fn().mockReturnValue({
|
|
32
|
+
data: { subscription: { unsubscribe: vi.fn() } },
|
|
33
|
+
error: null,
|
|
34
|
+
}),
|
|
32
35
|
},
|
|
33
36
|
from: vi.fn(),
|
|
34
37
|
rpc: vi.fn(),
|
|
@@ -47,8 +50,8 @@ function TestComponent() {
|
|
|
47
50
|
<p data-testid="app-name">{auth.appName}</p>
|
|
48
51
|
<p data-testid="permissions-count">{0}</p>
|
|
49
52
|
<p data-testid="roles-count">{0}</p>
|
|
50
|
-
<p data-testid="organisations-count">{auth.organisations
|
|
51
|
-
<p data-testid="events-count">{auth.events
|
|
53
|
+
<p data-testid="organisations-count">{auth.organisations?.length ?? 0}</p>
|
|
54
|
+
<p data-testid="events-count">{auth.events?.length ?? 0}</p>
|
|
52
55
|
</section>
|
|
53
56
|
);
|
|
54
57
|
}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* Note: RBAC functionality is available via useRBAC() hook from '@jmruthers/pace-core/rbac'
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import React, { useMemo, useCallback, useRef, useEffect, useState
|
|
11
|
+
import React, { useMemo, useCallback, useRef, useEffect, useState } from 'react';
|
|
12
|
+
import { flushSync } from 'react-dom';
|
|
12
13
|
import { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';
|
|
13
14
|
import type { Event } from '../../types/event';
|
|
14
15
|
import type { SessionRestorationState } from '../../types/auth';
|
|
@@ -24,7 +25,15 @@ import { useInactivityService } from '../../hooks/services/useInactivityService'
|
|
|
24
25
|
import { useSessionRestoration } from '../../hooks/useSessionRestoration';
|
|
25
26
|
import { logger } from '../../utils/core/logger';
|
|
26
27
|
import { setupRBAC, isRBACInitialized } from '../../rbac/api';
|
|
27
|
-
import {
|
|
28
|
+
import { setPrintAppName } from '../../theming/runtime';
|
|
29
|
+
import { UnifiedAuthContext } from './UnifiedAuthContext';
|
|
30
|
+
import {
|
|
31
|
+
useAppIdResolution,
|
|
32
|
+
useUnifiedAuthSubscriptions,
|
|
33
|
+
useUnifiedAuthContextValue,
|
|
34
|
+
type UnifiedAuthContextState,
|
|
35
|
+
type UnifiedAuthContextCallbacks,
|
|
36
|
+
} from './useUnifiedAuthContextValue';
|
|
28
37
|
|
|
29
38
|
// Re-export UserEventAccess type
|
|
30
39
|
/**
|
|
@@ -69,230 +78,40 @@ export interface UnifiedAuthProviderProps {
|
|
|
69
78
|
dangerouslyDisableInactivity?: boolean; // Dev-only; must not disable in production
|
|
70
79
|
}
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
restorationComplete,
|
|
88
|
-
restorationError,
|
|
89
|
-
} = sessionRestorationState;
|
|
90
|
-
const sessionRestoration: SessionRestorationState = useMemo(() => ({
|
|
91
|
-
isRestoring,
|
|
92
|
-
restorationComplete,
|
|
93
|
-
restorationError,
|
|
94
|
-
}), [isRestoring, restorationComplete, restorationError]);
|
|
95
|
-
|
|
96
|
-
// App config removed - scope is now page-level only (rbac_app_pages.scope_type)
|
|
97
|
-
|
|
98
|
-
// Call hook unconditionally - if provider is missing, it will throw
|
|
99
|
-
// Errors should be handled by error boundaries at a higher level
|
|
100
|
-
// We cannot conditionally call hooks
|
|
101
|
-
const eventService = useEventService();
|
|
102
|
-
|
|
103
|
-
// Get current auth state - these will trigger re-renders when services change
|
|
104
|
-
const currentUser = authService.getUser();
|
|
105
|
-
const currentSession = authService.getSession();
|
|
81
|
+
/** Build state and callbacks from services. Extracted to keep UnifiedAuthContextProvider under max-lines. */
|
|
82
|
+
function useUnifiedAuthStateAndCallbacks(
|
|
83
|
+
authService: ReturnType<typeof useAuthService>,
|
|
84
|
+
organisationService: ReturnType<typeof useOrganisationService>,
|
|
85
|
+
eventService: ReturnType<typeof useEventService>,
|
|
86
|
+
inactivityService: ReturnType<typeof useInactivityService>,
|
|
87
|
+
sessionRestoration: SessionRestorationState,
|
|
88
|
+
sessionRestorationTimedOut: boolean,
|
|
89
|
+
sessionRestorationTimeoutMs: number,
|
|
90
|
+
appName: string,
|
|
91
|
+
userOverride?: User | null,
|
|
92
|
+
sessionOverride?: Session | null
|
|
93
|
+
): { state: UnifiedAuthContextState; callbacks: UnifiedAuthContextCallbacks } {
|
|
94
|
+
const currentUser = userOverride !== undefined ? userOverride : authService.getUser();
|
|
95
|
+
const currentSession = sessionOverride !== undefined ? sessionOverride : authService.getSession();
|
|
106
96
|
const isAuth = !!(currentUser && currentSession);
|
|
107
|
-
|
|
108
|
-
// Stabilize supabase client reference to prevent infinite re-renders
|
|
109
|
-
// Memoize the supabaseClient prop to ensure a stable reference across renders
|
|
110
|
-
// This is critical for preventing infinite loops when supabase is used in useEffect dependency arrays
|
|
111
|
-
// The reference will only change when supabaseClientProp actually changes (different instance)
|
|
112
|
-
// If the consuming app creates the client once and reuses it, this will be stable
|
|
113
|
-
const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
|
|
114
|
-
|
|
115
|
-
// Resolve appId immediately when user logs in (don't wait for organisation/event)
|
|
116
|
-
// This makes appId available early for navigation menu filtering
|
|
117
|
-
const [appId, setAppId] = useState<string | undefined>(undefined);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const isResolvingAppIdRef = useRef(false);
|
|
121
|
-
const resolvedAppIdRef = useRef<string | undefined>(undefined);
|
|
122
|
-
const resolvedUserIdRef = useRef<string | undefined>(undefined);
|
|
123
|
-
|
|
124
|
-
useEffect(() => {
|
|
125
|
-
// Clear appId when user logs out or changes
|
|
126
|
-
if (!isAuth) {
|
|
127
|
-
// User logged out - clear all refs and state
|
|
128
|
-
resolvedAppIdRef.current = undefined;
|
|
129
|
-
resolvedUserIdRef.current = undefined;
|
|
130
|
-
setAppId(undefined);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// User changed - clear previous resolution to allow re-resolution for new user
|
|
135
|
-
if (currentUser?.id && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUser.id) {
|
|
136
|
-
resolvedAppIdRef.current = undefined;
|
|
137
|
-
resolvedUserIdRef.current = undefined;
|
|
138
|
-
setAppId(undefined);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Resolve appId as soon as we have user + supabase + appName
|
|
142
|
-
// Don't wait for organisation or event - appId resolution only needs user + appName
|
|
143
|
-
// Extract userId to stable const to prevent reference issues
|
|
144
|
-
const currentUserId = currentUser?.id;
|
|
145
|
-
|
|
146
|
-
// Only resolve if we haven't already resolved for this user
|
|
147
|
-
if (
|
|
148
|
-
isAuth &&
|
|
149
|
-
currentUserId &&
|
|
150
|
-
supabase &&
|
|
151
|
-
appName &&
|
|
152
|
-
resolvedUserIdRef.current !== currentUserId && // Haven't resolved for this user yet
|
|
153
|
-
!isResolvingAppIdRef.current
|
|
154
|
-
) {
|
|
155
|
-
// CRITICAL FIX: Set refs IMMEDIATELY (synchronously) before async operation
|
|
156
|
-
// This prevents race conditions where effect re-runs before async completes
|
|
157
|
-
isResolvingAppIdRef.current = true;
|
|
158
|
-
resolvedUserIdRef.current = currentUserId; // Set BEFORE async, not after
|
|
159
|
-
|
|
160
|
-
const userId = currentUserId;
|
|
161
|
-
const appNameValue = appName;
|
|
162
|
-
|
|
163
|
-
// Resolve appId immediately
|
|
164
|
-
import('../../rbac/api').then(async ({ resolveAppContext, setupRBAC }) => {
|
|
165
|
-
try {
|
|
166
|
-
// Ensure RBAC is initialized (idempotent - safe to call multiple times)
|
|
167
|
-
setupRBAC(supabase);
|
|
168
|
-
|
|
169
|
-
const result = await resolveAppContext({
|
|
170
|
-
userId,
|
|
171
|
-
appName: appNameValue
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
if (result?.appId) {
|
|
175
|
-
resolvedAppIdRef.current = result.appId;
|
|
176
|
-
// resolvedUserIdRef already set above to prevent race conditions
|
|
177
|
-
setAppId(result.appId);
|
|
178
|
-
} else {
|
|
179
|
-
// No appId returned - reset ref to allow retry
|
|
180
|
-
resolvedUserIdRef.current = undefined;
|
|
181
|
-
}
|
|
182
|
-
} catch (error) {
|
|
183
|
-
logger.error('UnifiedAuthProvider', 'Failed to resolve appId on login', {
|
|
184
|
-
error: error instanceof Error ? error.message : String(error),
|
|
185
|
-
appName: appNameValue,
|
|
186
|
-
userId
|
|
187
|
-
});
|
|
188
|
-
// Reset ref on error to allow retry
|
|
189
|
-
resolvedUserIdRef.current = undefined;
|
|
190
|
-
} finally {
|
|
191
|
-
isResolvingAppIdRef.current = false;
|
|
192
|
-
}
|
|
193
|
-
}).catch((importError) => {
|
|
194
|
-
logger.error('UnifiedAuthProvider', 'Failed to import RBAC API', importError);
|
|
195
|
-
isResolvingAppIdRef.current = false;
|
|
196
|
-
// Reset ref on import error to allow retry
|
|
197
|
-
resolvedUserIdRef.current = undefined;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}, [isAuth, currentUser?.id, supabase, appName]); // Removed appId from deps - it's the output, not an input. currentUser?.id is stable primitive.
|
|
201
|
-
|
|
202
97
|
|
|
203
|
-
// Subscribe to service state changes to trigger re-renders
|
|
204
|
-
// Use useReducer to force updates when services notify
|
|
205
|
-
const [, forceUpdate] = useReducer(x => x + 1, 0);
|
|
206
|
-
const forceUpdateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
207
|
-
|
|
208
|
-
const debouncedForceUpdate = useCallback(() => {
|
|
209
|
-
if (forceUpdateTimeoutRef.current) {
|
|
210
|
-
clearTimeout(forceUpdateTimeoutRef.current);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
forceUpdateTimeoutRef.current = setTimeout(() => {
|
|
214
|
-
forceUpdate();
|
|
215
|
-
forceUpdateTimeoutRef.current = null;
|
|
216
|
-
}, 100); // Batch updates - 100ms debounce to prevent excessive re-renders
|
|
217
|
-
// Reduced from 16ms to 100ms to better batch service state updates
|
|
218
|
-
// and prevent flickering when multiple services update in quick succession
|
|
219
|
-
}, [forceUpdate]);
|
|
220
|
-
|
|
221
|
-
// Use refs for services to avoid dependency on service instances
|
|
222
|
-
// This prevents re-subscriptions when service instances change reference
|
|
223
|
-
const authServiceRef = useRef(authService);
|
|
224
|
-
const organisationServiceRef = useRef(organisationService);
|
|
225
|
-
const eventServiceRef = useRef(eventService);
|
|
226
|
-
const inactivityServiceRef = useRef(inactivityService);
|
|
227
|
-
|
|
228
|
-
// Update refs when services change
|
|
229
|
-
useEffect(() => {
|
|
230
|
-
authServiceRef.current = authService;
|
|
231
|
-
organisationServiceRef.current = organisationService;
|
|
232
|
-
eventServiceRef.current = eventService;
|
|
233
|
-
inactivityServiceRef.current = inactivityService;
|
|
234
|
-
}, [authService, organisationService, eventService, inactivityService]);
|
|
235
|
-
|
|
236
|
-
// Subscribe using refs - only depends on debouncedForceUpdate
|
|
237
|
-
// This prevents re-subscriptions when service instances change
|
|
238
|
-
useEffect(() => {
|
|
239
|
-
// Subscribe to all service changes using current refs
|
|
240
|
-
const unsubscribeAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
|
|
241
|
-
const unsubscribeOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
|
|
242
|
-
const unsubscribeEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
|
|
243
|
-
const unsubscribeInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
|
|
244
|
-
|
|
245
|
-
return () => {
|
|
246
|
-
unsubscribeAuth();
|
|
247
|
-
unsubscribeOrg();
|
|
248
|
-
unsubscribeEvent();
|
|
249
|
-
unsubscribeInactivity();
|
|
250
|
-
|
|
251
|
-
if (forceUpdateTimeoutRef.current) {
|
|
252
|
-
clearTimeout(forceUpdateTimeoutRef.current);
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
}, [debouncedForceUpdate]);
|
|
256
|
-
|
|
257
|
-
// Get loading states - these will trigger re-renders when services change
|
|
258
98
|
const authLoading = authService.isLoading();
|
|
259
99
|
const orgLoading = organisationService.isLoading();
|
|
260
100
|
const eventLoading = eventService.isLoading();
|
|
261
101
|
const restorationLoading = sessionRestoration.isRestoring && !sessionRestorationTimedOut && !sessionRestoration.restorationError;
|
|
262
|
-
// For ADMIN/PORTAL apps, don't block on organisation loading (super admins can proceed)
|
|
263
102
|
const shouldIncludeOrgLoading = appName !== 'ADMIN' && appName !== 'PORTAL';
|
|
264
103
|
const totalLoading = restorationLoading || authLoading || (shouldIncludeOrgLoading ? orgLoading : false) || eventLoading;
|
|
265
|
-
|
|
266
|
-
// Extract all primitive values from services to use in dependencies
|
|
267
104
|
const authError = authService.getError();
|
|
268
|
-
|
|
269
|
-
const rawSelectedOrganisation = organisationService.getSelectedOrganisation();
|
|
105
|
+
const selectedOrganisation = organisationService.getSelectedOrganisation();
|
|
270
106
|
const organisationError = organisationService.getError();
|
|
271
|
-
|
|
272
|
-
// Scope is now page-level only - use whatever organisation is selected
|
|
273
|
-
// No app-level scope determination needed
|
|
274
|
-
const selectedOrganisation = rawSelectedOrganisation;
|
|
275
107
|
const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();
|
|
276
108
|
const isContextReady = organisationService.isContextReady();
|
|
277
|
-
|
|
278
|
-
// Get raw data from services
|
|
279
109
|
const rawEvents = eventService.getEvents();
|
|
280
110
|
const rawOrganisations = organisationService.getOrganisations();
|
|
281
111
|
const rawUserMemberships = organisationService.getUserMemberships();
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
return rawEvents;
|
|
286
|
-
}, [rawEvents]);
|
|
287
|
-
|
|
288
|
-
const organisations = useMemo(() => {
|
|
289
|
-
return rawOrganisations;
|
|
290
|
-
}, [rawOrganisations]);
|
|
291
|
-
|
|
292
|
-
const userMemberships = useMemo(() => {
|
|
293
|
-
return rawUserMemberships;
|
|
294
|
-
}, [rawUserMemberships]);
|
|
295
|
-
|
|
112
|
+
const events = useMemo(() => rawEvents, [rawEvents]);
|
|
113
|
+
const organisations = useMemo(() => rawOrganisations, [rawOrganisations]);
|
|
114
|
+
const userMemberships = useMemo(() => rawUserMemberships, [rawUserMemberships]);
|
|
296
115
|
const selectedEvent = eventService.getSelectedEvent();
|
|
297
116
|
const eventError = eventService.getError();
|
|
298
117
|
const showInactivityWarning = inactivityService.getShowInactivityWarning();
|
|
@@ -301,8 +120,6 @@ function UnifiedAuthContextProvider({
|
|
|
301
120
|
const timeRemaining = inactivityService.getTimeRemaining();
|
|
302
121
|
const showWarning = inactivityService.isWarningShown();
|
|
303
122
|
const isTracking = inactivityService.isTracking();
|
|
304
|
-
|
|
305
|
-
// Memoize inactivity values to prevent unnecessary context updates
|
|
306
123
|
const inactivityState = useMemo(() => ({
|
|
307
124
|
showInactivityWarning,
|
|
308
125
|
inactivityTimeRemaining,
|
|
@@ -310,25 +127,15 @@ function UnifiedAuthContextProvider({
|
|
|
310
127
|
timeRemaining,
|
|
311
128
|
showWarning,
|
|
312
129
|
isTracking,
|
|
313
|
-
}), [
|
|
314
|
-
showInactivityWarning,
|
|
315
|
-
inactivityTimeRemaining,
|
|
316
|
-
isIdle,
|
|
317
|
-
timeRemaining,
|
|
318
|
-
showWarning,
|
|
319
|
-
isTracking,
|
|
320
|
-
]);
|
|
321
|
-
|
|
130
|
+
}), [showInactivityWarning, inactivityTimeRemaining, isIdle, timeRemaining, showWarning, isTracking]);
|
|
322
131
|
const hasErrors = !!(authError || organisationError || eventError || sessionRestoration.restorationError);
|
|
323
132
|
|
|
324
|
-
// Wrap all functions in useCallback to ensure stable references
|
|
325
133
|
const signIn = useCallback((email: string, password?: string) => authService.signIn(email, password), [authService]);
|
|
326
134
|
const signUp = useCallback((email: string, password: string) => authService.signUp(email, password), [authService]);
|
|
327
135
|
const signOut = useCallback(() => authService.signOut(), [authService]);
|
|
328
136
|
const resetPassword = useCallback((email: string) => authService.resetPassword(email), [authService]);
|
|
329
137
|
const updatePassword = useCallback((password: string) => authService.updatePassword(password), [authService]);
|
|
330
138
|
const refreshSession = useCallback(() => authService.refreshSession(), [authService]);
|
|
331
|
-
|
|
332
139
|
const switchOrganisation = useCallback((orgId: string) => organisationService.switchOrganisation(orgId), [organisationService]);
|
|
333
140
|
const getUserRole = useCallback((orgId?: string) => organisationService.getUserRole(orgId), [organisationService]);
|
|
334
141
|
const validateOrganisationAccess = useCallback((orgId: string) => organisationService.validateOrganisationAccess(orgId), [organisationService]);
|
|
@@ -336,10 +143,8 @@ function UnifiedAuthContextProvider({
|
|
|
336
143
|
const ensureOrganisationContext = useCallback(() => organisationService.ensureOrganisationContext(), [organisationService]);
|
|
337
144
|
const isOrganisationSecure = useCallback(() => organisationService.isOrganisationSecure(), [organisationService]);
|
|
338
145
|
const getPrimaryOrganisation = useCallback(() => organisationService.getPrimaryOrganisation(), [organisationService]);
|
|
339
|
-
|
|
340
146
|
const setSelectedEvent = useCallback((event: Event | null) => eventService.setSelectedEvent(event), [eventService]);
|
|
341
147
|
const refreshEvents = useCallback(() => eventService.refreshEvents(), [eventService]);
|
|
342
|
-
|
|
343
148
|
const resetActivity = useCallback(() => inactivityService.resetActivity(), [inactivityService]);
|
|
344
149
|
const startTracking = useCallback(() => inactivityService.startTracking(), [inactivityService]);
|
|
345
150
|
const stopTracking = useCallback(() => inactivityService.stopTracking(), [inactivityService]);
|
|
@@ -347,115 +152,12 @@ function UnifiedAuthContextProvider({
|
|
|
347
152
|
const handleStaySignedIn = useCallback(() => inactivityService.handleStaySignedIn(), [inactivityService]);
|
|
348
153
|
const handleSignOutNow = useCallback(() => inactivityService.handleSignOutNow(), [inactivityService]);
|
|
349
154
|
|
|
350
|
-
|
|
351
|
-
const prevStateRef = useRef<{
|
|
352
|
-
isAuthenticated: boolean;
|
|
353
|
-
userEmail: string | undefined;
|
|
354
|
-
totalLoading: boolean;
|
|
355
|
-
} | null>(null);
|
|
356
|
-
|
|
357
|
-
// Only log when state actually changes (dev mode detection)
|
|
358
|
-
const isDev = import.meta.env.DEV || import.meta.env.MODE === 'development';
|
|
359
|
-
if (isDev) {
|
|
360
|
-
const currentState = {
|
|
361
|
-
isAuthenticated: isAuth,
|
|
362
|
-
userEmail: currentUser?.email,
|
|
363
|
-
totalLoading,
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
const prevState = prevStateRef.current;
|
|
367
|
-
if (!prevState ||
|
|
368
|
-
prevState.isAuthenticated !== currentState.isAuthenticated ||
|
|
369
|
-
prevState.userEmail !== currentState.userEmail ||
|
|
370
|
-
prevState.totalLoading !== currentState.totalLoading) {
|
|
371
|
-
// State change detected, notify subscribers
|
|
372
|
-
prevStateRef.current = currentState;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Memoized combined context value - only depends on primitive values
|
|
377
|
-
const contextValue = useMemo<UnifiedAuthContextType>(() => {
|
|
378
|
-
return {
|
|
379
|
-
// Auth state
|
|
380
|
-
user: currentUser,
|
|
381
|
-
session: currentSession,
|
|
382
|
-
isAuthenticated: isAuth,
|
|
383
|
-
authLoading: authLoading,
|
|
384
|
-
authError: authError,
|
|
385
|
-
supabase: supabase,
|
|
386
|
-
|
|
387
|
-
// Auth methods
|
|
388
|
-
signIn,
|
|
389
|
-
signUp,
|
|
390
|
-
signOut,
|
|
391
|
-
resetPassword,
|
|
392
|
-
updatePassword,
|
|
393
|
-
refreshSession,
|
|
394
|
-
|
|
395
|
-
// Organisation state
|
|
396
|
-
selectedOrganisation: selectedOrganisation,
|
|
397
|
-
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
398
|
-
organisations: organisations,
|
|
399
|
-
userMemberships: userMemberships,
|
|
400
|
-
organisationLoading: orgLoading,
|
|
401
|
-
organisationError: organisationError,
|
|
402
|
-
hasValidOrganisationContext: hasValidOrganisationContext,
|
|
403
|
-
isContextReady: isContextReady,
|
|
404
|
-
|
|
405
|
-
// Organisation methods
|
|
406
|
-
switchOrganisation,
|
|
407
|
-
getUserRole,
|
|
408
|
-
validateOrganisationAccess,
|
|
409
|
-
refreshOrganisations,
|
|
410
|
-
ensureOrganisationContext,
|
|
411
|
-
isOrganisationSecure,
|
|
412
|
-
getPrimaryOrganisation,
|
|
413
|
-
|
|
414
|
-
// Event state
|
|
415
|
-
events: events,
|
|
416
|
-
selectedEvent: selectedEvent,
|
|
417
|
-
selectedEventId: selectedEvent?.event_id || null,
|
|
418
|
-
eventLoading: eventLoading,
|
|
419
|
-
eventError: eventError,
|
|
420
|
-
|
|
421
|
-
// Event methods
|
|
422
|
-
setSelectedEvent,
|
|
423
|
-
refreshEvents,
|
|
424
|
-
|
|
425
|
-
// Inactivity state
|
|
426
|
-
showInactivityWarning: inactivityState.showInactivityWarning,
|
|
427
|
-
inactivityTimeRemaining: inactivityState.inactivityTimeRemaining,
|
|
428
|
-
isIdle: inactivityState.isIdle,
|
|
429
|
-
timeRemaining: inactivityState.timeRemaining,
|
|
430
|
-
showWarning: inactivityState.showWarning,
|
|
431
|
-
isTracking: inactivityState.isTracking,
|
|
432
|
-
|
|
433
|
-
// Inactivity methods
|
|
434
|
-
resetActivity,
|
|
435
|
-
startTracking,
|
|
436
|
-
stopTracking,
|
|
437
|
-
handleIdleLogout,
|
|
438
|
-
handleStaySignedIn,
|
|
439
|
-
handleSignOutNow,
|
|
440
|
-
|
|
441
|
-
// Additional unified properties
|
|
442
|
-
appName,
|
|
443
|
-
appId, // Resolved immediately on login
|
|
444
|
-
isLoading: totalLoading,
|
|
445
|
-
hasErrors: hasErrors,
|
|
446
|
-
sessionRestoration: sessionRestoration,
|
|
447
|
-
sessionRestorationTimedOut,
|
|
448
|
-
sessionRestorationTimeoutMs,
|
|
449
|
-
};
|
|
450
|
-
}, [
|
|
451
|
-
// All primitive values extracted from services
|
|
452
|
-
// Note: Arrays/objects from services are stable references (same reference unless data changes)
|
|
155
|
+
const state: UnifiedAuthContextState = useMemo(() => ({
|
|
453
156
|
currentUser,
|
|
454
157
|
currentSession,
|
|
455
158
|
isAuth,
|
|
456
159
|
authLoading,
|
|
457
160
|
authError,
|
|
458
|
-
supabase,
|
|
459
161
|
selectedOrganisation,
|
|
460
162
|
organisations,
|
|
461
163
|
userMemberships,
|
|
@@ -467,38 +169,86 @@ function UnifiedAuthContextProvider({
|
|
|
467
169
|
selectedEvent,
|
|
468
170
|
eventLoading,
|
|
469
171
|
eventError,
|
|
470
|
-
inactivityState,
|
|
172
|
+
inactivityState,
|
|
471
173
|
totalLoading,
|
|
472
174
|
hasErrors,
|
|
473
|
-
appName,
|
|
474
|
-
appId,
|
|
475
175
|
sessionRestoration,
|
|
476
176
|
sessionRestorationTimedOut,
|
|
477
177
|
sessionRestorationTimeoutMs,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
validateOrganisationAccess,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
startTracking,
|
|
496
|
-
|
|
497
|
-
handleIdleLogout,
|
|
498
|
-
handleStaySignedIn,
|
|
499
|
-
handleSignOutNow,
|
|
178
|
+
}), [
|
|
179
|
+
currentUser, currentSession, isAuth, authLoading, authError, selectedOrganisation, organisations,
|
|
180
|
+
userMemberships, orgLoading, organisationError, hasValidOrganisationContext, isContextReady,
|
|
181
|
+
events, selectedEvent, eventLoading, eventError, inactivityState, totalLoading, hasErrors,
|
|
182
|
+
sessionRestoration, sessionRestorationTimedOut, sessionRestorationTimeoutMs,
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
const callbacks: UnifiedAuthContextCallbacks = useMemo(() => ({
|
|
186
|
+
signIn, signUp, signOut, resetPassword, updatePassword, refreshSession,
|
|
187
|
+
switchOrganisation, getUserRole, validateOrganisationAccess, refreshOrganisations,
|
|
188
|
+
ensureOrganisationContext, isOrganisationSecure, getPrimaryOrganisation,
|
|
189
|
+
setSelectedEvent, refreshEvents, resetActivity, startTracking, stopTracking,
|
|
190
|
+
handleIdleLogout, handleStaySignedIn, handleSignOutNow,
|
|
191
|
+
}), [
|
|
192
|
+
signIn, signUp, signOut, resetPassword, updatePassword, refreshSession,
|
|
193
|
+
switchOrganisation, getUserRole, validateOrganisationAccess, refreshOrganisations,
|
|
194
|
+
ensureOrganisationContext, isOrganisationSecure, getPrimaryOrganisation,
|
|
195
|
+
setSelectedEvent, refreshEvents, resetActivity, startTracking, stopTracking,
|
|
196
|
+
handleIdleLogout, handleStaySignedIn, handleSignOutNow,
|
|
500
197
|
]);
|
|
501
198
|
|
|
199
|
+
return { state, callbacks };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Internal component that combines all contexts.
|
|
203
|
+
// When user/session are passed from ServiceAwareProviders, they are the subscription-updated values
|
|
204
|
+
// and must be used for the context so consumers see the same state (avoids stale authService.getUser() in same tick).
|
|
205
|
+
function UnifiedAuthContextProvider({
|
|
206
|
+
children,
|
|
207
|
+
appName,
|
|
208
|
+
supabaseClient: supabaseClientProp,
|
|
209
|
+
user: userFromParent,
|
|
210
|
+
session: sessionFromParent,
|
|
211
|
+
}: UnifiedAuthProviderProps & { user?: User | null; session?: Session | null }) {
|
|
212
|
+
const authService = useAuthService();
|
|
213
|
+
const organisationService = useOrganisationService();
|
|
214
|
+
const inactivityService = useInactivityService();
|
|
215
|
+
const eventService = useEventService();
|
|
216
|
+
const sessionRestorationState = useSessionRestoration();
|
|
217
|
+
const sessionRestoration: SessionRestorationState = useMemo(() => ({
|
|
218
|
+
isRestoring: sessionRestorationState.isRestoring,
|
|
219
|
+
restorationComplete: sessionRestorationState.restorationComplete,
|
|
220
|
+
restorationError: sessionRestorationState.restorationError,
|
|
221
|
+
}), [sessionRestorationState.isRestoring, sessionRestorationState.restorationComplete, sessionRestorationState.restorationError]);
|
|
222
|
+
const { hasTimedOut: sessionRestorationTimedOut, timeoutMs: sessionRestorationTimeoutMs } = sessionRestorationState;
|
|
223
|
+
|
|
224
|
+
const currentUser = userFromParent !== undefined ? userFromParent : authService.getUser();
|
|
225
|
+
const currentSession = sessionFromParent !== undefined ? sessionFromParent : authService.getSession();
|
|
226
|
+
const isAuth = !!(currentUser && currentSession);
|
|
227
|
+
const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
|
|
228
|
+
|
|
229
|
+
const appId = useAppIdResolution(supabase, appName, isAuth, currentUser?.id);
|
|
230
|
+
useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService);
|
|
231
|
+
|
|
232
|
+
const { state, callbacks } = useUnifiedAuthStateAndCallbacks(
|
|
233
|
+
authService,
|
|
234
|
+
organisationService,
|
|
235
|
+
eventService,
|
|
236
|
+
inactivityService,
|
|
237
|
+
sessionRestoration,
|
|
238
|
+
sessionRestorationTimedOut,
|
|
239
|
+
sessionRestorationTimeoutMs,
|
|
240
|
+
appName,
|
|
241
|
+
currentUser,
|
|
242
|
+
currentSession
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const contextValue = useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase);
|
|
246
|
+
|
|
247
|
+
// Set --print-app-name once when app mounts so print headers/footers use the correct app name
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
if (appName) setPrintAppName(appName);
|
|
250
|
+
}, [appName]);
|
|
251
|
+
|
|
502
252
|
return (
|
|
503
253
|
<UnifiedAuthContext.Provider value={contextValue}>
|
|
504
254
|
{children}
|
|
@@ -574,15 +324,18 @@ function ServiceAwareProviders({
|
|
|
574
324
|
const [userState, setUserState] = useState(() => authService.getUser());
|
|
575
325
|
const [sessionState, setSessionState] = useState(() => authService.getSession());
|
|
576
326
|
|
|
577
|
-
// Subscribe directly to auth service changes and update state immediately
|
|
327
|
+
// Subscribe directly to auth service changes and update state immediately.
|
|
328
|
+
// flushSync ensures the context updates before the next tick so consumers (e.g. PaceLoginPage
|
|
329
|
+
// useEffect, ProtectedRoute) see isAuthenticated/user on the very next render and avoid
|
|
330
|
+
// redirect-to-login races when navigation happens after signIn.
|
|
578
331
|
useEffect(() => {
|
|
579
332
|
const unsubscribe = authService.subscribe(() => {
|
|
580
|
-
// Update state immediately when auth service notifies (bypasses debounce)
|
|
581
333
|
const newUser = authService.getUser();
|
|
582
334
|
const newSession = authService.getSession();
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
335
|
+
flushSync(() => {
|
|
336
|
+
setUserState(newUser);
|
|
337
|
+
setSessionState(newSession);
|
|
338
|
+
});
|
|
586
339
|
});
|
|
587
340
|
return unsubscribe;
|
|
588
341
|
}, [authService]);
|
|
@@ -616,6 +369,8 @@ function ServiceAwareProviders({
|
|
|
616
369
|
<UnifiedAuthContextProvider
|
|
617
370
|
appName={appName}
|
|
618
371
|
supabaseClient={supabaseClient}
|
|
372
|
+
user={user}
|
|
373
|
+
session={session}
|
|
619
374
|
persistState={persistState}
|
|
620
375
|
enablePersistence={enablePersistence}
|
|
621
376
|
requireOrganisationContext={requireOrganisationContext}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file Service Contexts Unit Tests
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module Providers/Services
|
|
4
|
+
* @module Providers/Services
|
|
5
5
|
* @since 0.1.0
|
|
6
6
|
*
|
|
7
7
|
* Comprehensive unit tests for service context files covering:
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
import React from 'react';
|
|
14
14
|
import { render, screen } from '@testing-library/react';
|
|
15
15
|
import { describe, it, expect, vi } from 'vitest';
|
|
16
|
-
import { AuthServiceContext, type AuthServiceContextType } from '
|
|
17
|
-
import { EventServiceContext, type EventServiceContextType } from '
|
|
18
|
-
import { InactivityServiceContext, type InactivityServiceContextType } from '
|
|
19
|
-
import { OrganisationServiceContext, type OrganisationServiceContextType } from '
|
|
20
|
-
import { UnifiedAuthContext, type UnifiedAuthContextType } from '
|
|
16
|
+
import { AuthServiceContext, type AuthServiceContextType } from './AuthServiceContext';
|
|
17
|
+
import { EventServiceContext, type EventServiceContextType } from './EventServiceContext';
|
|
18
|
+
import { InactivityServiceContext, type InactivityServiceContextType } from './InactivityServiceContext';
|
|
19
|
+
import { OrganisationServiceContext, type OrganisationServiceContextType } from './OrganisationServiceContext';
|
|
20
|
+
import { UnifiedAuthContext, type UnifiedAuthContextType } from './UnifiedAuthContext';
|
|
21
21
|
|
|
22
22
|
// Following testing standards: use timeout parameter to prevent hanging
|
|
23
23
|
const TEST_TIMEOUT = 10000; // 10 seconds per test
|