@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,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setPrintAppName } from './chunk-D6BMFMQZ.js';
|
|
2
|
+
import { isRBACInitialized, setupRBAC } from './chunk-7A6IMHH2.js';
|
|
2
3
|
import { assertOrganisationId, assertUserId } from './chunk-4SXLQIZO.js';
|
|
3
4
|
import { secureStorage } from './chunk-RMLY6KB5.js';
|
|
4
5
|
import { createLogger, logger } from './chunk-BTHN5MKC.js';
|
|
6
|
+
import { err, ok } from './chunk-44CNXN4P.js';
|
|
5
7
|
import { createContext, useRef, useEffect, useState, useMemo, useContext, useReducer, useCallback } from 'react';
|
|
6
8
|
import { AuthError } from '@supabase/supabase-js';
|
|
7
9
|
import { jsx } from 'react/jsx-runtime';
|
|
10
|
+
import { flushSync } from 'react-dom';
|
|
8
11
|
|
|
9
12
|
// src/services/base/BaseService.ts
|
|
10
13
|
var BaseService = class {
|
|
@@ -74,6 +77,13 @@ var BaseService = class {
|
|
|
74
77
|
}
|
|
75
78
|
};
|
|
76
79
|
|
|
80
|
+
// src/utils/security/auth-utils.ts
|
|
81
|
+
function toApiError(error) {
|
|
82
|
+
const message = error.message || "An unexpected error occurred";
|
|
83
|
+
const code = "status" in error && typeof error.status === "number" ? `AUTH_${error.status}` : error.name || "AUTH_ERROR";
|
|
84
|
+
return { code, message };
|
|
85
|
+
}
|
|
86
|
+
|
|
77
87
|
// src/services/AuthService.ts
|
|
78
88
|
var _AuthService = class _AuthService extends BaseService {
|
|
79
89
|
// Track previous auth state to detect transitions
|
|
@@ -135,7 +145,7 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
135
145
|
const error = new AuthError("Supabase client not available");
|
|
136
146
|
this.authError = error;
|
|
137
147
|
this.notify();
|
|
138
|
-
return
|
|
148
|
+
return err(toApiError(error));
|
|
139
149
|
}
|
|
140
150
|
try {
|
|
141
151
|
const { data, error } = await this.supabaseClient.auth.signInWithPassword({
|
|
@@ -146,24 +156,25 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
146
156
|
this.authError = error;
|
|
147
157
|
this.user = null;
|
|
148
158
|
this.session = null;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
this.notify();
|
|
160
|
+
return err(toApiError(error));
|
|
161
|
+
}
|
|
162
|
+
this.authError = null;
|
|
163
|
+
this.user = data.user;
|
|
164
|
+
this.session = data.session;
|
|
165
|
+
if (!this.wasAuthenticatedRef && data.user) {
|
|
166
|
+
this.clearPersistenceOnLogin(null, true);
|
|
167
|
+
this.wasAuthenticatedRef = true;
|
|
157
168
|
}
|
|
158
169
|
this.notify();
|
|
159
|
-
return { user: data.user, session: data.session
|
|
170
|
+
return ok({ user: data.user, session: data.session });
|
|
160
171
|
} catch (error) {
|
|
161
172
|
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
162
173
|
this.authError = authError;
|
|
163
174
|
this.user = null;
|
|
164
175
|
this.session = null;
|
|
165
176
|
this.notify();
|
|
166
|
-
return
|
|
177
|
+
return err(toApiError(authError));
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
180
|
async signUp(email, password) {
|
|
@@ -171,7 +182,7 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
171
182
|
const error = new AuthError("Supabase client not available");
|
|
172
183
|
this.authError = error;
|
|
173
184
|
this.notify();
|
|
174
|
-
return
|
|
185
|
+
return err(toApiError(error));
|
|
175
186
|
}
|
|
176
187
|
try {
|
|
177
188
|
const { data, error } = await this.supabaseClient.auth.signUp({
|
|
@@ -182,24 +193,25 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
182
193
|
this.authError = error;
|
|
183
194
|
this.user = null;
|
|
184
195
|
this.session = null;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
this.notify();
|
|
197
|
+
return err(toApiError(error));
|
|
198
|
+
}
|
|
199
|
+
this.authError = null;
|
|
200
|
+
this.user = data.user;
|
|
201
|
+
this.session = data.session;
|
|
202
|
+
if (!this.wasAuthenticatedRef && data.user) {
|
|
203
|
+
this.clearPersistenceOnLogin(null, true);
|
|
204
|
+
this.wasAuthenticatedRef = true;
|
|
193
205
|
}
|
|
194
206
|
this.notify();
|
|
195
|
-
return { user: data.user, session: data.session
|
|
207
|
+
return ok({ user: data.user, session: data.session });
|
|
196
208
|
} catch (error) {
|
|
197
209
|
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
198
210
|
this.authError = authError;
|
|
199
211
|
this.user = null;
|
|
200
212
|
this.session = null;
|
|
201
213
|
this.notify();
|
|
202
|
-
return
|
|
214
|
+
return err(toApiError(authError));
|
|
203
215
|
}
|
|
204
216
|
}
|
|
205
217
|
async signOut() {
|
|
@@ -207,36 +219,47 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
207
219
|
const error = new AuthError("Supabase client not available");
|
|
208
220
|
this.authError = error;
|
|
209
221
|
this.notify();
|
|
210
|
-
return
|
|
222
|
+
return err(toApiError(error));
|
|
211
223
|
}
|
|
212
|
-
|
|
213
|
-
|
|
224
|
+
const clearLocalState = () => {
|
|
225
|
+
this.authError = null;
|
|
226
|
+
this.user = null;
|
|
227
|
+
this.session = null;
|
|
214
228
|
try {
|
|
215
229
|
sessionStorage.clear();
|
|
216
230
|
} catch (storageError) {
|
|
217
231
|
logger.warn("AuthService", "Failed to clear sessionStorage", { error: storageError });
|
|
218
232
|
}
|
|
233
|
+
this.notify();
|
|
234
|
+
};
|
|
235
|
+
try {
|
|
236
|
+
const { error } = await this.supabaseClient.auth.signOut();
|
|
219
237
|
if (error) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
238
|
+
logger.warn("AuthService", "signOut (global) failed, clearing local state and trying local scope", {
|
|
239
|
+
message: error.message,
|
|
240
|
+
status: error.status
|
|
241
|
+
});
|
|
242
|
+
clearLocalState();
|
|
243
|
+
const { error: localError } = await this.supabaseClient.auth.signOut({ scope: "local" });
|
|
244
|
+
if (localError) {
|
|
245
|
+
logger.warn("AuthService", "signOut (local) also failed", { message: localError.message });
|
|
246
|
+
}
|
|
247
|
+
return err(toApiError(error));
|
|
225
248
|
}
|
|
226
|
-
|
|
227
|
-
return { user: null, session: null
|
|
249
|
+
clearLocalState();
|
|
250
|
+
return ok({ user: null, session: null });
|
|
228
251
|
} catch (error) {
|
|
252
|
+
logger.warn("AuthService", "signOut threw, clearing local state and trying local scope", {
|
|
253
|
+
message: error instanceof Error ? error.message : String(error)
|
|
254
|
+
});
|
|
255
|
+
clearLocalState();
|
|
229
256
|
try {
|
|
230
|
-
|
|
231
|
-
} catch (
|
|
232
|
-
logger.warn("AuthService", "Failed to clear sessionStorage", { error: storageError });
|
|
257
|
+
await this.supabaseClient.auth.signOut({ scope: "local" });
|
|
258
|
+
} catch (_localError) {
|
|
233
259
|
}
|
|
234
260
|
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
235
261
|
this.authError = authError;
|
|
236
|
-
|
|
237
|
-
this.session = null;
|
|
238
|
-
this.notify();
|
|
239
|
-
return { user: null, session: null, error: authError };
|
|
262
|
+
return err(toApiError(authError));
|
|
240
263
|
}
|
|
241
264
|
}
|
|
242
265
|
async resetPassword(email) {
|
|
@@ -244,22 +267,23 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
244
267
|
const error = new AuthError("Supabase client not available");
|
|
245
268
|
this.authError = error;
|
|
246
269
|
this.notify();
|
|
247
|
-
return
|
|
270
|
+
return err(toApiError(error));
|
|
248
271
|
}
|
|
249
272
|
try {
|
|
250
273
|
const { error } = await this.supabaseClient.auth.resetPasswordForEmail(email);
|
|
251
274
|
if (error) {
|
|
252
275
|
this.authError = error;
|
|
253
|
-
|
|
254
|
-
|
|
276
|
+
this.notify();
|
|
277
|
+
return err(toApiError(error));
|
|
255
278
|
}
|
|
279
|
+
this.authError = null;
|
|
256
280
|
this.notify();
|
|
257
|
-
return { user:
|
|
281
|
+
return ok({ user: this.user, session: this.session });
|
|
258
282
|
} catch (error) {
|
|
259
283
|
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
260
284
|
this.authError = authError;
|
|
261
285
|
this.notify();
|
|
262
|
-
return
|
|
286
|
+
return err(toApiError(authError));
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
289
|
async updatePassword(password) {
|
|
@@ -267,7 +291,7 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
267
291
|
const error = new AuthError("Supabase client not available");
|
|
268
292
|
this.authError = error;
|
|
269
293
|
this.notify();
|
|
270
|
-
return
|
|
294
|
+
return err(toApiError(error));
|
|
271
295
|
}
|
|
272
296
|
try {
|
|
273
297
|
const { error } = await this.supabaseClient.auth.updateUser({
|
|
@@ -275,16 +299,17 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
275
299
|
});
|
|
276
300
|
if (error) {
|
|
277
301
|
this.authError = error;
|
|
278
|
-
|
|
279
|
-
|
|
302
|
+
this.notify();
|
|
303
|
+
return err(toApiError(error));
|
|
280
304
|
}
|
|
305
|
+
this.authError = null;
|
|
281
306
|
this.notify();
|
|
282
|
-
return { user:
|
|
307
|
+
return ok({ user: this.user, session: this.session });
|
|
283
308
|
} catch (error) {
|
|
284
|
-
const authError = error;
|
|
309
|
+
const authError = error instanceof AuthError ? error : error;
|
|
285
310
|
this.authError = authError;
|
|
286
311
|
this.notify();
|
|
287
|
-
return
|
|
312
|
+
return err(toApiError(authError));
|
|
288
313
|
}
|
|
289
314
|
}
|
|
290
315
|
async refreshSession() {
|
|
@@ -292,7 +317,7 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
292
317
|
const error = new AuthError("Supabase client not available");
|
|
293
318
|
this.authError = error;
|
|
294
319
|
this.notify();
|
|
295
|
-
return
|
|
320
|
+
return err(toApiError(error));
|
|
296
321
|
}
|
|
297
322
|
try {
|
|
298
323
|
const { data, error } = await this.supabaseClient.auth.refreshSession();
|
|
@@ -300,29 +325,29 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
300
325
|
this.authError = error;
|
|
301
326
|
this.user = null;
|
|
302
327
|
this.session = null;
|
|
328
|
+
this.notify();
|
|
329
|
+
return err(toApiError(error));
|
|
330
|
+
}
|
|
331
|
+
this.authError = null;
|
|
332
|
+
if (data?.user && data?.session) {
|
|
333
|
+
this.user = data.user;
|
|
334
|
+
this.session = data.session;
|
|
303
335
|
} else {
|
|
304
|
-
this.
|
|
305
|
-
|
|
306
|
-
this.user = data.user;
|
|
307
|
-
this.session = data.session;
|
|
308
|
-
} else {
|
|
309
|
-
this.user = null;
|
|
310
|
-
this.session = null;
|
|
311
|
-
}
|
|
336
|
+
this.user = null;
|
|
337
|
+
this.session = null;
|
|
312
338
|
}
|
|
313
339
|
this.notify();
|
|
314
|
-
return {
|
|
340
|
+
return ok({
|
|
315
341
|
user: data?.user && data?.session ? data.user : null,
|
|
316
|
-
session: data?.session ?? null
|
|
317
|
-
|
|
318
|
-
};
|
|
342
|
+
session: data?.session ?? null
|
|
343
|
+
});
|
|
319
344
|
} catch (error) {
|
|
320
345
|
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
321
346
|
this.authError = authError;
|
|
322
347
|
this.user = null;
|
|
323
348
|
this.session = null;
|
|
324
349
|
this.notify();
|
|
325
|
-
return
|
|
350
|
+
return err(toApiError(authError));
|
|
326
351
|
}
|
|
327
352
|
}
|
|
328
353
|
// Lifecycle methods
|
|
@@ -432,6 +457,62 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
432
457
|
logger.warn("AuthService", `Failed to clear persistence [ID:${this.instanceId}]:`, error);
|
|
433
458
|
}
|
|
434
459
|
}
|
|
460
|
+
handleSignedOut(session) {
|
|
461
|
+
this.session = null;
|
|
462
|
+
this.user = null;
|
|
463
|
+
this.authError = null;
|
|
464
|
+
this.wasAuthenticatedRef = false;
|
|
465
|
+
if (session?.user) {
|
|
466
|
+
this.trackSession("logout", session).catch((err2) => {
|
|
467
|
+
logger.warn("AuthService", `Failed to track logout session [ID:${this.instanceId}]:`, err2);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
handleSignedInOrTokenRefreshed(event, session, wasAuthenticated, isNowAuthenticated, userChanged, previousUserId) {
|
|
472
|
+
this.session = session;
|
|
473
|
+
this.user = session?.user ?? null;
|
|
474
|
+
if (session?.user) {
|
|
475
|
+
this.authError = null;
|
|
476
|
+
}
|
|
477
|
+
if (!wasAuthenticated && isNowAuthenticated && event === "SIGNED_IN") {
|
|
478
|
+
this.clearPersistenceOnLogin(null, true);
|
|
479
|
+
} else if (userChanged && previousUserId) {
|
|
480
|
+
this.clearPersistenceOnLogin(previousUserId, true);
|
|
481
|
+
}
|
|
482
|
+
this.wasAuthenticatedRef = isNowAuthenticated;
|
|
483
|
+
if (event === "SIGNED_IN" && session?.user) {
|
|
484
|
+
this.trackSession("login", session).catch((err2) => {
|
|
485
|
+
logger.warn("AuthService", `Failed to track login session [ID:${this.instanceId}]:`, err2);
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
handleInitialSession(session, wasAuthenticated) {
|
|
490
|
+
if (session) {
|
|
491
|
+
const previousUserId = this.user?.id ?? null;
|
|
492
|
+
const newUserId = session.user?.id ?? null;
|
|
493
|
+
const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
|
|
494
|
+
this.session = session;
|
|
495
|
+
this.user = session.user ?? null;
|
|
496
|
+
this.authError = null;
|
|
497
|
+
if (userChanged && previousUserId) {
|
|
498
|
+
this.clearPersistenceOnLogin(previousUserId, true);
|
|
499
|
+
} else if (!wasAuthenticated && !!session.user) {
|
|
500
|
+
this.clearPersistenceOnLogin(null, true);
|
|
501
|
+
}
|
|
502
|
+
this.wasAuthenticatedRef = !!session.user;
|
|
503
|
+
const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
|
|
504
|
+
if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
|
|
505
|
+
this.finishSessionRestoration();
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
this.wasAuthenticatedRef = false;
|
|
509
|
+
if (this.sessionRestorationState.isRestoring) {
|
|
510
|
+
this.finishSessionRestoration();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
this.authLoading = false;
|
|
514
|
+
this.notify();
|
|
515
|
+
}
|
|
435
516
|
async setupAuthStateListener() {
|
|
436
517
|
if (!this.supabaseClient) {
|
|
437
518
|
this.authLoading = false;
|
|
@@ -444,62 +525,22 @@ var _AuthService = class _AuthService extends BaseService {
|
|
|
444
525
|
try {
|
|
445
526
|
const wasAuthenticated = this.wasAuthenticatedRef;
|
|
446
527
|
const isNowAuthenticated = !!session?.user;
|
|
447
|
-
const previousUserId = this.user?.id
|
|
448
|
-
const newUserId = session?.user?.id
|
|
528
|
+
const previousUserId = this.user?.id ?? null;
|
|
529
|
+
const newUserId = session?.user?.id ?? null;
|
|
449
530
|
const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
|
|
450
531
|
if (event === "SIGNED_OUT") {
|
|
451
|
-
this.session
|
|
452
|
-
this.user = null;
|
|
453
|
-
this.authError = null;
|
|
454
|
-
this.wasAuthenticatedRef = false;
|
|
455
|
-
if (session?.user) {
|
|
456
|
-
this.trackSession("logout", session).catch((err) => {
|
|
457
|
-
logger.warn("AuthService", `Failed to track logout session [ID:${this.instanceId}]:`, err);
|
|
458
|
-
});
|
|
459
|
-
}
|
|
532
|
+
this.handleSignedOut(session);
|
|
460
533
|
} else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
|
461
|
-
this.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
this.clearPersistenceOnLogin(previousUserId, true);
|
|
470
|
-
}
|
|
471
|
-
this.wasAuthenticatedRef = isNowAuthenticated;
|
|
472
|
-
if (event === "SIGNED_IN" && session?.user) {
|
|
473
|
-
this.trackSession("login", session).catch((err) => {
|
|
474
|
-
logger.warn("AuthService", `Failed to track login session [ID:${this.instanceId}]:`, err);
|
|
475
|
-
});
|
|
476
|
-
}
|
|
534
|
+
this.handleSignedInOrTokenRefreshed(
|
|
535
|
+
event,
|
|
536
|
+
session,
|
|
537
|
+
wasAuthenticated,
|
|
538
|
+
isNowAuthenticated,
|
|
539
|
+
userChanged,
|
|
540
|
+
previousUserId
|
|
541
|
+
);
|
|
477
542
|
} else if (event === "INITIAL_SESSION") {
|
|
478
|
-
|
|
479
|
-
const previousUserId2 = this.user?.id || null;
|
|
480
|
-
const newUserId2 = session.user?.id || null;
|
|
481
|
-
const userChanged2 = previousUserId2 !== null && newUserId2 !== null && previousUserId2 !== newUserId2;
|
|
482
|
-
this.session = session;
|
|
483
|
-
this.user = session.user ?? null;
|
|
484
|
-
this.authError = null;
|
|
485
|
-
if (userChanged2 && previousUserId2) {
|
|
486
|
-
this.clearPersistenceOnLogin(previousUserId2, true);
|
|
487
|
-
} else if (!wasAuthenticated && !!session.user) {
|
|
488
|
-
this.clearPersistenceOnLogin(null, true);
|
|
489
|
-
}
|
|
490
|
-
this.wasAuthenticatedRef = !!session.user;
|
|
491
|
-
const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
|
|
492
|
-
if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
|
|
493
|
-
this.finishSessionRestoration();
|
|
494
|
-
}
|
|
495
|
-
} else {
|
|
496
|
-
this.wasAuthenticatedRef = false;
|
|
497
|
-
if (this.sessionRestorationState.isRestoring) {
|
|
498
|
-
this.finishSessionRestoration();
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
this.authLoading = false;
|
|
502
|
-
this.notify();
|
|
543
|
+
this.handleInitialSession(session, wasAuthenticated);
|
|
503
544
|
return;
|
|
504
545
|
}
|
|
505
546
|
this.authLoading = false;
|
|
@@ -732,6 +773,7 @@ function AuthServiceProvider({ children, supabaseClient, appName }) {
|
|
|
732
773
|
}), [authService, sessionRestoration]);
|
|
733
774
|
return /* @__PURE__ */ jsx(AuthServiceContext.Provider, { value: contextValue, children });
|
|
734
775
|
}
|
|
776
|
+
var OrganisationServiceContext = createContext(null);
|
|
735
777
|
|
|
736
778
|
// src/services/OrganisationService.ts
|
|
737
779
|
var _OrganisationService = class _OrganisationService extends BaseService {
|
|
@@ -959,7 +1001,8 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
959
1001
|
this._isContextReady = true;
|
|
960
1002
|
this.notify();
|
|
961
1003
|
}
|
|
962
|
-
|
|
1004
|
+
/** Returns false if load should return early; when true, abort controller and loading state are set. */
|
|
1005
|
+
prepareLoad() {
|
|
963
1006
|
if (!this.user || !this.session || !this.supabaseClient) {
|
|
964
1007
|
this._selectedOrganisation = null;
|
|
965
1008
|
this._organisations = [];
|
|
@@ -967,12 +1010,12 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
967
1010
|
this._isLoading = false;
|
|
968
1011
|
this._error = null;
|
|
969
1012
|
this.notify();
|
|
970
|
-
return;
|
|
1013
|
+
return false;
|
|
971
1014
|
}
|
|
972
1015
|
if (this.isLoadingRef) {
|
|
973
1016
|
this._isLoading = true;
|
|
974
1017
|
this.notify();
|
|
975
|
-
return;
|
|
1018
|
+
return false;
|
|
976
1019
|
}
|
|
977
1020
|
const now = Date.now();
|
|
978
1021
|
if (this._organisations.length > 0 && now - this.lastLoadTimeRef < 2e3) {
|
|
@@ -982,146 +1025,183 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
982
1025
|
this._isLoading = true;
|
|
983
1026
|
}
|
|
984
1027
|
this.notify();
|
|
985
|
-
return;
|
|
1028
|
+
return false;
|
|
986
1029
|
}
|
|
987
1030
|
if (this.abortControllerRef) {
|
|
988
1031
|
this.abortControllerRef.abort();
|
|
989
1032
|
}
|
|
990
1033
|
this.abortControllerRef = new AbortController();
|
|
991
|
-
const abortSignal = this.abortControllerRef.signal;
|
|
992
1034
|
this.lastLoadTimeRef = now;
|
|
993
1035
|
this.isLoadingRef = true;
|
|
994
1036
|
this._isLoading = true;
|
|
995
1037
|
this._error = null;
|
|
996
1038
|
this.notify();
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
async fetchRolesAndOrganisations(signal) {
|
|
1042
|
+
if (signal.aborted) {
|
|
1043
|
+
throw new Error("Request aborted");
|
|
1044
|
+
}
|
|
1045
|
+
if (!this.supabaseClient || !this.user) {
|
|
1046
|
+
throw new Error("Missing supabase client or user");
|
|
1047
|
+
}
|
|
997
1048
|
try {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1049
|
+
const { data: rolesData, error: rolesError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
|
|
1050
|
+
id,
|
|
1051
|
+
user_id,
|
|
1052
|
+
organisation_id,
|
|
1053
|
+
role,
|
|
1054
|
+
status,
|
|
1055
|
+
granted_at,
|
|
1056
|
+
granted_by,
|
|
1057
|
+
revoked_at,
|
|
1058
|
+
revoked_by,
|
|
1059
|
+
notes,
|
|
1060
|
+
created_at,
|
|
1061
|
+
updated_at,
|
|
1062
|
+
core_organisations!inner(
|
|
1004
1063
|
id,
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
revoked_at,
|
|
1012
|
-
revoked_by,
|
|
1013
|
-
notes,
|
|
1064
|
+
name,
|
|
1065
|
+
display_name,
|
|
1066
|
+
subscription_tier,
|
|
1067
|
+
settings,
|
|
1068
|
+
is_active,
|
|
1069
|
+
parent_id,
|
|
1014
1070
|
created_at,
|
|
1015
|
-
updated_at
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
id: orgData.id,
|
|
1044
|
-
name: orgData.name,
|
|
1045
|
-
display_name: orgData.display_name,
|
|
1046
|
-
subscription_tier: orgData.subscription_tier,
|
|
1047
|
-
settings: orgData.settings,
|
|
1048
|
-
is_active: orgData.is_active,
|
|
1049
|
-
parent_id: orgData.parent_id,
|
|
1050
|
-
created_at: orgData.created_at,
|
|
1051
|
-
updated_at: orgData.updated_at
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
});
|
|
1055
|
-
organisations = Array.from(organisationsMap.values());
|
|
1056
|
-
} catch (queryError) {
|
|
1057
|
-
if (queryError instanceof Error) {
|
|
1058
|
-
membershipError = queryError;
|
|
1059
|
-
} else if (queryError && typeof queryError === "object" && "message" in queryError) {
|
|
1060
|
-
membershipError = new Error(String(queryError.message));
|
|
1061
|
-
} else {
|
|
1062
|
-
membershipError = new Error(String(queryError));
|
|
1071
|
+
updated_at
|
|
1072
|
+
)
|
|
1073
|
+
`).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null);
|
|
1074
|
+
if (rolesError) {
|
|
1075
|
+
logger.error("OrganisationService", "Error loading organisation roles:", rolesError);
|
|
1076
|
+
throw rolesError;
|
|
1077
|
+
}
|
|
1078
|
+
const memberships = rolesData?.map((m) => ({
|
|
1079
|
+
...m,
|
|
1080
|
+
user_id: assertUserId(m.user_id),
|
|
1081
|
+
organisation_id: assertOrganisationId(m.organisation_id)
|
|
1082
|
+
})) || [];
|
|
1083
|
+
const organisationsMap = /* @__PURE__ */ new Map();
|
|
1084
|
+
rolesData?.forEach((role) => {
|
|
1085
|
+
const roleWithOrg = role;
|
|
1086
|
+
const orgData = roleWithOrg.core_organisations;
|
|
1087
|
+
if (orgData && roleWithOrg.organisation_id && !organisationsMap.has(roleWithOrg.organisation_id)) {
|
|
1088
|
+
organisationsMap.set(roleWithOrg.organisation_id, {
|
|
1089
|
+
id: orgData.id,
|
|
1090
|
+
name: orgData.name,
|
|
1091
|
+
display_name: orgData.display_name,
|
|
1092
|
+
subscription_tier: orgData.subscription_tier,
|
|
1093
|
+
settings: orgData.settings,
|
|
1094
|
+
is_active: orgData.is_active,
|
|
1095
|
+
parent_id: orgData.parent_id,
|
|
1096
|
+
created_at: orgData.created_at,
|
|
1097
|
+
updated_at: orgData.updated_at
|
|
1098
|
+
});
|
|
1063
1099
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1100
|
+
});
|
|
1101
|
+
const organisations = Array.from(organisationsMap.values());
|
|
1102
|
+
return { memberships, organisations };
|
|
1103
|
+
} catch (queryError) {
|
|
1104
|
+
const err2 = queryError instanceof Error ? queryError : queryError && typeof queryError === "object" && "message" in queryError ? new Error(String(queryError.message)) : new Error(String(queryError));
|
|
1105
|
+
logger.error("OrganisationService", "Error loading organisation roles:", err2);
|
|
1106
|
+
throw err2;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
async checkAndCacheSuperAdmin() {
|
|
1110
|
+
if (!this.user?.id) {
|
|
1111
|
+
this._isSuperAdmin = false;
|
|
1112
|
+
return false;
|
|
1113
|
+
}
|
|
1114
|
+
try {
|
|
1115
|
+
const { isSuperAdmin: checkSuperAdmin, isRBACInitialized: isRBACInitialized2, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
|
|
1116
|
+
if (!isRBACInitialized2() && this.supabaseClient) {
|
|
1117
|
+
setupRBAC2(this.supabaseClient);
|
|
1066
1118
|
}
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1119
|
+
if (isRBACInitialized2()) {
|
|
1120
|
+
const result = await checkSuperAdmin(this.user.id);
|
|
1121
|
+
const isSuper = result.ok && result.data;
|
|
1122
|
+
this._isSuperAdmin = isSuper;
|
|
1123
|
+
return isSuper;
|
|
1124
|
+
}
|
|
1125
|
+
this._isSuperAdmin = false;
|
|
1126
|
+
return false;
|
|
1127
|
+
} catch (error) {
|
|
1128
|
+
logger.warn("OrganisationService", "Failed to check super admin status", { error });
|
|
1129
|
+
this._isSuperAdmin = false;
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
applyEmptyStateAndNotify() {
|
|
1134
|
+
this._organisations = [];
|
|
1135
|
+
this._userMemberships = [];
|
|
1136
|
+
this._isLoading = false;
|
|
1137
|
+
this._error = null;
|
|
1138
|
+
this._isContextReady = true;
|
|
1139
|
+
this.notify();
|
|
1140
|
+
}
|
|
1141
|
+
selectInitialOrganisation(activeOrgs, memberships, organisations) {
|
|
1142
|
+
let initialOrg = null;
|
|
1143
|
+
try {
|
|
1144
|
+
const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
|
|
1145
|
+
if (persistedOrgString) {
|
|
1146
|
+
const persistedOrg = JSON.parse(persistedOrgString);
|
|
1147
|
+
if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
|
|
1148
|
+
const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
|
|
1149
|
+
if (validPersistedOrg) {
|
|
1150
|
+
initialOrg = validPersistedOrg;
|
|
1076
1151
|
} else {
|
|
1077
|
-
|
|
1152
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1078
1153
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
logger.warn("OrganisationService", "Failed to check super admin status", { error });
|
|
1082
|
-
this._isSuperAdmin = false;
|
|
1154
|
+
} else {
|
|
1155
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1083
1156
|
}
|
|
1084
|
-
} else {
|
|
1085
|
-
this._isSuperAdmin = false;
|
|
1086
1157
|
}
|
|
1158
|
+
} catch {
|
|
1159
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1160
|
+
}
|
|
1161
|
+
if (!initialOrg) {
|
|
1162
|
+
const adminMembership = memberships.find((m) => m.role === "org_admin");
|
|
1163
|
+
if (adminMembership) {
|
|
1164
|
+
const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
|
|
1165
|
+
if (foundOrg) initialOrg = foundOrg;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
if (!initialOrg) {
|
|
1169
|
+
initialOrg = activeOrgs[0];
|
|
1170
|
+
}
|
|
1171
|
+
if (!initialOrg) {
|
|
1172
|
+
throw new Error("No valid organisation found for user");
|
|
1173
|
+
}
|
|
1174
|
+
localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
|
|
1175
|
+
return initialOrg;
|
|
1176
|
+
}
|
|
1177
|
+
async loadUserOrganisations() {
|
|
1178
|
+
if (!this.prepareLoad()) return;
|
|
1179
|
+
const abortSignal = this.abortControllerRef.signal;
|
|
1180
|
+
try {
|
|
1181
|
+
const { memberships, organisations } = await this.fetchRolesAndOrganisations(abortSignal);
|
|
1182
|
+
const userIsSuperAdmin = await this.checkAndCacheSuperAdmin();
|
|
1087
1183
|
if (!memberships || memberships.length === 0) {
|
|
1088
1184
|
if (userIsSuperAdmin) {
|
|
1089
|
-
this.
|
|
1090
|
-
this._userMemberships = [];
|
|
1091
|
-
this._isLoading = false;
|
|
1092
|
-
this._error = null;
|
|
1093
|
-
this._isContextReady = true;
|
|
1094
|
-
this.notify();
|
|
1185
|
+
this.applyEmptyStateAndNotify();
|
|
1095
1186
|
return;
|
|
1096
1187
|
}
|
|
1097
1188
|
throw new Error("User has no active organisation memberships");
|
|
1098
1189
|
}
|
|
1099
1190
|
if (!organisations || organisations.length === 0) {
|
|
1100
1191
|
if (userIsSuperAdmin) {
|
|
1101
|
-
this.
|
|
1102
|
-
this._userMemberships = [];
|
|
1103
|
-
this._isLoading = false;
|
|
1104
|
-
this._error = null;
|
|
1105
|
-
this._isContextReady = true;
|
|
1106
|
-
this.notify();
|
|
1192
|
+
this.applyEmptyStateAndNotify();
|
|
1107
1193
|
return;
|
|
1108
1194
|
}
|
|
1109
1195
|
throw new Error("No organisations found in role data");
|
|
1110
1196
|
}
|
|
1111
1197
|
const roleMap = /* @__PURE__ */ new Map();
|
|
1112
|
-
memberships
|
|
1198
|
+
memberships.forEach((membership) => {
|
|
1113
1199
|
roleMap.set(membership.organisation_id, membership.role);
|
|
1114
1200
|
});
|
|
1115
|
-
const
|
|
1116
|
-
const activeOrgs = orgs.filter((org) => org.is_active);
|
|
1201
|
+
const activeOrgs = organisations.filter((org) => org.is_active);
|
|
1117
1202
|
if (activeOrgs.length === 0) {
|
|
1118
1203
|
if (userIsSuperAdmin) {
|
|
1119
|
-
this.
|
|
1120
|
-
this._userMemberships = [];
|
|
1121
|
-
this._isLoading = false;
|
|
1122
|
-
this._error = null;
|
|
1123
|
-
this._isContextReady = true;
|
|
1124
|
-
this.notify();
|
|
1204
|
+
this.applyEmptyStateAndNotify();
|
|
1125
1205
|
return;
|
|
1126
1206
|
}
|
|
1127
1207
|
throw new Error("User has no access to active organisations");
|
|
@@ -1134,44 +1214,7 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
1134
1214
|
this._organisations = sortedOrgs;
|
|
1135
1215
|
this._userMemberships = memberships;
|
|
1136
1216
|
this._roleMapState = roleMap;
|
|
1137
|
-
|
|
1138
|
-
let _selectionMethod = "first";
|
|
1139
|
-
try {
|
|
1140
|
-
const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
|
|
1141
|
-
if (persistedOrgString) {
|
|
1142
|
-
const persistedOrg = JSON.parse(persistedOrgString);
|
|
1143
|
-
if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
|
|
1144
|
-
const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
|
|
1145
|
-
if (validPersistedOrg) {
|
|
1146
|
-
initialOrg = validPersistedOrg;
|
|
1147
|
-
_selectionMethod = "persisted";
|
|
1148
|
-
} else {
|
|
1149
|
-
localStorage.removeItem("pace-core-selected-organisation");
|
|
1150
|
-
}
|
|
1151
|
-
} else {
|
|
1152
|
-
localStorage.removeItem("pace-core-selected-organisation");
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
} catch (_storageError) {
|
|
1156
|
-
localStorage.removeItem("pace-core-selected-organisation");
|
|
1157
|
-
}
|
|
1158
|
-
if (!initialOrg) {
|
|
1159
|
-
const adminMembership = memberships.find((m) => m.role === "org_admin");
|
|
1160
|
-
if (adminMembership) {
|
|
1161
|
-
const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
|
|
1162
|
-
if (foundOrg) {
|
|
1163
|
-
initialOrg = foundOrg;
|
|
1164
|
-
_selectionMethod = "admin";
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
if (!initialOrg) {
|
|
1169
|
-
initialOrg = activeOrgs[0];
|
|
1170
|
-
_selectionMethod = "first";
|
|
1171
|
-
}
|
|
1172
|
-
if (!initialOrg) {
|
|
1173
|
-
throw new Error("No valid organisation found for user");
|
|
1174
|
-
}
|
|
1217
|
+
const initialOrg = this.selectInitialOrganisation(activeOrgs, memberships, organisations);
|
|
1175
1218
|
const currentSelectedOrg = this._selectedOrganisation;
|
|
1176
1219
|
if (currentSelectedOrg && !activeOrgs.some((org) => org.id === currentSelectedOrg.id)) {
|
|
1177
1220
|
logger.warn("OrganisationService", "Current selected organisation is no longer valid, resetting", {
|
|
@@ -1181,14 +1224,13 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
1181
1224
|
this._selectedOrganisation = null;
|
|
1182
1225
|
}
|
|
1183
1226
|
this._selectedOrganisation = initialOrg;
|
|
1184
|
-
localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
|
|
1185
1227
|
await this.setDatabaseOrganisationContext(initialOrg);
|
|
1186
1228
|
this.retryCount = 0;
|
|
1187
1229
|
this.hasFailedRef = false;
|
|
1188
|
-
} catch (
|
|
1189
|
-
const error =
|
|
1230
|
+
} catch (err2) {
|
|
1231
|
+
const error = err2;
|
|
1190
1232
|
if (error.message !== "User has no access to active organisations") {
|
|
1191
|
-
logger.error("OrganisationService", "Failed to load organisations:",
|
|
1233
|
+
logger.error("OrganisationService", "Failed to load organisations:", err2);
|
|
1192
1234
|
}
|
|
1193
1235
|
this._error = error;
|
|
1194
1236
|
this.retryCount = this.retryCount + 1;
|
|
@@ -1215,7 +1257,6 @@ var _OrganisationService = class _OrganisationService extends BaseService {
|
|
|
1215
1257
|
};
|
|
1216
1258
|
_OrganisationService.instanceCount = 0;
|
|
1217
1259
|
var OrganisationService = _OrganisationService;
|
|
1218
|
-
var OrganisationServiceContext = createContext(null);
|
|
1219
1260
|
function OrganisationServiceProvider({
|
|
1220
1261
|
children,
|
|
1221
1262
|
supabaseClient,
|
|
@@ -1303,86 +1344,100 @@ var _EventService = class _EventService extends BaseService {
|
|
|
1303
1344
|
const newOrgId = selectedOrganisation?.id;
|
|
1304
1345
|
const previousUserId = this.user?.id || null;
|
|
1305
1346
|
const newUserId = user?.id || null;
|
|
1306
|
-
this.
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
this.
|
|
1318
|
-
|
|
1319
|
-
|
|
1347
|
+
await this.handleUserChange(previousUserId, newUserId);
|
|
1348
|
+
this.applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
|
|
1349
|
+
await this.updateSuperAdminStatus(user);
|
|
1350
|
+
this.handleOrganisationChange(previousOrgId, newOrgId);
|
|
1351
|
+
this.notify();
|
|
1352
|
+
}
|
|
1353
|
+
async handleUserChange(previousUserId, newUserId) {
|
|
1354
|
+
if (previousUserId === newUserId) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
if (previousUserId !== null) {
|
|
1358
|
+
await this.clearEventSelectionForUser(previousUserId);
|
|
1359
|
+
}
|
|
1360
|
+
if (newUserId === null) {
|
|
1361
|
+
this.selectedEvent = null;
|
|
1362
|
+
this.setSelectedEventId?.(null);
|
|
1320
1363
|
}
|
|
1364
|
+
this.resetInitialization();
|
|
1365
|
+
this.isInitializedRef = false;
|
|
1366
|
+
this.isFetchingRef = false;
|
|
1367
|
+
this.userClearedEventRef = false;
|
|
1368
|
+
this.hasAutoSelectedRef = false;
|
|
1369
|
+
}
|
|
1370
|
+
applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
|
|
1321
1371
|
this.supabaseClient = supabaseClient;
|
|
1322
1372
|
this.user = user;
|
|
1323
1373
|
this.session = session;
|
|
1324
1374
|
this.appName = appName;
|
|
1325
1375
|
this.selectedOrganisation = selectedOrganisation;
|
|
1326
1376
|
this.setSelectedEventId = setSelectedEventId;
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
logger.warn("EventService", "Failed to check super admin status in updateDependencies", {
|
|
1344
|
-
error,
|
|
1377
|
+
}
|
|
1378
|
+
async updateSuperAdminStatus(user) {
|
|
1379
|
+
if (!user?.id) {
|
|
1380
|
+
this.isSuperAdmin = false;
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
try {
|
|
1384
|
+
const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
|
|
1385
|
+
if (!isRBACInitialized2() && this.supabaseClient) {
|
|
1386
|
+
setupRBAC2(this.supabaseClient);
|
|
1387
|
+
}
|
|
1388
|
+
if (isRBACInitialized2()) {
|
|
1389
|
+
const result = await checkSuperAdmin(user.id);
|
|
1390
|
+
this.isSuperAdmin = result.ok && result.data;
|
|
1391
|
+
} else {
|
|
1392
|
+
logger.warn("EventService", "RBAC not initialized in updateDependencies, keeping existing super admin status", {
|
|
1345
1393
|
userId: user.id,
|
|
1346
|
-
existingIsSuperAdmin: this.isSuperAdmin
|
|
1394
|
+
existingIsSuperAdmin: this.isSuperAdmin,
|
|
1395
|
+
note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
|
|
1347
1396
|
});
|
|
1348
1397
|
}
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
logger.warn("EventService", "Failed to check super admin status in updateDependencies", {
|
|
1400
|
+
error,
|
|
1401
|
+
userId: user.id,
|
|
1402
|
+
existingIsSuperAdmin: this.isSuperAdmin
|
|
1403
|
+
});
|
|
1351
1404
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
selectedEventId: this.selectedEvent?.event_id,
|
|
1368
|
-
hadAutoSelectedEvent,
|
|
1369
|
-
preservingEvent: hadAutoSelectedEvent,
|
|
1370
|
-
previousOrgId,
|
|
1371
|
-
newOrgId
|
|
1372
|
-
});
|
|
1373
|
-
} else if (previousOrgId !== null && previousOrgId !== void 0 && newOrgId !== null && newOrgId !== void 0 && previousOrgId !== newOrgId) {
|
|
1374
|
-
if (shouldClearEvents) {
|
|
1375
|
-
this.events = [];
|
|
1376
|
-
this.setSelectedEvent(null);
|
|
1377
|
-
}
|
|
1378
|
-
} else if (previousOrgId !== null && previousOrgId !== void 0 && newOrgId === null) {
|
|
1379
|
-
if (shouldClearEvents) {
|
|
1380
|
-
this.events = [];
|
|
1381
|
-
this.setSelectedEvent(null);
|
|
1382
|
-
}
|
|
1405
|
+
}
|
|
1406
|
+
handleOrganisationChange(previousOrgId, newOrgId) {
|
|
1407
|
+
if (previousOrgId === newOrgId) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
this.resetInitialization();
|
|
1411
|
+
this.isInitializedRef = false;
|
|
1412
|
+
this.isFetchingRef = false;
|
|
1413
|
+
const shouldClearEvents = !this.isSuperAdmin;
|
|
1414
|
+
const isFirstOrgSet = (previousOrgId === null || previousOrgId === void 0) && newOrgId !== null && newOrgId !== void 0;
|
|
1415
|
+
if (isFirstOrgSet) {
|
|
1416
|
+
const hadAutoSelectedEvent = this.hasAutoSelectedRef && !!this.selectedEvent;
|
|
1417
|
+
this.userClearedEventRef = false;
|
|
1418
|
+
if (!hadAutoSelectedEvent) {
|
|
1419
|
+
this.hasAutoSelectedRef = false;
|
|
1383
1420
|
}
|
|
1421
|
+
logger.debug("EventService", "Organisation first set - preserving event and resetting auto-selection flags", {
|
|
1422
|
+
organisationId: newOrgId,
|
|
1423
|
+
hasSelectedEvent: !!this.selectedEvent,
|
|
1424
|
+
selectedEventId: this.selectedEvent?.event_id,
|
|
1425
|
+
hadAutoSelectedEvent,
|
|
1426
|
+
preservingEvent: hadAutoSelectedEvent,
|
|
1427
|
+
previousOrgId,
|
|
1428
|
+
newOrgId
|
|
1429
|
+
});
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const switchingOrgs = previousOrgId != null && newOrgId != null && previousOrgId !== newOrgId;
|
|
1433
|
+
const orgRemoved = previousOrgId != null && newOrgId === null;
|
|
1434
|
+
if (switchingOrgs && shouldClearEvents) {
|
|
1435
|
+
this.events = [];
|
|
1436
|
+
this.setSelectedEvent(null);
|
|
1437
|
+
} else if (orgRemoved && shouldClearEvents) {
|
|
1438
|
+
this.events = [];
|
|
1439
|
+
this.setSelectedEvent(null);
|
|
1384
1440
|
}
|
|
1385
|
-
this.notify();
|
|
1386
1441
|
}
|
|
1387
1442
|
// Event state getters
|
|
1388
1443
|
getEvents() {
|
|
@@ -1524,6 +1579,122 @@ var _EventService = class _EventService extends BaseService {
|
|
|
1524
1579
|
}
|
|
1525
1580
|
doCleanup() {
|
|
1526
1581
|
}
|
|
1582
|
+
async resolveOrganisationIdForRpc() {
|
|
1583
|
+
let userIsSuperAdmin = this.isSuperAdmin;
|
|
1584
|
+
try {
|
|
1585
|
+
const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
|
|
1586
|
+
if (!isRBACInitialized2() && this.supabaseClient) {
|
|
1587
|
+
setupRBAC2(this.supabaseClient);
|
|
1588
|
+
}
|
|
1589
|
+
if (isRBACInitialized2()) {
|
|
1590
|
+
const result = await checkSuperAdmin(this.user.id);
|
|
1591
|
+
userIsSuperAdmin = result.ok && result.data;
|
|
1592
|
+
this.isSuperAdmin = userIsSuperAdmin;
|
|
1593
|
+
} else {
|
|
1594
|
+
if (this.isSuperAdmin) {
|
|
1595
|
+
userIsSuperAdmin = true;
|
|
1596
|
+
logger.warn("EventService", "RBAC not initialized, using cached super admin status", {
|
|
1597
|
+
userId: this.user.id,
|
|
1598
|
+
cachedIsSuperAdmin: this.isSuperAdmin,
|
|
1599
|
+
note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
|
|
1600
|
+
});
|
|
1601
|
+
} else {
|
|
1602
|
+
logger.warn("EventService", "RBAC not initialized, using cached non-super-admin status", {
|
|
1603
|
+
userId: this.user.id,
|
|
1604
|
+
cachedIsSuperAdmin: this.isSuperAdmin,
|
|
1605
|
+
note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
if (userIsSuperAdmin) {
|
|
1610
|
+
return null;
|
|
1611
|
+
}
|
|
1612
|
+
if (this.selectedEvent) {
|
|
1613
|
+
return this.selectedEvent.organisation_id;
|
|
1614
|
+
}
|
|
1615
|
+
if (this.selectedOrganisation) {
|
|
1616
|
+
return this.selectedOrganisation.id;
|
|
1617
|
+
}
|
|
1618
|
+
return null;
|
|
1619
|
+
} catch (superAdminCheckError) {
|
|
1620
|
+
if (this.isSuperAdmin) {
|
|
1621
|
+
logger.warn("EventService", "Super admin check failed, using cached super admin status", {
|
|
1622
|
+
error: superAdminCheckError,
|
|
1623
|
+
cachedIsSuperAdmin: this.isSuperAdmin
|
|
1624
|
+
});
|
|
1625
|
+
return null;
|
|
1626
|
+
}
|
|
1627
|
+
logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
|
|
1628
|
+
error: superAdminCheckError,
|
|
1629
|
+
cachedIsSuperAdmin: this.isSuperAdmin
|
|
1630
|
+
});
|
|
1631
|
+
if (this.selectedEvent) {
|
|
1632
|
+
return this.selectedEvent.organisation_id;
|
|
1633
|
+
}
|
|
1634
|
+
if (this.selectedOrganisation) {
|
|
1635
|
+
return this.selectedOrganisation.id;
|
|
1636
|
+
}
|
|
1637
|
+
return null;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
transformRpcDataToEvents(data) {
|
|
1641
|
+
const eventsData = Array.isArray(data) ? data : [];
|
|
1642
|
+
const transformed = eventsData.map((event) => ({
|
|
1643
|
+
id: event.event_id,
|
|
1644
|
+
event_id: event.event_id,
|
|
1645
|
+
event_name: event.event_name,
|
|
1646
|
+
event_code: event.event_code,
|
|
1647
|
+
event_date: event.event_date ?? void 0,
|
|
1648
|
+
event_venue: event.event_venue ?? void 0,
|
|
1649
|
+
event_participants: event.event_participants ?? void 0,
|
|
1650
|
+
event_colours: event.event_colours,
|
|
1651
|
+
event_logo: "",
|
|
1652
|
+
organisation_id: assertOrganisationId(event.organisation_id),
|
|
1653
|
+
is_visible: event.is_visible,
|
|
1654
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1655
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1656
|
+
}));
|
|
1657
|
+
return [...transformed].sort((a, b) => {
|
|
1658
|
+
if (a.event_date && b.event_date) {
|
|
1659
|
+
return new Date(b.event_date).getTime() - new Date(a.event_date).getTime();
|
|
1660
|
+
}
|
|
1661
|
+
if (a.event_date && !b.event_date) return -1;
|
|
1662
|
+
if (!a.event_date && b.event_date) return 1;
|
|
1663
|
+
return 0;
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
validateSelectedEventInList(events) {
|
|
1667
|
+
if (!this.selectedEvent) {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
const selectedEventId = this.selectedEvent.event_id;
|
|
1671
|
+
const eventStillExists = events.some((e) => e.event_id === selectedEventId);
|
|
1672
|
+
if (!eventStillExists) {
|
|
1673
|
+
const previousUserClearedRef = this.userClearedEventRef;
|
|
1674
|
+
this.selectedEvent = null;
|
|
1675
|
+
this.setSelectedEventId?.(null);
|
|
1676
|
+
this.userClearedEventRef = previousUserClearedRef;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
async runPersistedOrAutoSelection(events, skipLoadPersisted) {
|
|
1680
|
+
this.hasAutoSelectedRef = false;
|
|
1681
|
+
if (!skipLoadPersisted) {
|
|
1682
|
+
const persistedEventLoaded = await this.loadPersistedEvent(events);
|
|
1683
|
+
if (!persistedEventLoaded && !this.userClearedEventRef) {
|
|
1684
|
+
const nextEvent = this.getNextEventByDate(events);
|
|
1685
|
+
if (nextEvent) {
|
|
1686
|
+
this.hasAutoSelectedRef = true;
|
|
1687
|
+
this.setSelectedEvent(nextEvent);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
} else if (!this.userClearedEventRef) {
|
|
1691
|
+
const nextEvent = this.getNextEventByDate(events);
|
|
1692
|
+
if (nextEvent) {
|
|
1693
|
+
this.hasAutoSelectedRef = true;
|
|
1694
|
+
this.setSelectedEvent(nextEvent);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1527
1698
|
async fetchEvents(skipLoadPersisted = false) {
|
|
1528
1699
|
if (!this.user || !this.session || !this.supabaseClient || !this.appName) {
|
|
1529
1700
|
this.notify();
|
|
@@ -1537,65 +1708,7 @@ var _EventService = class _EventService extends BaseService {
|
|
|
1537
1708
|
this.isFetchingRef = true;
|
|
1538
1709
|
const isMounted = true;
|
|
1539
1710
|
try {
|
|
1540
|
-
|
|
1541
|
-
let userIsSuperAdmin = this.isSuperAdmin;
|
|
1542
|
-
try {
|
|
1543
|
-
const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-F47QJ7FX.js');
|
|
1544
|
-
if (!isRBACInitialized2() && this.supabaseClient) {
|
|
1545
|
-
setupRBAC2(this.supabaseClient);
|
|
1546
|
-
}
|
|
1547
|
-
if (isRBACInitialized2()) {
|
|
1548
|
-
userIsSuperAdmin = await checkSuperAdmin(this.user.id);
|
|
1549
|
-
this.isSuperAdmin = userIsSuperAdmin;
|
|
1550
|
-
} else {
|
|
1551
|
-
if (this.isSuperAdmin) {
|
|
1552
|
-
userIsSuperAdmin = true;
|
|
1553
|
-
logger.warn("EventService", "RBAC not initialized, using cached super admin status", {
|
|
1554
|
-
userId: this.user.id,
|
|
1555
|
-
cachedIsSuperAdmin: this.isSuperAdmin,
|
|
1556
|
-
note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
|
|
1557
|
-
});
|
|
1558
|
-
} else {
|
|
1559
|
-
logger.warn("EventService", "RBAC not initialized, using cached non-super-admin status", {
|
|
1560
|
-
userId: this.user.id,
|
|
1561
|
-
cachedIsSuperAdmin: this.isSuperAdmin,
|
|
1562
|
-
note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
|
|
1563
|
-
});
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
if (userIsSuperAdmin) {
|
|
1567
|
-
organisationIdForRpc = null;
|
|
1568
|
-
} else {
|
|
1569
|
-
if (this.selectedEvent) {
|
|
1570
|
-
organisationIdForRpc = this.selectedEvent.organisation_id;
|
|
1571
|
-
} else if (this.selectedOrganisation) {
|
|
1572
|
-
organisationIdForRpc = this.selectedOrganisation.id;
|
|
1573
|
-
} else {
|
|
1574
|
-
organisationIdForRpc = null;
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
} catch (superAdminCheckError) {
|
|
1578
|
-
if (this.isSuperAdmin) {
|
|
1579
|
-
userIsSuperAdmin = true;
|
|
1580
|
-
organisationIdForRpc = null;
|
|
1581
|
-
logger.warn("EventService", "Super admin check failed, using cached super admin status", {
|
|
1582
|
-
error: superAdminCheckError,
|
|
1583
|
-
cachedIsSuperAdmin: this.isSuperAdmin
|
|
1584
|
-
});
|
|
1585
|
-
} else {
|
|
1586
|
-
logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
|
|
1587
|
-
error: superAdminCheckError,
|
|
1588
|
-
cachedIsSuperAdmin: this.isSuperAdmin
|
|
1589
|
-
});
|
|
1590
|
-
if (this.selectedEvent) {
|
|
1591
|
-
organisationIdForRpc = this.selectedEvent.organisation_id;
|
|
1592
|
-
} else if (this.selectedOrganisation) {
|
|
1593
|
-
organisationIdForRpc = this.selectedOrganisation.id;
|
|
1594
|
-
} else {
|
|
1595
|
-
organisationIdForRpc = null;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1711
|
+
const organisationIdForRpc = await this.resolveOrganisationIdForRpc();
|
|
1599
1712
|
const { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
|
|
1600
1713
|
p_user_id: this.user.id,
|
|
1601
1714
|
p_organisation_id: organisationIdForRpc,
|
|
@@ -1606,71 +1719,15 @@ var _EventService = class _EventService extends BaseService {
|
|
|
1606
1719
|
throw new Error(rpcError.message || "Failed to fetch events");
|
|
1607
1720
|
}
|
|
1608
1721
|
if (isMounted) {
|
|
1609
|
-
const
|
|
1610
|
-
|
|
1611
|
-
id: event.event_id,
|
|
1612
|
-
event_id: event.event_id,
|
|
1613
|
-
event_name: event.event_name,
|
|
1614
|
-
event_code: event.event_code,
|
|
1615
|
-
event_date: event.event_date,
|
|
1616
|
-
event_venue: event.event_venue,
|
|
1617
|
-
event_participants: event.event_participants,
|
|
1618
|
-
event_colours: event.event_colours,
|
|
1619
|
-
event_logo: "",
|
|
1620
|
-
// No logo field in event table
|
|
1621
|
-
organisation_id: assertOrganisationId(event.organisation_id),
|
|
1622
|
-
is_visible: event.is_visible,
|
|
1623
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1624
|
-
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1625
|
-
}));
|
|
1626
|
-
const sortedEvents = [...transformedEvents].sort((a, b) => {
|
|
1627
|
-
if (a.event_date && b.event_date) {
|
|
1628
|
-
return new Date(b.event_date).getTime() - new Date(a.event_date).getTime();
|
|
1629
|
-
}
|
|
1630
|
-
if (a.event_date && !b.event_date) return -1;
|
|
1631
|
-
if (!a.event_date && b.event_date) return 1;
|
|
1632
|
-
return 0;
|
|
1633
|
-
});
|
|
1634
|
-
this.events = sortedEvents;
|
|
1722
|
+
const transformedEvents = this.transformRpcDataToEvents(data ?? []);
|
|
1723
|
+
this.events = transformedEvents;
|
|
1635
1724
|
this.error = null;
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
const eventStillExists = transformedEvents.some(
|
|
1639
|
-
(e) => e.event_id === selectedEventId
|
|
1640
|
-
);
|
|
1641
|
-
if (!eventStillExists) {
|
|
1642
|
-
const previousUserClearedRef = this.userClearedEventRef;
|
|
1643
|
-
this.selectedEvent = null;
|
|
1644
|
-
this.setSelectedEventId?.(null);
|
|
1645
|
-
this.userClearedEventRef = previousUserClearedRef;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
this.hasAutoSelectedRef = false;
|
|
1649
|
-
if (!skipLoadPersisted) {
|
|
1650
|
-
const persistedEventLoaded = await this.loadPersistedEvent(transformedEvents);
|
|
1651
|
-
if (!persistedEventLoaded && !this.userClearedEventRef) {
|
|
1652
|
-
const nextEvent = this.getNextEventByDate(transformedEvents);
|
|
1653
|
-
if (nextEvent) {
|
|
1654
|
-
this.hasAutoSelectedRef = true;
|
|
1655
|
-
this.setSelectedEvent(nextEvent);
|
|
1656
|
-
}
|
|
1657
|
-
} else if (persistedEventLoaded) {
|
|
1658
|
-
} else if (this.userClearedEventRef) {
|
|
1659
|
-
}
|
|
1660
|
-
} else {
|
|
1661
|
-
if (!this.userClearedEventRef) {
|
|
1662
|
-
const nextEvent = this.getNextEventByDate(transformedEvents);
|
|
1663
|
-
if (nextEvent) {
|
|
1664
|
-
this.hasAutoSelectedRef = true;
|
|
1665
|
-
this.setSelectedEvent(nextEvent);
|
|
1666
|
-
}
|
|
1667
|
-
} else {
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1725
|
+
this.validateSelectedEventInList(transformedEvents);
|
|
1726
|
+
await this.runPersistedOrAutoSelection(transformedEvents, skipLoadPersisted);
|
|
1670
1727
|
}
|
|
1671
|
-
} catch (
|
|
1672
|
-
logger.error("EventService", "Error fetching events:",
|
|
1673
|
-
const _error =
|
|
1728
|
+
} catch (err2) {
|
|
1729
|
+
logger.error("EventService", "Error fetching events:", err2);
|
|
1730
|
+
const _error = err2 instanceof Error ? err2 : new Error("Unknown error occurred");
|
|
1674
1731
|
{
|
|
1675
1732
|
this.error = _error;
|
|
1676
1733
|
this.events = [];
|
|
@@ -1782,6 +1839,7 @@ function EventServiceProvider({
|
|
|
1782
1839
|
}), [eventService]);
|
|
1783
1840
|
return /* @__PURE__ */ jsx(EventServiceContext.Provider, { value: contextValue, children });
|
|
1784
1841
|
}
|
|
1842
|
+
var InactivityServiceContext = createContext(null);
|
|
1785
1843
|
|
|
1786
1844
|
// src/services/InactivityService.ts
|
|
1787
1845
|
var InactivityService = class extends BaseService {
|
|
@@ -2005,163 +2063,157 @@ var InactivityService = class extends BaseService {
|
|
|
2005
2063
|
}
|
|
2006
2064
|
this.setupEventHandlers();
|
|
2007
2065
|
}
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
|
|
2032
|
-
const newShowWarning = timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs && !newIsIdle;
|
|
2033
|
-
const newShowInactivityWarning = newShowWarning;
|
|
2034
|
-
const newInactivityTimeRemaining = newShowWarning ? Math.ceil(timeUntilIdle / 1e3) : 0;
|
|
2035
|
-
const newTimeRemaining = Math.max(0, timeUntilIdle);
|
|
2036
|
-
const stateChanged = prevIsIdle !== newIsIdle || prevShowWarning !== newShowWarning || prevShowInactivityWarning !== newShowInactivityWarning || newShowWarning && prevInactivityTimeRemaining !== newInactivityTimeRemaining || prevTimeRemaining !== newTimeRemaining;
|
|
2037
|
-
if (stateChanged || forceNotify) {
|
|
2038
|
-
this._isIdle = newIsIdle;
|
|
2039
|
-
this._showWarning = newShowWarning;
|
|
2040
|
-
this._showInactivityWarning = newShowInactivityWarning;
|
|
2041
|
-
this._inactivityTimeRemaining = newInactivityTimeRemaining;
|
|
2042
|
-
this._timeRemaining = newTimeRemaining;
|
|
2043
|
-
prevIsIdle = newIsIdle;
|
|
2044
|
-
prevShowWarning = newShowWarning;
|
|
2045
|
-
prevShowInactivityWarning = newShowInactivityWarning;
|
|
2046
|
-
prevInactivityTimeRemaining = newInactivityTimeRemaining;
|
|
2047
|
-
prevTimeRemaining = newTimeRemaining;
|
|
2048
|
-
if (stateChanged) {
|
|
2049
|
-
this.notify();
|
|
2050
|
-
}
|
|
2051
|
-
if (newIsIdle) {
|
|
2052
|
-
this.handleIdleLogout();
|
|
2053
|
-
}
|
|
2066
|
+
runUpdateState(ctx, forceNotify = false) {
|
|
2067
|
+
const now = Date.now();
|
|
2068
|
+
const timeSinceActivity = now - ctx.lastActivity;
|
|
2069
|
+
const timeUntilIdle = this.idleTimeoutMs - timeSinceActivity;
|
|
2070
|
+
const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
|
|
2071
|
+
const newShowWarning = timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs && !newIsIdle;
|
|
2072
|
+
const newShowInactivityWarning = newShowWarning;
|
|
2073
|
+
const newInactivityTimeRemaining = newShowWarning ? Math.ceil(timeUntilIdle / 1e3) : 0;
|
|
2074
|
+
const newTimeRemaining = Math.max(0, timeUntilIdle);
|
|
2075
|
+
const stateChanged = ctx.prevIsIdle !== newIsIdle || ctx.prevShowWarning !== newShowWarning || ctx.prevShowInactivityWarning !== newShowInactivityWarning || newShowWarning && ctx.prevInactivityTimeRemaining !== newInactivityTimeRemaining || ctx.prevTimeRemaining !== newTimeRemaining;
|
|
2076
|
+
if (stateChanged || forceNotify) {
|
|
2077
|
+
this._isIdle = newIsIdle;
|
|
2078
|
+
this._showWarning = newShowWarning;
|
|
2079
|
+
this._showInactivityWarning = newShowInactivityWarning;
|
|
2080
|
+
this._inactivityTimeRemaining = newInactivityTimeRemaining;
|
|
2081
|
+
this._timeRemaining = newTimeRemaining;
|
|
2082
|
+
ctx.prevIsIdle = newIsIdle;
|
|
2083
|
+
ctx.prevShowWarning = newShowWarning;
|
|
2084
|
+
ctx.prevShowInactivityWarning = newShowInactivityWarning;
|
|
2085
|
+
ctx.prevInactivityTimeRemaining = newInactivityTimeRemaining;
|
|
2086
|
+
ctx.prevTimeRemaining = newTimeRemaining;
|
|
2087
|
+
if (stateChanged) {
|
|
2088
|
+
this.notify();
|
|
2054
2089
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
clearInterval(countdownInterval);
|
|
2090
|
-
countdownInterval = null;
|
|
2090
|
+
if (newIsIdle) {
|
|
2091
|
+
this.handleIdleLogout();
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
runScheduleNextCheck(ctx) {
|
|
2096
|
+
if (ctx.warningTimer) {
|
|
2097
|
+
clearTimeout(ctx.warningTimer);
|
|
2098
|
+
ctx.warningTimer = null;
|
|
2099
|
+
}
|
|
2100
|
+
if (ctx.logoutTimer) {
|
|
2101
|
+
clearTimeout(ctx.logoutTimer);
|
|
2102
|
+
ctx.logoutTimer = null;
|
|
2103
|
+
}
|
|
2104
|
+
if (ctx.countdownInterval) {
|
|
2105
|
+
clearInterval(ctx.countdownInterval);
|
|
2106
|
+
ctx.countdownInterval = null;
|
|
2107
|
+
}
|
|
2108
|
+
const getTimeUntilWarning = () => Math.max(0, this.idleTimeoutMs - this.warnBeforeMs - (Date.now() - ctx.lastActivity));
|
|
2109
|
+
const getTimeUntilLogout = () => Math.max(0, this.idleTimeoutMs - (Date.now() - ctx.lastActivity));
|
|
2110
|
+
const timeUntilWarning = getTimeUntilWarning();
|
|
2111
|
+
const timeUntilLogout = getTimeUntilLogout();
|
|
2112
|
+
const timeSinceActivity = Date.now() - ctx.lastActivity;
|
|
2113
|
+
if (timeSinceActivity >= this.idleTimeoutMs) {
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
2116
|
+
if (timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs) {
|
|
2117
|
+
this.runUpdateState(ctx);
|
|
2118
|
+
ctx.countdownInterval = setInterval(() => {
|
|
2119
|
+
this.runUpdateState(ctx);
|
|
2120
|
+
if (Date.now() - ctx.lastActivity >= this.idleTimeoutMs) {
|
|
2121
|
+
if (ctx.countdownInterval) {
|
|
2122
|
+
clearInterval(ctx.countdownInterval);
|
|
2123
|
+
ctx.countdownInterval = null;
|
|
2091
2124
|
}
|
|
2092
2125
|
this.handleIdleLogout();
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2126
|
+
}
|
|
2127
|
+
}, 1e3);
|
|
2128
|
+
ctx.logoutTimer = setTimeout(() => {
|
|
2129
|
+
if (ctx.countdownInterval) {
|
|
2130
|
+
clearInterval(ctx.countdownInterval);
|
|
2131
|
+
ctx.countdownInterval = null;
|
|
2132
|
+
}
|
|
2133
|
+
this.handleIdleLogout();
|
|
2134
|
+
}, timeUntilLogout);
|
|
2135
|
+
} else {
|
|
2136
|
+
const timeUntilWarningMs = timeUntilWarning;
|
|
2137
|
+
const adaptiveInterval = timeUntilWarningMs > 5 * 60 * 1e3 ? 60 * 1e3 : timeUntilWarningMs > 60 * 1e3 ? 10 * 1e3 : 1e3;
|
|
2138
|
+
ctx.warningTimer = setTimeout(() => {
|
|
2139
|
+
this.runUpdateState(ctx);
|
|
2140
|
+
this.runScheduleNextCheck(ctx);
|
|
2141
|
+
}, Math.min(adaptiveInterval, timeUntilWarningMs));
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
runResetTimers(ctx) {
|
|
2145
|
+
ctx.lastActivity = Date.now();
|
|
2146
|
+
if (ctx.warningTimer) {
|
|
2147
|
+
clearTimeout(ctx.warningTimer);
|
|
2148
|
+
ctx.warningTimer = null;
|
|
2149
|
+
}
|
|
2150
|
+
if (ctx.logoutTimer) {
|
|
2151
|
+
clearTimeout(ctx.logoutTimer);
|
|
2152
|
+
ctx.logoutTimer = null;
|
|
2153
|
+
}
|
|
2154
|
+
if (ctx.countdownInterval) {
|
|
2155
|
+
clearInterval(ctx.countdownInterval);
|
|
2156
|
+
ctx.countdownInterval = null;
|
|
2157
|
+
}
|
|
2158
|
+
const hadWarning = this._showWarning || this._showInactivityWarning;
|
|
2159
|
+
this._showInactivityWarning = false;
|
|
2160
|
+
this._inactivityTimeRemaining = 0;
|
|
2161
|
+
this._isIdle = false;
|
|
2162
|
+
this._showWarning = false;
|
|
2163
|
+
this._timeRemaining = this.idleTimeoutMs;
|
|
2164
|
+
ctx.prevIsIdle = false;
|
|
2165
|
+
ctx.prevShowWarning = false;
|
|
2166
|
+
ctx.prevShowInactivityWarning = false;
|
|
2167
|
+
ctx.prevInactivityTimeRemaining = 0;
|
|
2168
|
+
ctx.prevTimeRemaining = this.idleTimeoutMs;
|
|
2169
|
+
if (hadWarning) {
|
|
2170
|
+
this.notify();
|
|
2171
|
+
}
|
|
2172
|
+
this.runScheduleNextCheck(ctx);
|
|
2173
|
+
}
|
|
2174
|
+
setupEventHandlers() {
|
|
2175
|
+
if (typeof window === "undefined") return;
|
|
2176
|
+
const ctx = {
|
|
2177
|
+
warningTimer: null,
|
|
2178
|
+
logoutTimer: null,
|
|
2179
|
+
countdownInterval: null,
|
|
2180
|
+
activityThrottleTimer: null,
|
|
2181
|
+
lastActivity: Date.now(),
|
|
2182
|
+
prevIsIdle: false,
|
|
2183
|
+
prevShowWarning: false,
|
|
2184
|
+
prevShowInactivityWarning: false,
|
|
2185
|
+
prevInactivityTimeRemaining: 0,
|
|
2186
|
+
prevTimeRemaining: this.idleTimeoutMs
|
|
2132
2187
|
};
|
|
2133
2188
|
const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];
|
|
2134
|
-
let activityThrottleTimer = null;
|
|
2135
2189
|
const handleActivity = () => {
|
|
2136
|
-
if (activityThrottleTimer)
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
activityThrottleTimer = null;
|
|
2141
|
-
resetTimers();
|
|
2190
|
+
if (ctx.activityThrottleTimer) return;
|
|
2191
|
+
ctx.activityThrottleTimer = setTimeout(() => {
|
|
2192
|
+
ctx.activityThrottleTimer = null;
|
|
2193
|
+
this.runResetTimers(ctx);
|
|
2142
2194
|
}, 1e3);
|
|
2143
2195
|
};
|
|
2144
2196
|
activityEvents.forEach((event) => {
|
|
2145
2197
|
document.addEventListener(event, handleActivity, true);
|
|
2146
2198
|
});
|
|
2147
|
-
|
|
2148
|
-
|
|
2199
|
+
this.runUpdateState(ctx, true);
|
|
2200
|
+
this.runScheduleNextCheck(ctx);
|
|
2149
2201
|
this.cleanupHandlers = () => {
|
|
2150
|
-
if (warningTimer) {
|
|
2151
|
-
clearTimeout(warningTimer);
|
|
2152
|
-
warningTimer = null;
|
|
2202
|
+
if (ctx.warningTimer) {
|
|
2203
|
+
clearTimeout(ctx.warningTimer);
|
|
2204
|
+
ctx.warningTimer = null;
|
|
2153
2205
|
}
|
|
2154
|
-
if (logoutTimer) {
|
|
2155
|
-
clearTimeout(logoutTimer);
|
|
2156
|
-
logoutTimer = null;
|
|
2206
|
+
if (ctx.logoutTimer) {
|
|
2207
|
+
clearTimeout(ctx.logoutTimer);
|
|
2208
|
+
ctx.logoutTimer = null;
|
|
2157
2209
|
}
|
|
2158
|
-
if (countdownInterval) {
|
|
2159
|
-
clearInterval(countdownInterval);
|
|
2160
|
-
countdownInterval = null;
|
|
2210
|
+
if (ctx.countdownInterval) {
|
|
2211
|
+
clearInterval(ctx.countdownInterval);
|
|
2212
|
+
ctx.countdownInterval = null;
|
|
2161
2213
|
}
|
|
2162
|
-
if (activityThrottleTimer) {
|
|
2163
|
-
clearTimeout(activityThrottleTimer);
|
|
2164
|
-
activityThrottleTimer = null;
|
|
2214
|
+
if (ctx.activityThrottleTimer) {
|
|
2215
|
+
clearTimeout(ctx.activityThrottleTimer);
|
|
2216
|
+
ctx.activityThrottleTimer = null;
|
|
2165
2217
|
}
|
|
2166
2218
|
activityEvents.forEach((event) => {
|
|
2167
2219
|
document.removeEventListener(event, handleActivity, true);
|
|
@@ -2176,7 +2228,6 @@ var InactivityService = class extends BaseService {
|
|
|
2176
2228
|
this._isTracking = true;
|
|
2177
2229
|
}
|
|
2178
2230
|
};
|
|
2179
|
-
var InactivityServiceContext = createContext(null);
|
|
2180
2231
|
function InactivityServiceProvider({
|
|
2181
2232
|
children,
|
|
2182
2233
|
supabaseClient,
|
|
@@ -2391,33 +2442,7 @@ function useUnifiedAuth() {
|
|
|
2391
2442
|
}
|
|
2392
2443
|
return context;
|
|
2393
2444
|
}
|
|
2394
|
-
function
|
|
2395
|
-
children,
|
|
2396
|
-
appName,
|
|
2397
|
-
supabaseClient: supabaseClientProp,
|
|
2398
|
-
..._props
|
|
2399
|
-
}) {
|
|
2400
|
-
const authService = useAuthService();
|
|
2401
|
-
const organisationService = useOrganisationService();
|
|
2402
|
-
const inactivityService = useInactivityService();
|
|
2403
|
-
const sessionRestorationState = useSessionRestoration();
|
|
2404
|
-
const {
|
|
2405
|
-
hasTimedOut: sessionRestorationTimedOut,
|
|
2406
|
-
timeoutMs: sessionRestorationTimeoutMs,
|
|
2407
|
-
isRestoring,
|
|
2408
|
-
restorationComplete,
|
|
2409
|
-
restorationError
|
|
2410
|
-
} = sessionRestorationState;
|
|
2411
|
-
const sessionRestoration = useMemo(() => ({
|
|
2412
|
-
isRestoring,
|
|
2413
|
-
restorationComplete,
|
|
2414
|
-
restorationError
|
|
2415
|
-
}), [isRestoring, restorationComplete, restorationError]);
|
|
2416
|
-
const eventService = useEventService();
|
|
2417
|
-
const currentUser = authService.getUser();
|
|
2418
|
-
const currentSession = authService.getSession();
|
|
2419
|
-
const isAuth = !!(currentUser && currentSession);
|
|
2420
|
-
const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
|
|
2445
|
+
function useAppIdResolution(supabase, appName, isAuth, currentUserId) {
|
|
2421
2446
|
const [appId, setAppId] = useState(void 0);
|
|
2422
2447
|
const isResolvingAppIdRef = useRef(false);
|
|
2423
2448
|
const resolvedAppIdRef = useRef(void 0);
|
|
@@ -2429,54 +2454,51 @@ function UnifiedAuthContextProvider({
|
|
|
2429
2454
|
setAppId(void 0);
|
|
2430
2455
|
return;
|
|
2431
2456
|
}
|
|
2432
|
-
if (
|
|
2457
|
+
if (currentUserId && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUserId) {
|
|
2433
2458
|
resolvedAppIdRef.current = void 0;
|
|
2434
2459
|
resolvedUserIdRef.current = void 0;
|
|
2435
2460
|
setAppId(void 0);
|
|
2436
2461
|
}
|
|
2437
|
-
const
|
|
2438
|
-
if (
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
resolvedAppIdRef.current = result.appId;
|
|
2453
|
-
setAppId(result.appId);
|
|
2454
|
-
} else {
|
|
2455
|
-
resolvedUserIdRef.current = void 0;
|
|
2456
|
-
}
|
|
2457
|
-
} catch (error) {
|
|
2458
|
-
logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
|
|
2459
|
-
error: error instanceof Error ? error.message : String(error),
|
|
2460
|
-
appName: appNameValue,
|
|
2461
|
-
userId
|
|
2462
|
-
});
|
|
2462
|
+
const shouldResolve = isAuth && currentUserId && supabase && appName && resolvedUserIdRef.current !== currentUserId && !isResolvingAppIdRef.current;
|
|
2463
|
+
if (!shouldResolve) return;
|
|
2464
|
+
isResolvingAppIdRef.current = true;
|
|
2465
|
+
resolvedUserIdRef.current = currentUserId;
|
|
2466
|
+
const userId = currentUserId;
|
|
2467
|
+
const appNameValue = appName;
|
|
2468
|
+
import('./api-BZR2CYXL.js').then(async ({ resolveAppContext, setupRBAC: setupRBAC2 }) => {
|
|
2469
|
+
try {
|
|
2470
|
+
setupRBAC2(supabase);
|
|
2471
|
+
const result = await resolveAppContext({ userId, appName: appNameValue });
|
|
2472
|
+
if (result.ok && result.data?.appId) {
|
|
2473
|
+
const appIdValue = result.data.appId;
|
|
2474
|
+
resolvedAppIdRef.current = appIdValue;
|
|
2475
|
+
setAppId(appIdValue);
|
|
2476
|
+
} else {
|
|
2463
2477
|
resolvedUserIdRef.current = void 0;
|
|
2464
|
-
} finally {
|
|
2465
|
-
isResolvingAppIdRef.current = false;
|
|
2466
2478
|
}
|
|
2467
|
-
}
|
|
2468
|
-
logger.error("UnifiedAuthProvider", "Failed to
|
|
2469
|
-
|
|
2479
|
+
} catch (error) {
|
|
2480
|
+
logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
|
|
2481
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2482
|
+
appName: appNameValue,
|
|
2483
|
+
userId
|
|
2484
|
+
});
|
|
2470
2485
|
resolvedUserIdRef.current = void 0;
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2486
|
+
} finally {
|
|
2487
|
+
isResolvingAppIdRef.current = false;
|
|
2488
|
+
}
|
|
2489
|
+
}).catch((importError) => {
|
|
2490
|
+
logger.error("UnifiedAuthProvider", "Failed to import RBAC API", importError);
|
|
2491
|
+
isResolvingAppIdRef.current = false;
|
|
2492
|
+
resolvedUserIdRef.current = void 0;
|
|
2493
|
+
});
|
|
2494
|
+
}, [isAuth, currentUserId, supabase, appName]);
|
|
2495
|
+
return appId;
|
|
2496
|
+
}
|
|
2497
|
+
function useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService) {
|
|
2474
2498
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
2475
2499
|
const forceUpdateTimeoutRef = useRef(null);
|
|
2476
2500
|
const debouncedForceUpdate = useCallback(() => {
|
|
2477
|
-
if (forceUpdateTimeoutRef.current)
|
|
2478
|
-
clearTimeout(forceUpdateTimeoutRef.current);
|
|
2479
|
-
}
|
|
2501
|
+
if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
|
|
2480
2502
|
forceUpdateTimeoutRef.current = setTimeout(() => {
|
|
2481
2503
|
forceUpdate();
|
|
2482
2504
|
forceUpdateTimeoutRef.current = null;
|
|
@@ -2493,20 +2515,86 @@ function UnifiedAuthContextProvider({
|
|
|
2493
2515
|
inactivityServiceRef.current = inactivityService;
|
|
2494
2516
|
}, [authService, organisationService, eventService, inactivityService]);
|
|
2495
2517
|
useEffect(() => {
|
|
2496
|
-
const
|
|
2497
|
-
const
|
|
2498
|
-
const
|
|
2499
|
-
const
|
|
2518
|
+
const unsubAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
|
|
2519
|
+
const unsubOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
|
|
2520
|
+
const unsubEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
|
|
2521
|
+
const unsubInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
|
|
2500
2522
|
return () => {
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
if (forceUpdateTimeoutRef.current)
|
|
2506
|
-
clearTimeout(forceUpdateTimeoutRef.current);
|
|
2507
|
-
}
|
|
2523
|
+
unsubAuth();
|
|
2524
|
+
unsubOrg();
|
|
2525
|
+
unsubEvent();
|
|
2526
|
+
unsubInactivity();
|
|
2527
|
+
if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
|
|
2508
2528
|
};
|
|
2509
2529
|
}, [debouncedForceUpdate]);
|
|
2530
|
+
}
|
|
2531
|
+
function useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase) {
|
|
2532
|
+
return useMemo(
|
|
2533
|
+
() => {
|
|
2534
|
+
const selectedOrganisationId = state.selectedOrganisation?.id ?? state.selectedEvent?.organisation_id ?? null;
|
|
2535
|
+
return {
|
|
2536
|
+
user: state.currentUser,
|
|
2537
|
+
session: state.currentSession,
|
|
2538
|
+
isAuthenticated: state.isAuth,
|
|
2539
|
+
authLoading: state.authLoading,
|
|
2540
|
+
authError: state.authError,
|
|
2541
|
+
supabase,
|
|
2542
|
+
signIn: callbacks.signIn,
|
|
2543
|
+
signUp: callbacks.signUp,
|
|
2544
|
+
signOut: callbacks.signOut,
|
|
2545
|
+
resetPassword: callbacks.resetPassword,
|
|
2546
|
+
updatePassword: callbacks.updatePassword,
|
|
2547
|
+
refreshSession: callbacks.refreshSession,
|
|
2548
|
+
selectedOrganisation: state.selectedOrganisation,
|
|
2549
|
+
selectedOrganisationId,
|
|
2550
|
+
organisations: state.organisations,
|
|
2551
|
+
userMemberships: state.userMemberships,
|
|
2552
|
+
organisationLoading: state.orgLoading,
|
|
2553
|
+
organisationError: state.organisationError,
|
|
2554
|
+
hasValidOrganisationContext: state.hasValidOrganisationContext,
|
|
2555
|
+
isContextReady: state.isContextReady,
|
|
2556
|
+
switchOrganisation: callbacks.switchOrganisation,
|
|
2557
|
+
getUserRole: callbacks.getUserRole,
|
|
2558
|
+
validateOrganisationAccess: callbacks.validateOrganisationAccess,
|
|
2559
|
+
refreshOrganisations: callbacks.refreshOrganisations,
|
|
2560
|
+
ensureOrganisationContext: callbacks.ensureOrganisationContext,
|
|
2561
|
+
isOrganisationSecure: callbacks.isOrganisationSecure,
|
|
2562
|
+
getPrimaryOrganisation: callbacks.getPrimaryOrganisation,
|
|
2563
|
+
events: state.events,
|
|
2564
|
+
selectedEvent: state.selectedEvent,
|
|
2565
|
+
selectedEventId: state.selectedEvent?.event_id ?? null,
|
|
2566
|
+
eventLoading: state.eventLoading,
|
|
2567
|
+
eventError: state.eventError,
|
|
2568
|
+
setSelectedEvent: callbacks.setSelectedEvent,
|
|
2569
|
+
refreshEvents: callbacks.refreshEvents,
|
|
2570
|
+
showInactivityWarning: state.inactivityState.showInactivityWarning,
|
|
2571
|
+
inactivityTimeRemaining: state.inactivityState.inactivityTimeRemaining,
|
|
2572
|
+
isIdle: state.inactivityState.isIdle,
|
|
2573
|
+
timeRemaining: state.inactivityState.timeRemaining,
|
|
2574
|
+
showWarning: state.inactivityState.showWarning,
|
|
2575
|
+
isTracking: state.inactivityState.isTracking,
|
|
2576
|
+
resetActivity: callbacks.resetActivity,
|
|
2577
|
+
startTracking: callbacks.startTracking,
|
|
2578
|
+
stopTracking: callbacks.stopTracking,
|
|
2579
|
+
handleIdleLogout: callbacks.handleIdleLogout,
|
|
2580
|
+
handleStaySignedIn: callbacks.handleStaySignedIn,
|
|
2581
|
+
handleSignOutNow: callbacks.handleSignOutNow,
|
|
2582
|
+
appName,
|
|
2583
|
+
appId,
|
|
2584
|
+
isLoading: state.totalLoading,
|
|
2585
|
+
hasErrors: state.hasErrors,
|
|
2586
|
+
sessionRestoration: state.sessionRestoration,
|
|
2587
|
+
sessionRestorationTimedOut: state.sessionRestorationTimedOut,
|
|
2588
|
+
sessionRestorationTimeoutMs: state.sessionRestorationTimeoutMs
|
|
2589
|
+
};
|
|
2590
|
+
},
|
|
2591
|
+
[state, callbacks, appId, appName, supabase]
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
function useUnifiedAuthStateAndCallbacks(authService, organisationService, eventService, inactivityService, sessionRestoration, sessionRestorationTimedOut, sessionRestorationTimeoutMs, appName, userOverride, sessionOverride) {
|
|
2595
|
+
const currentUser = userOverride !== void 0 ? userOverride : authService.getUser();
|
|
2596
|
+
const currentSession = sessionOverride !== void 0 ? sessionOverride : authService.getSession();
|
|
2597
|
+
const isAuth = !!(currentUser && currentSession);
|
|
2510
2598
|
const authLoading = authService.isLoading();
|
|
2511
2599
|
const orgLoading = organisationService.isLoading();
|
|
2512
2600
|
const eventLoading = eventService.isLoading();
|
|
@@ -2514,23 +2602,16 @@ function UnifiedAuthContextProvider({
|
|
|
2514
2602
|
const shouldIncludeOrgLoading = appName !== "ADMIN" && appName !== "PORTAL";
|
|
2515
2603
|
const totalLoading = restorationLoading || authLoading || (shouldIncludeOrgLoading ? orgLoading : false) || eventLoading;
|
|
2516
2604
|
const authError = authService.getError();
|
|
2517
|
-
const
|
|
2605
|
+
const selectedOrganisation = organisationService.getSelectedOrganisation();
|
|
2518
2606
|
const organisationError = organisationService.getError();
|
|
2519
|
-
const selectedOrganisation = rawSelectedOrganisation;
|
|
2520
2607
|
const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();
|
|
2521
2608
|
const isContextReady = organisationService.isContextReady();
|
|
2522
2609
|
const rawEvents = eventService.getEvents();
|
|
2523
2610
|
const rawOrganisations = organisationService.getOrganisations();
|
|
2524
2611
|
const rawUserMemberships = organisationService.getUserMemberships();
|
|
2525
|
-
const events = useMemo(() =>
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
const organisations = useMemo(() => {
|
|
2529
|
-
return rawOrganisations;
|
|
2530
|
-
}, [rawOrganisations]);
|
|
2531
|
-
const userMemberships = useMemo(() => {
|
|
2532
|
-
return rawUserMemberships;
|
|
2533
|
-
}, [rawUserMemberships]);
|
|
2612
|
+
const events = useMemo(() => rawEvents, [rawEvents]);
|
|
2613
|
+
const organisations = useMemo(() => rawOrganisations, [rawOrganisations]);
|
|
2614
|
+
const userMemberships = useMemo(() => rawUserMemberships, [rawUserMemberships]);
|
|
2534
2615
|
const selectedEvent = eventService.getSelectedEvent();
|
|
2535
2616
|
const eventError = eventService.getError();
|
|
2536
2617
|
const showInactivityWarning = inactivityService.getShowInactivityWarning();
|
|
@@ -2546,14 +2627,7 @@ function UnifiedAuthContextProvider({
|
|
|
2546
2627
|
timeRemaining,
|
|
2547
2628
|
showWarning,
|
|
2548
2629
|
isTracking
|
|
2549
|
-
}), [
|
|
2550
|
-
showInactivityWarning,
|
|
2551
|
-
inactivityTimeRemaining,
|
|
2552
|
-
isIdle,
|
|
2553
|
-
timeRemaining,
|
|
2554
|
-
showWarning,
|
|
2555
|
-
isTracking
|
|
2556
|
-
]);
|
|
2630
|
+
}), [showInactivityWarning, inactivityTimeRemaining, isIdle, timeRemaining, showWarning, isTracking]);
|
|
2557
2631
|
const hasErrors = !!(authError || organisationError || eventError || sessionRestoration.restorationError);
|
|
2558
2632
|
const signIn = useCallback((email, password) => authService.signIn(email, password), [authService]);
|
|
2559
2633
|
const signUp = useCallback((email, password) => authService.signUp(email, password), [authService]);
|
|
@@ -2576,94 +2650,12 @@ function UnifiedAuthContextProvider({
|
|
|
2576
2650
|
const handleIdleLogout = useCallback(() => inactivityService.handleIdleLogout(), [inactivityService]);
|
|
2577
2651
|
const handleStaySignedIn = useCallback(() => inactivityService.handleStaySignedIn(), [inactivityService]);
|
|
2578
2652
|
const handleSignOutNow = useCallback(() => inactivityService.handleSignOutNow(), [inactivityService]);
|
|
2579
|
-
const
|
|
2580
|
-
const isDev = import.meta.env.DEV || import.meta.env.MODE === "development";
|
|
2581
|
-
if (isDev) {
|
|
2582
|
-
const currentState = {
|
|
2583
|
-
isAuthenticated: isAuth,
|
|
2584
|
-
userEmail: currentUser?.email,
|
|
2585
|
-
totalLoading
|
|
2586
|
-
};
|
|
2587
|
-
const prevState = prevStateRef.current;
|
|
2588
|
-
if (!prevState || prevState.isAuthenticated !== currentState.isAuthenticated || prevState.userEmail !== currentState.userEmail || prevState.totalLoading !== currentState.totalLoading) {
|
|
2589
|
-
prevStateRef.current = currentState;
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
const contextValue = useMemo(() => {
|
|
2593
|
-
return {
|
|
2594
|
-
// Auth state
|
|
2595
|
-
user: currentUser,
|
|
2596
|
-
session: currentSession,
|
|
2597
|
-
isAuthenticated: isAuth,
|
|
2598
|
-
authLoading,
|
|
2599
|
-
authError,
|
|
2600
|
-
supabase,
|
|
2601
|
-
// Auth methods
|
|
2602
|
-
signIn,
|
|
2603
|
-
signUp,
|
|
2604
|
-
signOut,
|
|
2605
|
-
resetPassword,
|
|
2606
|
-
updatePassword,
|
|
2607
|
-
refreshSession,
|
|
2608
|
-
// Organisation state
|
|
2609
|
-
selectedOrganisation,
|
|
2610
|
-
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
2611
|
-
organisations,
|
|
2612
|
-
userMemberships,
|
|
2613
|
-
organisationLoading: orgLoading,
|
|
2614
|
-
organisationError,
|
|
2615
|
-
hasValidOrganisationContext,
|
|
2616
|
-
isContextReady,
|
|
2617
|
-
// Organisation methods
|
|
2618
|
-
switchOrganisation,
|
|
2619
|
-
getUserRole,
|
|
2620
|
-
validateOrganisationAccess,
|
|
2621
|
-
refreshOrganisations,
|
|
2622
|
-
ensureOrganisationContext,
|
|
2623
|
-
isOrganisationSecure,
|
|
2624
|
-
getPrimaryOrganisation,
|
|
2625
|
-
// Event state
|
|
2626
|
-
events,
|
|
2627
|
-
selectedEvent,
|
|
2628
|
-
selectedEventId: selectedEvent?.event_id || null,
|
|
2629
|
-
eventLoading,
|
|
2630
|
-
eventError,
|
|
2631
|
-
// Event methods
|
|
2632
|
-
setSelectedEvent,
|
|
2633
|
-
refreshEvents,
|
|
2634
|
-
// Inactivity state
|
|
2635
|
-
showInactivityWarning: inactivityState.showInactivityWarning,
|
|
2636
|
-
inactivityTimeRemaining: inactivityState.inactivityTimeRemaining,
|
|
2637
|
-
isIdle: inactivityState.isIdle,
|
|
2638
|
-
timeRemaining: inactivityState.timeRemaining,
|
|
2639
|
-
showWarning: inactivityState.showWarning,
|
|
2640
|
-
isTracking: inactivityState.isTracking,
|
|
2641
|
-
// Inactivity methods
|
|
2642
|
-
resetActivity,
|
|
2643
|
-
startTracking,
|
|
2644
|
-
stopTracking,
|
|
2645
|
-
handleIdleLogout,
|
|
2646
|
-
handleStaySignedIn,
|
|
2647
|
-
handleSignOutNow,
|
|
2648
|
-
// Additional unified properties
|
|
2649
|
-
appName,
|
|
2650
|
-
appId,
|
|
2651
|
-
// Resolved immediately on login
|
|
2652
|
-
isLoading: totalLoading,
|
|
2653
|
-
hasErrors,
|
|
2654
|
-
sessionRestoration,
|
|
2655
|
-
sessionRestorationTimedOut,
|
|
2656
|
-
sessionRestorationTimeoutMs
|
|
2657
|
-
};
|
|
2658
|
-
}, [
|
|
2659
|
-
// All primitive values extracted from services
|
|
2660
|
-
// Note: Arrays/objects from services are stable references (same reference unless data changes)
|
|
2653
|
+
const state = useMemo(() => ({
|
|
2661
2654
|
currentUser,
|
|
2662
2655
|
currentSession,
|
|
2663
2656
|
isAuth,
|
|
2664
2657
|
authLoading,
|
|
2665
2658
|
authError,
|
|
2666
|
-
supabase,
|
|
2667
2659
|
selectedOrganisation,
|
|
2668
2660
|
organisations,
|
|
2669
2661
|
userMemberships,
|
|
@@ -2676,15 +2668,58 @@ function UnifiedAuthContextProvider({
|
|
|
2676
2668
|
eventLoading,
|
|
2677
2669
|
eventError,
|
|
2678
2670
|
inactivityState,
|
|
2679
|
-
// Use memoized object instead of individual values
|
|
2680
2671
|
totalLoading,
|
|
2681
2672
|
hasErrors,
|
|
2682
|
-
appName,
|
|
2683
|
-
appId,
|
|
2684
2673
|
sessionRestoration,
|
|
2685
2674
|
sessionRestorationTimedOut,
|
|
2686
|
-
sessionRestorationTimeoutMs
|
|
2687
|
-
|
|
2675
|
+
sessionRestorationTimeoutMs
|
|
2676
|
+
}), [
|
|
2677
|
+
currentUser,
|
|
2678
|
+
currentSession,
|
|
2679
|
+
isAuth,
|
|
2680
|
+
authLoading,
|
|
2681
|
+
authError,
|
|
2682
|
+
selectedOrganisation,
|
|
2683
|
+
organisations,
|
|
2684
|
+
userMemberships,
|
|
2685
|
+
orgLoading,
|
|
2686
|
+
organisationError,
|
|
2687
|
+
hasValidOrganisationContext,
|
|
2688
|
+
isContextReady,
|
|
2689
|
+
events,
|
|
2690
|
+
selectedEvent,
|
|
2691
|
+
eventLoading,
|
|
2692
|
+
eventError,
|
|
2693
|
+
inactivityState,
|
|
2694
|
+
totalLoading,
|
|
2695
|
+
hasErrors,
|
|
2696
|
+
sessionRestoration,
|
|
2697
|
+
sessionRestorationTimedOut,
|
|
2698
|
+
sessionRestorationTimeoutMs
|
|
2699
|
+
]);
|
|
2700
|
+
const callbacks = useMemo(() => ({
|
|
2701
|
+
signIn,
|
|
2702
|
+
signUp,
|
|
2703
|
+
signOut,
|
|
2704
|
+
resetPassword,
|
|
2705
|
+
updatePassword,
|
|
2706
|
+
refreshSession,
|
|
2707
|
+
switchOrganisation,
|
|
2708
|
+
getUserRole,
|
|
2709
|
+
validateOrganisationAccess,
|
|
2710
|
+
refreshOrganisations,
|
|
2711
|
+
ensureOrganisationContext,
|
|
2712
|
+
isOrganisationSecure,
|
|
2713
|
+
getPrimaryOrganisation,
|
|
2714
|
+
setSelectedEvent,
|
|
2715
|
+
refreshEvents,
|
|
2716
|
+
resetActivity,
|
|
2717
|
+
startTracking,
|
|
2718
|
+
stopTracking,
|
|
2719
|
+
handleIdleLogout,
|
|
2720
|
+
handleStaySignedIn,
|
|
2721
|
+
handleSignOutNow
|
|
2722
|
+
}), [
|
|
2688
2723
|
signIn,
|
|
2689
2724
|
signUp,
|
|
2690
2725
|
signOut,
|
|
@@ -2707,6 +2742,48 @@ function UnifiedAuthContextProvider({
|
|
|
2707
2742
|
handleStaySignedIn,
|
|
2708
2743
|
handleSignOutNow
|
|
2709
2744
|
]);
|
|
2745
|
+
return { state, callbacks };
|
|
2746
|
+
}
|
|
2747
|
+
function UnifiedAuthContextProvider({
|
|
2748
|
+
children,
|
|
2749
|
+
appName,
|
|
2750
|
+
supabaseClient: supabaseClientProp,
|
|
2751
|
+
user: userFromParent,
|
|
2752
|
+
session: sessionFromParent
|
|
2753
|
+
}) {
|
|
2754
|
+
const authService = useAuthService();
|
|
2755
|
+
const organisationService = useOrganisationService();
|
|
2756
|
+
const inactivityService = useInactivityService();
|
|
2757
|
+
const eventService = useEventService();
|
|
2758
|
+
const sessionRestorationState = useSessionRestoration();
|
|
2759
|
+
const sessionRestoration = useMemo(() => ({
|
|
2760
|
+
isRestoring: sessionRestorationState.isRestoring,
|
|
2761
|
+
restorationComplete: sessionRestorationState.restorationComplete,
|
|
2762
|
+
restorationError: sessionRestorationState.restorationError
|
|
2763
|
+
}), [sessionRestorationState.isRestoring, sessionRestorationState.restorationComplete, sessionRestorationState.restorationError]);
|
|
2764
|
+
const { hasTimedOut: sessionRestorationTimedOut, timeoutMs: sessionRestorationTimeoutMs } = sessionRestorationState;
|
|
2765
|
+
const currentUser = userFromParent !== void 0 ? userFromParent : authService.getUser();
|
|
2766
|
+
const currentSession = sessionFromParent !== void 0 ? sessionFromParent : authService.getSession();
|
|
2767
|
+
const isAuth = !!(currentUser && currentSession);
|
|
2768
|
+
const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
|
|
2769
|
+
const appId = useAppIdResolution(supabase, appName, isAuth, currentUser?.id);
|
|
2770
|
+
useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService);
|
|
2771
|
+
const { state, callbacks } = useUnifiedAuthStateAndCallbacks(
|
|
2772
|
+
authService,
|
|
2773
|
+
organisationService,
|
|
2774
|
+
eventService,
|
|
2775
|
+
inactivityService,
|
|
2776
|
+
sessionRestoration,
|
|
2777
|
+
sessionRestorationTimedOut,
|
|
2778
|
+
sessionRestorationTimeoutMs,
|
|
2779
|
+
appName,
|
|
2780
|
+
currentUser,
|
|
2781
|
+
currentSession
|
|
2782
|
+
);
|
|
2783
|
+
const contextValue = useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase);
|
|
2784
|
+
useEffect(() => {
|
|
2785
|
+
if (appName) setPrintAppName(appName);
|
|
2786
|
+
}, [appName]);
|
|
2710
2787
|
return /* @__PURE__ */ jsx(UnifiedAuthContext.Provider, { value: contextValue, children });
|
|
2711
2788
|
}
|
|
2712
2789
|
function EventServiceProviderWrapper({
|
|
@@ -2754,8 +2831,10 @@ function ServiceAwareProviders({
|
|
|
2754
2831
|
const unsubscribe = authService.subscribe(() => {
|
|
2755
2832
|
const newUser = authService.getUser();
|
|
2756
2833
|
const newSession = authService.getSession();
|
|
2757
|
-
|
|
2758
|
-
|
|
2834
|
+
flushSync(() => {
|
|
2835
|
+
setUserState(newUser);
|
|
2836
|
+
setSessionState(newSession);
|
|
2837
|
+
});
|
|
2759
2838
|
});
|
|
2760
2839
|
return unsubscribe;
|
|
2761
2840
|
}, [authService]);
|
|
@@ -2788,6 +2867,8 @@ function ServiceAwareProviders({
|
|
|
2788
2867
|
{
|
|
2789
2868
|
appName,
|
|
2790
2869
|
supabaseClient,
|
|
2870
|
+
user,
|
|
2871
|
+
session,
|
|
2791
2872
|
persistState,
|
|
2792
2873
|
enablePersistence,
|
|
2793
2874
|
requireOrganisationContext,
|
|
@@ -2837,8 +2918,8 @@ function UnifiedAuthProvider({
|
|
|
2837
2918
|
try {
|
|
2838
2919
|
setupRBAC(supabaseClient);
|
|
2839
2920
|
logger.debug("UnifiedAuthProvider", "RBAC initialized synchronously");
|
|
2840
|
-
} catch (
|
|
2841
|
-
logger.error("UnifiedAuthProvider", "Failed to initialize RBAC",
|
|
2921
|
+
} catch (err2) {
|
|
2922
|
+
logger.error("UnifiedAuthProvider", "Failed to initialize RBAC", err2);
|
|
2842
2923
|
}
|
|
2843
2924
|
}
|
|
2844
2925
|
return /* @__PURE__ */ jsx(AuthServiceProvider, { supabaseClient, appName, children: /* @__PURE__ */ jsx(
|