@jmruthers/pace-core 0.6.2 → 0.6.4
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 +45 -0
- package/cursor-rules/00-pace-core-compliance.mdc +34 -2
- package/dist/{AuthService-BPvc3Ka0.d.ts → AuthService-Cb34EQs3.d.ts} +9 -1
- package/dist/{DataTable-TPTKCX4D.js → DataTable-E7YQZD7D.js} +9 -8
- package/dist/{PublicPageProvider-DC6kCaqf.d.ts → PublicPageProvider-DEMpysFR.d.ts} +45 -67
- package/dist/{UnifiedAuthProvider-CVcTjx-d.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +1 -8
- package/dist/{UnifiedAuthProvider-CH6Z342H.js → UnifiedAuthProvider-QPXO24B4.js} +5 -4
- package/dist/{api-MVVQZLJI.js → api-6LVZTHDS.js} +10 -10
- package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
- package/dist/chunk-36LVWXB2.js +227 -0
- package/dist/chunk-36LVWXB2.js.map +1 -0
- package/dist/{chunk-24UVZUZG.js → chunk-3LPHPB62.js} +129 -387
- package/dist/chunk-3LPHPB62.js.map +1 -0
- package/dist/{chunk-2UOI2FG5.js → chunk-5EC5MEWX.js} +4 -4
- package/dist/{chunk-3XC4CPTD.js → chunk-7JPAB3T5.js} +244 -5727
- package/dist/chunk-7JPAB3T5.js.map +1 -0
- package/dist/{chunk-6J4GEEJR.js → chunk-ATKZM7RX.js} +53 -27
- package/dist/chunk-ATKZM7RX.js.map +1 -0
- package/dist/{chunk-EHMR7VYL.js → chunk-AVMLPIM7.js} +443 -189
- package/dist/chunk-AVMLPIM7.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/{chunk-NECFR5MM.js → chunk-I6DAQMWX.js} +575 -647
- package/dist/chunk-I6DAQMWX.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-M7MPQISP.js} +2 -2
- package/dist/{chunk-XWQCNGTQ.js → chunk-NN6WWZ5U.js} +173 -79
- package/dist/chunk-NN6WWZ5U.js.map +1 -0
- package/dist/{chunk-MMZ7JXPU.js → chunk-OEWDTMG7.js} +13 -21
- package/dist/{chunk-MMZ7JXPU.js.map → chunk-OEWDTMG7.js.map} +1 -1
- package/dist/{chunk-SFZUDBL5.js → chunk-YKRAFF5K.js} +70 -56
- package/dist/chunk-YKRAFF5K.js.map +1 -0
- package/dist/components.d.ts +2 -2
- package/dist/components.js +12 -13
- package/dist/contextValidator-OOPCLPZW.js +9 -0
- package/dist/contextValidator-OOPCLPZW.js.map +1 -0
- package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +7 -6
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +21 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +4 -3
- package/dist/rbac/index.d.ts +67 -27
- package/dist/rbac/index.js +15 -8
- package/dist/styles/index.js +1 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-1oMokgLF.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +7 -16
- package/dist/utils.js +5 -7
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +14 -16
- package/docs/api/modules.md +3796 -2513
- package/docs/components/context-selector.md +126 -0
- package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
- package/docs/pace-mint-fix-auto-selection.md +218 -0
- package/docs/pace-mint-rbac-setup.md +391 -0
- package/docs/rbac/secure-client-protection.md +330 -0
- package/package.json +10 -5
- package/scripts/audit/core/checks/compliance.cjs +72 -0
- package/scripts/audit/core/checks/dependencies.cjs +568 -28
- package/scripts/audit/core/checks/documentation.cjs +68 -3
- package/scripts/audit/core/checks/environment.cjs +2 -14
- package/scripts/audit/core/checks/error-handling.cjs +47 -6
- package/src/components/ContextSelector/ContextSelector.tsx +384 -0
- package/src/components/ContextSelector/index.ts +3 -0
- package/src/components/DataTable/components/RowComponent.tsx +19 -19
- package/src/components/DataTable/components/UnifiedTableBody.tsx +2 -2
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +8 -6
- package/src/components/Dialog/Dialog.tsx +29 -1
- package/src/components/FileDisplay/FileDisplay.tsx +42 -10
- package/src/components/Header/Header.test.tsx +43 -73
- package/src/components/Header/Header.tsx +44 -45
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +9 -9
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +157 -36
- package/src/components/PaceAppLayout/README.md +14 -17
- package/src/components/PaceAppLayout/test-setup.tsx +2 -2
- package/src/components/index.ts +5 -5
- package/src/eslint-rules/pace-core-compliance.cjs +106 -0
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
- package/src/hooks/useAppConfig.ts +15 -30
- package/src/hooks/useFileDisplay.ts +77 -50
- package/src/index.ts +4 -5
- package/src/providers/services/AuthServiceProvider.tsx +17 -7
- package/src/providers/services/EventServiceProvider.tsx +33 -5
- package/src/providers/services/UnifiedAuthProvider.tsx +90 -134
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
- package/src/rbac/adapters.tsx +2 -2
- package/src/rbac/api.test.ts +59 -51
- package/src/rbac/api.ts +178 -132
- package/src/rbac/components/PagePermissionGuard.tsx +38 -10
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
- package/src/rbac/hooks/permissions/useAccessLevel.ts +1 -1
- package/src/rbac/hooks/permissions/useCan.ts +41 -11
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +1 -1
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +1 -1
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +1 -1
- package/src/rbac/hooks/useCan.test.ts +0 -9
- package/src/rbac/hooks/useRBAC.test.ts +1 -5
- package/src/rbac/hooks/useRBAC.ts +36 -37
- package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
- package/src/rbac/hooks/useResolvedScope.ts +35 -40
- package/src/rbac/hooks/useSecureSupabase.ts +7 -7
- package/src/rbac/index.ts +7 -0
- package/src/rbac/secureClient.test.ts +22 -18
- package/src/rbac/secureClient.ts +103 -16
- package/src/rbac/security.ts +0 -17
- package/src/rbac/types.ts +1 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
- package/src/rbac/utils/clientSecurity.ts +93 -0
- package/src/rbac/utils/contextValidator.ts +77 -168
- package/src/services/AuthService.ts +39 -7
- package/src/services/EventService.ts +285 -56
- package/src/services/OrganisationService.ts +81 -14
- package/src/services/__tests__/EventService.test.ts +1 -2
- package/src/services/base/BaseService.ts +3 -0
- package/src/utils/dynamic/dynamicUtils.ts +7 -4
- package/dist/chunk-24UVZUZG.js.map +0 -1
- package/dist/chunk-3XC4CPTD.js.map +0 -1
- package/dist/chunk-6J4GEEJR.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-EHMR7VYL.js.map +0 -1
- package/dist/chunk-NECFR5MM.js.map +0 -1
- package/dist/chunk-SFZUDBL5.js.map +0 -1
- package/dist/chunk-XWQCNGTQ.js.map +0 -1
- package/docs/api/classes/ColumnFactory.md +0 -243
- package/docs/api/classes/InvalidScopeError.md +0 -73
- package/docs/api/classes/Logger.md +0 -178
- package/docs/api/classes/MissingUserContextError.md +0 -66
- package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
- package/docs/api/classes/PermissionDeniedError.md +0 -73
- package/docs/api/classes/RBACAuditManager.md +0 -297
- package/docs/api/classes/RBACCache.md +0 -322
- package/docs/api/classes/RBACEngine.md +0 -171
- package/docs/api/classes/RBACError.md +0 -76
- package/docs/api/classes/RBACNotInitializedError.md +0 -66
- package/docs/api/classes/SecureSupabaseClient.md +0 -163
- package/docs/api/classes/StorageUtils.md +0 -328
- package/docs/api/enums/FileCategory.md +0 -184
- package/docs/api/enums/LogLevel.md +0 -54
- package/docs/api/enums/RBACErrorCode.md +0 -228
- package/docs/api/enums/RPCFunction.md +0 -118
- package/docs/api/interfaces/AddressFieldProps.md +0 -241
- package/docs/api/interfaces/AddressFieldRef.md +0 -94
- package/docs/api/interfaces/AggregateConfig.md +0 -43
- package/docs/api/interfaces/AutocompleteOptions.md +0 -75
- package/docs/api/interfaces/AvatarProps.md +0 -128
- package/docs/api/interfaces/BadgeProps.md +0 -34
- package/docs/api/interfaces/ButtonProps.md +0 -56
- package/docs/api/interfaces/CalendarProps.md +0 -73
- package/docs/api/interfaces/CardProps.md +0 -69
- package/docs/api/interfaces/ColorPalette.md +0 -7
- package/docs/api/interfaces/ColorShade.md +0 -66
- package/docs/api/interfaces/ComplianceResult.md +0 -30
- package/docs/api/interfaces/DataAccessRecord.md +0 -96
- package/docs/api/interfaces/DataRecord.md +0 -11
- package/docs/api/interfaces/DataTableAction.md +0 -252
- package/docs/api/interfaces/DataTableColumn.md +0 -504
- package/docs/api/interfaces/DataTableProps.md +0 -625
- package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
- package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
- package/docs/api/interfaces/DatabaseIssue.md +0 -41
- package/docs/api/interfaces/EmptyStateConfig.md +0 -61
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
- package/docs/api/interfaces/ErrorBoundaryProps.md +0 -147
- package/docs/api/interfaces/ErrorBoundaryProviderProps.md +0 -36
- package/docs/api/interfaces/ErrorBoundaryState.md +0 -75
- package/docs/api/interfaces/EventAppRoleData.md +0 -71
- package/docs/api/interfaces/ExportColumn.md +0 -90
- package/docs/api/interfaces/ExportOptions.md +0 -126
- package/docs/api/interfaces/FileDisplayProps.md +0 -249
- package/docs/api/interfaces/FileMetadata.md +0 -129
- package/docs/api/interfaces/FileReference.md +0 -118
- package/docs/api/interfaces/FileSizeLimits.md +0 -7
- package/docs/api/interfaces/FileUploadOptions.md +0 -139
- package/docs/api/interfaces/FileUploadProps.md +0 -296
- package/docs/api/interfaces/FooterProps.md +0 -107
- package/docs/api/interfaces/FormFieldProps.md +0 -166
- package/docs/api/interfaces/FormProps.md +0 -113
- package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
- package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
- package/docs/api/interfaces/InputProps.md +0 -56
- package/docs/api/interfaces/LabelProps.md +0 -107
- package/docs/api/interfaces/LoggerConfig.md +0 -62
- package/docs/api/interfaces/LoginFormProps.md +0 -187
- package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
- package/docs/api/interfaces/NavigationContextType.md +0 -164
- package/docs/api/interfaces/NavigationGuardProps.md +0 -139
- package/docs/api/interfaces/NavigationItem.md +0 -120
- package/docs/api/interfaces/NavigationMenuProps.md +0 -221
- package/docs/api/interfaces/NavigationProviderProps.md +0 -117
- package/docs/api/interfaces/Organisation.md +0 -140
- package/docs/api/interfaces/OrganisationContextType.md +0 -388
- package/docs/api/interfaces/OrganisationMembership.md +0 -140
- package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
- package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
- package/docs/api/interfaces/PaceAppLayoutProps.md +0 -409
- package/docs/api/interfaces/PaceLoginPageProps.md +0 -49
- package/docs/api/interfaces/PageAccessRecord.md +0 -85
- package/docs/api/interfaces/PagePermissionContextType.md +0 -140
- package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
- package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
- package/docs/api/interfaces/PaletteData.md +0 -41
- package/docs/api/interfaces/ParsedAddress.md +0 -120
- package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
- package/docs/api/interfaces/ProgressProps.md +0 -42
- package/docs/api/interfaces/ProtectedRouteProps.md +0 -78
- package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
- package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
- package/docs/api/interfaces/PublicPageLayoutProps.md +0 -185
- package/docs/api/interfaces/QuickFix.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
- package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
- package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
- package/docs/api/interfaces/RBACConfig.md +0 -133
- package/docs/api/interfaces/RBACContext.md +0 -52
- package/docs/api/interfaces/RBACLogger.md +0 -112
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
- package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
- package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
- package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
- package/docs/api/interfaces/RBACResult.md +0 -58
- package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
- package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
- package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
- package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
- package/docs/api/interfaces/RBACRolesListParams.md +0 -52
- package/docs/api/interfaces/RBACRolesListResult.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
- package/docs/api/interfaces/ResourcePermissions.md +0 -155
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
- package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
- package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
- package/docs/api/interfaces/RoleManagementResult.md +0 -52
- package/docs/api/interfaces/RouteAccessRecord.md +0 -107
- package/docs/api/interfaces/RouteConfig.md +0 -134
- package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
- package/docs/api/interfaces/SecureDataContextType.md +0 -168
- package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
- package/docs/api/interfaces/SetupIssue.md +0 -41
- package/docs/api/interfaces/StorageConfig.md +0 -41
- package/docs/api/interfaces/StorageFileInfo.md +0 -74
- package/docs/api/interfaces/StorageFileMetadata.md +0 -151
- package/docs/api/interfaces/StorageListOptions.md +0 -99
- package/docs/api/interfaces/StorageListResult.md +0 -41
- package/docs/api/interfaces/StorageUploadOptions.md +0 -101
- package/docs/api/interfaces/StorageUploadResult.md +0 -63
- package/docs/api/interfaces/StorageUrlOptions.md +0 -60
- package/docs/api/interfaces/StyleImport.md +0 -19
- package/docs/api/interfaces/SwitchProps.md +0 -34
- package/docs/api/interfaces/TabsContentProps.md +0 -9
- package/docs/api/interfaces/TabsListProps.md +0 -9
- package/docs/api/interfaces/TabsProps.md +0 -9
- package/docs/api/interfaces/TabsTriggerProps.md +0 -50
- package/docs/api/interfaces/TextareaProps.md +0 -53
- package/docs/api/interfaces/ToastActionElement.md +0 -12
- package/docs/api/interfaces/ToastProps.md +0 -9
- package/docs/api/interfaces/UnifiedAuthContextType.md +0 -823
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -173
- package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
- package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -138
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -84
- package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
- package/docs/api/interfaces/UsePublicEventReturn.md +0 -71
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -123
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -97
- package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
- package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
- package/docs/api/interfaces/UserEventAccess.md +0 -121
- package/docs/api/interfaces/UserMenuProps.md +0 -88
- package/docs/api/interfaces/UserProfile.md +0 -63
- package/src/components/EventSelector/EventSelector.test.tsx +0 -720
- package/src/components/EventSelector/EventSelector.tsx +0 -423
- package/src/components/EventSelector/index.ts +0 -3
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -327
- package/src/components/OrganisationSelector/index.ts +0 -9
- /package/dist/{DataTable-TPTKCX4D.js.map → DataTable-E7YQZD7D.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-CH6Z342H.js.map → UnifiedAuthProvider-QPXO24B4.js.map} +0 -0
- /package/dist/{api-MVVQZLJI.js.map → api-6LVZTHDS.js.map} +0 -0
- /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
- /package/dist/{chunk-2UOI2FG5.js.map → chunk-5EC5MEWX.js.map} +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
- /package/dist/{chunk-F2IMUDXZ.js.map → chunk-M7MPQISP.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/AddressField/AddressField.tsx","../src/components/Label/Label.tsx","../src/components/Textarea/Textarea.tsx","../src/components/FileDisplay/FileDisplay.tsx","../src/hooks/useFileUrl.ts","../src/hooks/useFileReference.ts","../src/components/Avatar/Avatar.tsx","../src/components/Badge/Badge.tsx","../src/components/Switch/Switch.tsx","../src/components/Tabs/Tabs.tsx","../src/components/Calendar/Calendar.tsx","../src/components/Toast/Toast.tsx","../src/components/Form/Form.tsx","../src/components/LoginForm/LoginForm.tsx","../src/components/ContextSelector/ContextSelector.tsx","../src/components/PasswordChange/PasswordChangeForm.tsx","../src/components/UserMenu/UserMenu.tsx","../src/components/NavigationMenu/NavigationMenu.tsx","../src/components/NavigationMenu/useNavigationFiltering.ts","../src/components/Header/Header.tsx","../src/components/Footer/Footer.tsx","../src/components/PaceAppLayout/PaceAppLayout.tsx","../src/components/PaceLoginPage/PaceLoginPage.tsx","../src/components/SessionRestorationLoader/SessionRestorationLoader.tsx","../src/components/ProtectedRoute/ProtectedRoute.tsx","../src/components/FileUpload/FileUpload.tsx","../src/components/Table/Table.tsx","../src/components/PublicLayout/PublicPageLayout.tsx"],"sourcesContent":["/**\n * @file AddressField Component\n * @package @jmruthers/pace-core\n * @module Components/AddressField\n * @since 0.1.0\n *\n * Address input field with Google Places API autocomplete.\n * Provides address suggestions, keyboard navigation, and accessibility.\n *\n * Features:\n * - Google Places API autocomplete integration\n * - Debounced input with caching\n * - Keyboard navigation (Arrow keys, Enter, Escape)\n * - Accessible ARIA attributes\n * - Semantic HTML (description list for suggestions)\n * - Loading and error states\n * - place_id storage for later retrieval\n *\n * @accessibility\n * - Uses semantic HTML: `<dl>`, `<dt>`, `<dd>` for address suggestions\n * - Proper ARIA attributes for combobox pattern\n * - Keyboard navigation support\n * - Screen reader friendly\n */\n\nimport * as React from 'react';\nimport { Input } from '../Input/Input';\nimport { LoadingSpinner } from '../LoadingSpinner';\nimport { cn } from '../../utils/core/cn';\nimport { useAddressAutocomplete } from '../../hooks/useAddressAutocomplete';\nimport type { AddressFieldProps, AddressFieldRef } from './types';\nimport type { ParsedAddress } from '../../utils/google-places';\n\n/**\n * AddressField component\n * \n * A production-ready address input field with Google Places API autocomplete.\n * Returns structured address data including place_id for later retrieval.\n * \n * @param props - AddressField configuration\n * @param ref - Forwarded ref for imperative access\n * @returns JSX.Element - The rendered address field\n * \n * @example\n * ```tsx\n * <AddressField\n * apiKey={apiKey}\n * onChange={(address) => {\n * // address includes place_id, full_address, lat, lng, etc.\n * console.log(address.place_id);\n * }}\n * placeholder=\"Enter your address\"\n * />\n * ```\n */\nconst AddressField = React.forwardRef<HTMLInputElement, AddressFieldProps>(\n (\n {\n apiKey,\n value: controlledValue,\n defaultValue = '',\n onChange,\n onInputChange,\n placeholder = 'Enter address',\n error,\n disabled,\n className,\n size = 'md',\n variant = 'default',\n autocompleteOptions,\n debounceDelay,\n cacheEnabled = true,\n cacheTTL,\n ...props\n },\n ref\n ) => {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isOpen, setIsOpen] = React.useState(false);\n const [selectedIndex, setSelectedIndex] = React.useState(-1);\n const [inputFocused, setInputFocused] = React.useState(false);\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const suggestionsRef = React.useRef<HTMLDListElement>(null);\n const containerRef = React.useRef<HTMLFormElement>(null);\n\n // Use controlled or uncontrolled value\n const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n // Use autocomplete hook\n const { suggestions, isLoading, error: autocompleteError, selectAddress, clearSuggestions } =\n useAddressAutocomplete(apiKey, value, {\n autocompleteOptions,\n debounceDelay,\n cacheEnabled,\n cacheTTL,\n });\n\n // Update suggestions visibility\n React.useEffect(() => {\n if (suggestions.length > 0 && inputFocused && value.trim()) {\n setIsOpen(true);\n } else if (suggestions.length === 0 || !value.trim()) {\n setIsOpen(false);\n }\n }, [suggestions, inputFocused, value]);\n\n // Handle input change\n const handleInputChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInputChange?.(newValue);\n setSelectedIndex(-1);\n if (!newValue.trim()) {\n onChange?.(null);\n clearSuggestions();\n }\n },\n [controlledValue, onInputChange, onChange, clearSuggestions]\n );\n\n // Handle address selection\n const handleSelectAddress = React.useCallback(\n async (placeId: string) => {\n setIsOpen(false);\n setSelectedIndex(-1);\n const address = await selectAddress(placeId);\n if (address) {\n // Update input with formatted address\n const displayValue = address.full_address || '';\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInputChange?.(displayValue);\n onChange?.(address);\n }\n inputRef.current?.blur();\n },\n [selectAddress, onChange, onInputChange, controlledValue]\n );\n\n // Handle keyboard navigation\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || suggestions.length === 0) {\n if (e.key === 'Escape') {\n setIsOpen(false);\n inputRef.current?.blur();\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setSelectedIndex((prev) => (prev < suggestions.length - 1 ? prev + 1 : prev));\n break;\n case 'ArrowUp':\n e.preventDefault();\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1));\n break;\n case 'Enter':\n e.preventDefault();\n if (selectedIndex >= 0 && selectedIndex < suggestions.length) {\n handleSelectAddress(suggestions[selectedIndex].place_id);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.blur();\n break;\n case 'Tab':\n setIsOpen(false);\n setSelectedIndex(-1);\n break;\n }\n },\n [isOpen, suggestions, selectedIndex, handleSelectAddress]\n );\n\n // Handle focus\n const handleFocus = React.useCallback(() => {\n setInputFocused(true);\n if (suggestions.length > 0 && value.trim()) {\n setIsOpen(true);\n }\n }, [suggestions, value]);\n\n // Handle blur\n const handleBlur = React.useCallback(\n (e: React.FocusEvent<HTMLInputElement>) => {\n // Delay to allow click events on suggestions\n setTimeout(() => {\n if (!containerRef.current?.contains(document.activeElement)) {\n setInputFocused(false);\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n }, 200);\n },\n []\n );\n\n // Click outside handler\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSelectedIndex(-1);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }\n }, [isOpen]);\n\n // Generate unique ID for suggestions list\n const suggestionsId = React.useId();\n\n // Scroll selected item into view\n // Uses getElementById instead of querySelector to handle React.useId() generated IDs\n // which may contain colons (e.g., ':r15:') that are invalid in CSS selectors\n React.useEffect(() => {\n if (selectedIndex >= 0) {\n const selectedItem = document.getElementById(\n `${suggestionsId}-item-${selectedIndex}`\n ) as HTMLElement;\n if (selectedItem && typeof selectedItem.scrollIntoView === 'function') {\n selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }\n }\n }, [selectedIndex, suggestionsId]);\n\n // Combine refs\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const hasError = error || !!autocompleteError;\n\n return (\n <form ref={containerRef} className={cn('relative w-full', className)}>\n <Input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n disabled={disabled}\n error={hasError}\n size={size}\n variant={variant}\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n aria-controls={suggestionsId}\n aria-haspopup=\"listbox\"\n aria-activedescendant={\n selectedIndex >= 0 ? `${suggestionsId}-item-${selectedIndex}` : undefined\n }\n {...props}\n />\n {isLoading && (\n <p className=\"absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none\">\n <LoadingSpinner size=\"sm\" />\n </p>\n )}\n\n {isOpen && suggestions.length > 0 && (\n <dl\n ref={suggestionsRef}\n id={suggestionsId}\n role=\"listbox\"\n className={cn(\n 'absolute z-[99999] w-full mt-1 max-h-60 overflow-y-auto',\n 'border border-main-300 bg-main-50 shadow-lg rounded-md',\n 'list-none p-0 m-0'\n )}\n data-testid=\"address-suggestions\"\n >\n {suggestions.map((suggestion, index) => (\n <React.Fragment key={suggestion.place_id}>\n <dt\n id={`${suggestionsId}-item-${index}`}\n role=\"option\"\n aria-selected={selectedIndex === index}\n className={cn(\n 'px-3 py-2 cursor-pointer text-sm',\n 'hover:bg-main-100 focus:bg-main-100',\n 'border-b border-main-200 last:border-b-0',\n selectedIndex === index && 'bg-main-100',\n 'font-medium text-main-900'\n )}\n onClick={() => handleSelectAddress(suggestion.place_id)}\n onMouseEnter={() => setSelectedIndex(index)}\n data-testid={`address-suggestion-${index}`}\n >\n {suggestion.structured_formatting?.main_text || suggestion.description}\n </dt>\n {suggestion.structured_formatting?.secondary_text && (\n <dd className=\"px-3 pb-2 text-xs text-main-600 mt-0.5\">\n {suggestion.structured_formatting.secondary_text}\n </dd>\n )}\n </React.Fragment>\n ))}\n </dl>\n )}\n\n {autocompleteError && (\n <p className=\"mt-1 text-sm text-destructive\" role=\"alert\">\n {autocompleteError.message}\n </p>\n )}\n </form>\n );\n }\n);\n\nAddressField.displayName = 'AddressField';\n\nexport { AddressField };\nexport type { AddressFieldProps, AddressFieldRef, ParsedAddress } from './types';\n\n","/**\n * @file Label Component\n * @package @jmruthers/pace-core\n * @module Components/Label\n * @since 0.1.0\n *\n * An accessible label component built on top of Radix UI primitives.\n * Provides form labels with helper text, error states, and required indicators.\n *\n * Features:\n * - Proper label association with form controls\n * - Required field indicators\n * - Helper text support\n * - Error state display\n * - Customizable styling\n * - Screen reader friendly\n * - Keyboard accessible\n *\n * @example\n * ```tsx\n * // Basic label\n * <Label htmlFor=\"email\">Email Address</Label>\n * <Input id=\"email\" type=\"email\" />\n * \n * // Label with required indicator\n * <Label htmlFor=\"name\" required>\n * Full Name\n * </Label>\n * <Input id=\"name\" />\n * \n * // Label with helper text\n * <Label \n * htmlFor=\"password\" \n * required \n * helperText=\"Must be at least 8 characters\"\n * >\n * Password\n * </Label>\n * <Input id=\"password\" type=\"password\" />\n * \n * // Label with error state\n * <Label \n * htmlFor=\"email\" \n * error=\"Please enter a valid email address\"\n * >\n * Email Address\n * </Label>\n * <Input id=\"email\" type=\"email\" />\n * \n * // Custom required indicator\n * <Label \n * htmlFor=\"terms\" \n * required \n * requiredIndicator=\"(required)\"\n * >\n * Accept Terms\n * </Label>\n * <Checkbox id=\"terms\" />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper label association with htmlFor\n * - Screen reader announcements for errors\n * - Required field indicators for screen readers\n * - Error messages with role=\"alert\"\n * - High contrast support\n *\n * @dependencies\n * - @radix-ui/react-label - Core label functionality\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cn } from '../../utils/core/cn';\n\nconst getLabelClasses = (): string => {\n return 'font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70';\n};\n\n/**\n * Props for the Label component\n */\nexport interface LabelProps\n extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n /** Whether the field is required */\n required?: boolean;\n /** Custom required indicator (default: '*') */\n requiredIndicator?: React.ReactNode;\n /** Whether to hide the required indicator visually */\n hideRequiredIndicator?: boolean;\n /** Helper text to display below the label */\n helperText?: string;\n /** CSS classes for helper text styling */\n helperTextClassName?: string;\n /** Error message to display */\n error?: string;\n /** CSS classes for error message styling */\n errorClassName?: string;\n}\n\n/**\n * Label component\n * An accessible label with helper text and error state support\n * \n * @param props - Label configuration and styling\n * @param ref - Forwarded ref to the label element\n * @returns JSX.Element - The rendered label with optional helper text and errors\n * \n * @example\n * ```tsx\n * <Label htmlFor=\"email\" required helperText=\"We'll never share your email\">\n * Email Address\n * </Label>\n * ```\n */\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n LabelProps\n>(({\n className,\n required = false,\n requiredIndicator,\n hideRequiredIndicator = false,\n helperText,\n helperTextClassName,\n error,\n errorClassName,\n children,\n htmlFor,\n ...props\n}, ref) => {\n const hasError = !!error;\n const showHelperText = helperText && !hasError;\n \n return (\n <>\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n getLabelClasses(),\n hasError && 'text-destructive',\n className\n )}\n htmlFor={htmlFor}\n {...props}\n >\n {children}\n {required && (\n <span\n aria-label=\"required\"\n className={cn(\n 'text-destructive ml-1',\n hideRequiredIndicator && 'sr-only'\n )}\n >\n {requiredIndicator || '*'}\n </span>\n )}\n </LabelPrimitive.Root>\n \n {showHelperText && (\n <p className={cn('text-muted-foreground', helperTextClassName)}>\n {helperText}\n </p>\n )}\n \n {hasError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className={cn('text-destructive', errorClassName)}\n >\n {error}\n </p>\n )}\n </>\n );\n});\n\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","/**\n * @file Textarea Component\n * @package @jmruthers/pace-core\n * @module Textarea\n * @since 0.5.141\n *\n * A multi-line text input component with consistent styling matching the Input component.\n * Provides flexible, accessible textarea component with consistent styling and behavior.\n *\n * Features:\n * - Multiple textarea variants (default, destructive)\n * - Multiple textarea sizes (sm, md, lg)\n * - Error state styling\n * - Forwarded ref support\n * - Consistent styling with Input component\n *\n * @example\n * ```tsx\n * // Basic textarea\n * <Textarea placeholder=\"Enter your message...\" />\n * \n * // Textarea with variants and sizes\n * <Textarea \n * variant=\"destructive\" \n * size=\"lg\" \n * placeholder=\"Error textarea\" \n * />\n * \n * // Textarea with error state\n * <Textarea \n * placeholder=\"Comments\" \n * error={true}\n * />\n * ```\n *\n * @accessibility\n * - Proper ARIA attributes and roles\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n */\n\nimport * as React from 'react';\nimport { cn } from '../../utils/core/cn';\n\n// ============================================================================\n// TEXTAREA COMPONENT\n// ============================================================================\n\nexport interface TextareaProps\n extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n /**\n * Textarea variant style\n */\n variant?: 'default' | 'destructive';\n \n /**\n * Textarea size\n */\n size?: 'sm' | 'md' | 'lg';\n \n /**\n * Error state for styling\n */\n error?: boolean;\n}\n\n/**\n * Textarea component\n * A flexible, accessible textarea component with multiple variants and sizes.\n * Matches the Input component API and styling for consistency.\n * \n * @param props - Textarea configuration and styling\n * @param ref - Forwarded ref to the textarea element\n * @returns JSX.Element - The rendered textarea element\n * \n * @example\n * ```tsx\n * // Basic textarea\n * <Textarea placeholder=\"Enter your message...\" />\n * \n * // Textarea with error state\n * <Textarea \n * placeholder=\"Comments\" \n * error={true}\n * />\n * \n * // Large textarea with destructive variant\n * <Textarea \n * variant=\"destructive\" \n * size=\"lg\" \n * placeholder=\"Error textarea\" \n * />\n * ```\n */\nfunction Textarea({ className, variant = 'default', size = 'md', error, ref, ...props }: TextareaProps & { ref?: React.Ref<HTMLTextAreaElement> }) {\n return (\n <textarea\n className={cn(\n // Base styles (matching Input component)\n 'flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',\n \n // Variant styles\n {\n 'border-input': variant === 'default' && !error,\n 'border-destructive focus-visible:ring-destructive': variant === 'destructive' || error,\n },\n \n // Size styles\n {\n 'min-h-[60px] px-2 py-1 text-xs': size === 'sm',\n 'min-h-[80px] px-3 py-2 text-sm': size === 'md',\n 'min-h-[100px] px-4 py-3 text-base': size === 'lg',\n },\n \n className\n )}\n ref={ref}\n {...props}\n />\n );\n}\n\nTextarea.displayName = 'Textarea';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Textarea };\n\n","import React, { useState, useEffect, useCallback, useRef, useContext, useMemo } from 'react';\nimport { FileText, ExternalLink } from 'lucide-react';\nimport { FileReference, FileCategory } from '../../types/file-reference';\nimport { usePublicFileDisplay } from '../../hooks/public/usePublicFileDisplay';\nimport { useFileDisplay } from '../../hooks/useFileDisplay';\nimport { useFileUrl } from '../../hooks/useFileUrl';\nimport { PublicPageContext, useIsPublicPage } from '../PublicLayout/PublicPageProvider';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter } from '../Dialog/Dialog';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { logger } from '../../utils/core/logger';\n\n/**\n * Size classes for fallback display\n */\nconst fallbackSizeClasses = {\n xs: 'size-4 text-xs',\n sm: 'size-6 text-sm',\n md: 'size-8 text-base',\n lg: 'size-12 text-lg',\n xl: 'size-16 text-xl',\n '2xl': 'size-20 text-2xl'\n};\n\n/**\n * Base classes for fallback display\n */\nconst fallbackBaseClasses = 'size-full grid place-items-center text-center text-sec-600 font-semibold';\n\n/**\n * Helper function to compute fallback classes for a given size\n */\nfunction getFallbackClasses(size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' = 'md'): string {\n const sizeClass = fallbackSizeClasses[size];\n return `${fallbackBaseClasses} ${sizeClass}`.trim();\n}\n\n/**\n * Default fallback text generator - extracts initials from file name\n */\nfunction defaultGenerateFallbackText(fileName?: string): string {\n if (!fileName) return 'FL';\n \n // Extract initials from file name (without extension)\n const baseName = fileName.replace(/\\.[^/.]+$/, '');\n const words = baseName.split(/[\\s\\-_]+/);\n \n if (words.length === 0) return 'FL';\n \n return words\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3); // Max 3 characters\n}\n\nexport interface FileDisplayProps {\n table_name: string;\n record_id: string;\n /** \n * Optional organisation ID. When not provided (undefined), the component will automatically\n * search for files in both user-scoped (organisation_id = null) and organisation-scoped contexts.\n * If both types of files exist, organisation-scoped files are preferred.\n * When explicitly set to null, only user-scoped files are searched.\n */\n organisation_id?: string;\n category?: FileCategory;\n /** Display only a single file instead of all files. Uses first file (prefers images) from all files, without category filtering */\n displayOnly?: boolean;\n showDelete?: boolean;\n className?: string;\n /** Classes to apply to the first child element of <figure> (img, p, or other elements) */\n imgClassName?: string;\n children?: React.ReactNode;\n /** Custom loading component to render during data fetching */\n loadingComponent?: React.ComponentType;\n /** Custom error component to render when an error occurs */\n errorComponent?: React.ComponentType<{ error: Error | string | null; retry?: () => void }>;\n /** Whether to show fallback UI when no file is available or image fails to load */\n showFallback?: boolean;\n /** Custom function to generate fallback text from file name or other context */\n generateFallbackText?: (fileName?: string) => string;\n /** Explicit fallback text to display (overrides generateFallbackText) */\n fallbackText?: string;\n /** Source text to use for generating fallback text (overrides filename) */\n fallbackSourceText?: string;\n /** Size variant for fallback display (only applies when showFallback is true) */\n fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** \n * Enable children rendering in displayOnly mode. When true, uses standard display path \n * (with children support) even if showDelete is false. The delete button will only appear \n * if showDelete is also true.\n */\n enableChildren?: boolean;\n /** Whether to show metadata (filename, filesize, mimetype) in figcaption. Defaults to true. */\n showMetadata?: boolean;\n}\n\n// Shared rendering logic for file display\ninterface FileDisplayContentProps {\n isLoading: boolean;\n error: string | Error | null;\n fileUrl: string | null;\n fileReference: FileReference | null;\n fileReferences: FileReference[];\n fileUrls: Map<string, string>;\n fileCount: number;\n category: FileCategory | undefined;\n displayOnly: boolean;\n showDelete: boolean;\n className: string;\n imgClassName?: string;\n children?: React.ReactNode;\n onDelete?: () => Promise<void>;\n clearError?: () => void;\n organisation_id: string | undefined;\n loadingComponent?: React.ComponentType;\n errorComponent?: React.ComponentType<{ error: Error | string | null; retry?: () => void }>;\n showFallback?: boolean;\n generateFallbackText?: (fileName?: string) => string;\n fallbackText?: string;\n fallbackSourceText?: string;\n fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n enableChildren?: boolean;\n showMetadata?: boolean;\n}\n\nconst FileDisplayContent = React.memo(function FileDisplayContent({\n isLoading,\n error,\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n category,\n displayOnly,\n showDelete,\n className,\n imgClassName,\n children,\n onDelete,\n clearError,\n organisation_id,\n loadingComponent: LoadingComponent,\n errorComponent: ErrorComponent,\n showFallback = false,\n generateFallbackText = defaultGenerateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize = 'md',\n enableChildren = false,\n showMetadata = true\n}: FileDisplayContentProps) {\n const [imageError, setImageError] = useState(false);\n const [internalFileUrls, setInternalFileUrls] = useState<Map<string, string>>(new Map(fileUrls));\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const fileReferencesRef = useRef<FileReference[]>([]);\n const imgRef = useRef<HTMLImageElement | null>(null);\n const currentSrcRef = useRef<string | null>(null);\n const isImageLoadingRef = useRef(false);\n\n // Stabilize fileUrl to prevent unnecessary image reloads\n // This prevents NS_BINDING_ABORTED errors when the component re-renders\n const stableFileUrl = useMemo(() => fileUrl, [fileUrl]);\n\n // Track when image starts loading to prevent cancellation\n const handleImageLoadStart = useCallback(() => {\n isImageLoadingRef.current = true;\n if (stableFileUrl) {\n currentSrcRef.current = stableFileUrl;\n }\n }, [stableFileUrl]);\n\n // Track when image finishes loading\n const handleImageLoad = useCallback(() => {\n isImageLoadingRef.current = false;\n if (stableFileUrl) {\n currentSrcRef.current = stableFileUrl;\n }\n }, [stableFileUrl]);\n\n // Compute fallback text\n const computedFallbackText = useMemo(() => {\n if (fallbackText) return fallbackText;\n // Use fallbackSourceText if provided, otherwise fall back to filename\n const sourceText = fallbackSourceText ?? fileReference?.file_metadata?.fileName;\n return generateFallbackText(sourceText);\n }, [fallbackText, fallbackSourceText, fileReference, generateFallbackText]);\n\n // Compute fallback classes\n const fallbackClasses = useMemo(() => {\n return getFallbackClasses(fallbackSize);\n }, [fallbackSize]);\n\n // Sync fileUrls prop with internal state\n // Track file references to detect when they change and sync URLs\n useEffect(() => {\n const currentIds = fileReferences.map(f => f.id).join(',');\n const prevIds = fileReferencesRef.current.map(f => f.id).join(',');\n \n if (currentIds !== prevIds) {\n fileReferencesRef.current = fileReferences;\n // Reset internal URLs when file references change, then immediately sync from props\n setInternalFileUrls(new Map(fileUrls));\n } else {\n // If file references haven't changed, just sync URLs\n setInternalFileUrls(new Map(fileUrls));\n }\n }, [fileReferences, fileUrls]);\n\n const handleDeleteClick = () => {\n setDeleteDialogOpen(true);\n };\n\n const handleDeleteConfirm = async () => {\n setDeleteDialogOpen(false);\n try {\n if (onDelete) {\n await onDelete();\n }\n setImageError(false);\n } catch (error) {\n // Error handling is delegated to onDelete callback\n setImageError(false);\n }\n };\n\n const handleImageError = () => {\n setImageError(true);\n };\n\n const getFileIcon = (fileType: string) => {\n if (fileType.startsWith('image/')) return '🖼️';\n if (fileType.startsWith('video/')) return '🎥';\n if (fileType.startsWith('audio/')) return '🎵';\n if (fileType.includes('pdf')) return '📄';\n if (fileType.includes('word')) return '📝';\n if (fileType.includes('excel') || fileType.includes('spreadsheet')) return '📊';\n if (fileType.includes('powerpoint') || fileType.includes('presentation')) return '📊';\n return '📁';\n };\n\n const formatFileSize = (bytes: number) => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n };\n\n // Check for errors first - errors should be shown even if fileCount is 0\n if (error) {\n if (ErrorComponent) {\n return <ErrorComponent error={error} retry={clearError} />;\n }\n \n // Show fallback if enabled\n if (showFallback) {\n return (\n <figure className={className} title=\"File unavailable\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Error loading file: {error instanceof Error ? error.message : String(error)}\n </p>\n {clearError && (\n <Button\n onClick={clearError}\n className=\"mt-2\"\n aria-label=\"Retry loading file\"\n >\n Try again\n </Button>\n )}\n </figure>\n );\n }\n\n // Show fallback immediately if enabled and we have no files (even during loading)\n // This provides better UX by showing fallback UI instead of a spinner when we know there are no files\n if (fileCount === 0 && !isLoading) {\n // Show fallback if enabled\n if (showFallback) {\n return (\n <figure className={className} title=\"No file\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n {children}\n </figure>\n );\n }\n \n return (\n <figure className={`text-sec-500 text-center p-4 ${className}`}>\n <p>No files found</p>\n {children}\n </figure>\n );\n }\n\n // During loading, show fallback if enabled (better UX than spinner for empty states)\n if (isLoading && showFallback && fileCount === 0) {\n return (\n <figure className={className} title=\"Loading...\">\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n {children}\n </figure>\n );\n }\n\n if (isLoading) {\n if (LoadingComponent) {\n return <LoadingComponent />;\n }\n return (\n <figure className={className} title=\"Loading\">\n <p className=\"flex items-center justify-center p-4\">\n <LoadingSpinner />\n </p>\n </figure>\n );\n }\n\n // Single file display (when category or displayOnly is specified)\n if ((category || displayOnly) && fileReference) {\n const isImage = fileReference.file_metadata.fileType?.startsWith('image/');\n \n // Simplified image-only display when displayOnly is true and it's an image\n // Only use simplified path if enableChildren is not explicitly enabled\n if (displayOnly && isImage && !showDelete && !enableChildren) {\n // Show fallback if image error occurred and fallback is enabled\n if (imageError && showFallback) {\n return (\n <figure className={className} title={fileReference.file_metadata.fileName || 'File'}>\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n // Show loading skeleton if URL is not available yet\n if (!stableFileUrl) {\n return (\n <figure className={className || \"max-w-full h-48\"} title=\"Loading\">\n <p className={fallbackClasses}>\n <LoadingSpinner />\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={className || \"\"}>\n <img\n ref={imgRef}\n key={fileReference.id}\n src={stableFileUrl || undefined}\n alt={fileReference.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n onLoadStart={handleImageLoadStart}\n onLoad={handleImageLoad}\n loading=\"lazy\"\n />\n </figure>\n );\n }\n \n // Document link display when displayOnly is true and file is not an image\n // Render non-image files as clickable links that open in a new tab\n if (displayOnly && !isImage && stableFileUrl && fileReference && !showDelete) {\n const fileName = fileReference.file_metadata?.fileName || 'Document';\n const ariaLabel = `Open ${fileName} in new tab`;\n \n return (\n <figure className={className}>\n <a\n href={stableFileUrl || undefined}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={ariaLabel}\n className=\"flex items-center gap-2 p-3 bg-sec-50 border border-sec-200 rounded-lg hover:bg-sec-100 transition-colors text-main-600 hover:text-main-700 focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2\"\n >\n <FileText className=\"size-5 shrink-0\" aria-hidden=\"true\" />\n <span className=\"flex-1 font-medium truncate\">\n {fileName}\n </span>\n <ExternalLink className=\"size-5 shrink-0\" aria-hidden=\"true\" />\n </a>\n {showMetadata && (\n <figcaption>\n <p>{fileName}</p>\n {fileReference.file_metadata.fileSize && (\n <p>{formatFileSize(fileReference.file_metadata.fileSize)} • {fileReference.file_metadata.fileType}</p>\n )}\n </figcaption>\n )}\n </figure>\n );\n }\n \n // Standard single file display with wrapper\n // For displayOnly mode, if fallback is enabled and there's no URL or image error, show fallback instead of folder icon\n if (displayOnly && showFallback && (!stableFileUrl || imageError || !isImage)) {\n return (\n <figure className={className} title={fileReference.file_metadata.fileName || 'File'}>\n <p className={fallbackClasses}>\n {computedFallbackText}\n </p>\n </figure>\n );\n }\n \n return (\n <figure className={`relative ${className}`}>\n {isImage && stableFileUrl && !imageError ? (\n <>\n <img\n key={fileReference.id}\n src={stableFileUrl}\n alt={fileReference.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n loading=\"lazy\"\n />\n {showDelete && (\n <>\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n className=\"absolute top-2 right-2\"\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogContent size=\"sm\">\n <DialogHeader>\n <DialogTitle>Confirm Delete</DialogTitle>\n </DialogHeader>\n <DialogBody>\n <p>Are you sure you want to delete this file? This action cannot be undone.</p>\n </DialogBody>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={handleDeleteConfirm}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )}\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n ) : isImage && imageError && showFallback ? (\n // Show fallback when image fails to load and fallback is enabled\n <>\n <p className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>\n {computedFallbackText}\n </p>\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n ) : (\n <>\n <p className=\"flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200\">\n <span className=\"text-2xl\">\n {getFileIcon(fileReference.file_metadata.fileType || '')}\n </span>\n {showDelete && (\n <>\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n className=\"ml-auto\"\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>\n <DialogContent size=\"sm\">\n <DialogHeader>\n <DialogTitle>Confirm Delete</DialogTitle>\n </DialogHeader>\n <DialogBody>\n <p>Are you sure you want to delete this file? This action cannot be undone.</p>\n </DialogBody>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setDeleteDialogOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={handleDeleteConfirm}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )}\n </p>\n {children}\n {showMetadata && (\n <figcaption>\n <p>{fileReference.file_metadata.fileName || 'Unknown file'}</p>\n {(fileReference.file_metadata.fileSize || fileReference.file_metadata.fileType) && (\n <p>\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileSize && fileReference.file_metadata.fileType && ' • '}\n {fileReference.file_metadata.fileType}\n </p>\n )}\n </figcaption>\n )}\n </>\n )}\n </figure>\n );\n }\n\n // Multiple files display\n return (\n <figure className={`space-y-2 ${className}`}>\n {fileReferences.map((fileRef) => {\n const isImage = fileRef.file_metadata.fileType?.startsWith('image/');\n const fileUrl = internalFileUrls.get(fileRef.id) || null;\n const canDownload = !isImage && fileUrl;\n \n return (\n <figure key={fileRef.id} className=\"flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200\">\n {isImage && fileUrl ? (\n <img\n key={fileRef.id}\n src={fileUrl || undefined}\n alt={fileRef.file_metadata.fileName || 'File'}\n className={imgClassName || \"object-cover size-full\"}\n onError={handleImageError}\n loading=\"lazy\"\n />\n ) : (\n <span className=\"text-2xl\">\n {getFileIcon(fileRef.file_metadata.fileType || '')}\n </span>\n )}\n {showMetadata && (\n <figcaption className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-sec-900 truncate\">\n {fileRef.file_metadata.fileName || 'Unknown file'}\n </p>\n {(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType || fileRef.file_metadata.category) && (\n <p className=\"text-sm text-sec-500\">\n {fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize)}\n {fileRef.file_metadata.fileSize && fileRef.file_metadata.fileType && ' • '}\n {fileRef.file_metadata.fileType}\n {(fileRef.file_metadata.fileSize || fileRef.file_metadata.fileType) && fileRef.file_metadata.category && ' • '}\n {fileRef.file_metadata.category}\n </p>\n )}\n </figcaption>\n )}\n <p className=\"flex items-center space-x-2\">\n {canDownload && (\n <a\n href={fileRef.file_path}\n download={fileRef.file_metadata.fileName || 'download'}\n className=\"text-main-500 hover:text-main-700 p-1\"\n title=\"Download file\"\n >\n ↓\n </a>\n )}\n {showDelete && onDelete && (\n <Button\n variant=\"destructive\"\n size=\"icon\"\n onClick={handleDeleteClick}\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </Button>\n )}\n </p>\n </figure>\n );\n })}\n {children}\n </figure>\n );\n});\n\n/**\n * Internal component for public page context\n * Uses PublicPageContext to get Supabase client\n */\nfunction FileDisplayPublic({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n const publicPageContext = useContext(PublicPageContext);\n const supabase = publicPageContext?.supabase ?? null;\n\n if (!supabase) {\n // If fallback is enabled, show fallback UI instead of error\n if (showFallback) {\n return (\n <FileDisplayContent\n isLoading={false}\n error={null}\n fileUrl={null}\n fileReference={null}\n fileReferences={[]}\n fileUrls={new Map()}\n fileCount={0}\n category={category}\n displayOnly={displayOnly}\n showDelete={false}\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={undefined}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n }\n \n // Only show error if fallback is not enabled\n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Supabase client not available in public context\n </p>\n </figure>\n );\n }\n\n const {\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n isLoading,\n error,\n refetch\n } = usePublicFileDisplay(\n table_name,\n record_id,\n organisation_id,\n category,\n { supabase }\n );\n\n // Log errors for debugging public file display issues\n if (error) {\n logger.error('FileDisplayPublic', 'Error fetching file', {\n table_name,\n record_id,\n organisation_id,\n category,\n error: error.message,\n errorStack: error.stack\n });\n }\n\n // Public context doesn't support delete operations\n const handleDelete = async () => {\n // Delete operations are not available in public context for security reasons\n };\n\n // Handle displayOnly mode: select first file (prefer images) from all files\n let finalFileReference = fileReference;\n let finalFileUrl = fileUrl;\n let finalFileReferences = fileReferences;\n let finalFileCount = fileCount;\n\n if (displayOnly && !category && fileReferences.length > 0) {\n // Prefer image files\n const imageFiles = fileReferences.filter(f => \n f.file_metadata.fileType?.startsWith('image/')\n );\n const targetFile = imageFiles.length > 0 ? imageFiles[0] : fileReferences[0];\n finalFileReference = targetFile;\n finalFileReferences = [targetFile];\n finalFileCount = 1;\n \n // Get URL for target file from fileUrls map\n finalFileUrl = fileUrls.get(targetFile.id) || null;\n }\n\n return (\n <FileDisplayContent\n isLoading={isLoading}\n error={error}\n fileUrl={finalFileUrl}\n fileReference={finalFileReference}\n fileReferences={finalFileReferences}\n fileUrls={fileUrls}\n fileCount={finalFileCount}\n category={category}\n displayOnly={displayOnly}\n showDelete={false} // Never show delete in public context\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={showDelete ? handleDelete : undefined}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n\n/**\n * Internal component for authenticated page context\n * Uses UnifiedAuthProvider to get Supabase client\n */\nfunction FileDisplayAuthenticated({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n const { supabase } = useUnifiedAuth();\n\n // Consolidated state for displayOnly mode - must be before early return\n const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState<FileReference | null>(null);\n\n // Call hooks before any early returns - hooks must handle null supabase gracefully\n const {\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n isLoading,\n error,\n refetch\n } = useFileDisplay(\n table_name,\n record_id,\n organisation_id,\n category,\n { supabase: supabase || null }\n );\n \n // Use fileUrls map if available, otherwise use useFileUrl hook\n const displayOnlyFileUrlFromMap = displayOnlyFileReference ? fileUrls.get(displayOnlyFileReference.id) : null;\n const displayOnlyFileUrlHook = useFileUrl(\n displayOnlyFileReference && !displayOnlyFileUrlFromMap ? displayOnlyFileReference : null,\n {\n supabase: supabase || null,\n organisation_id,\n autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference && !!supabase\n }\n );\n const displayOnlyFileUrl = displayOnlyFileUrlFromMap || displayOnlyFileUrlHook.url;\n\n // Handle displayOnly mode: select first file (prefer images) from all files\n useEffect(() => {\n if (displayOnly && !category && fileReferences.length > 0) {\n // Prefer image files\n const imageFiles = fileReferences.filter(f => \n f.file_metadata.fileType?.startsWith('image/')\n );\n const targetFile = imageFiles.length > 0 ? imageFiles[0] : fileReferences[0];\n setDisplayOnlyFileReference(targetFile);\n // URL generation is handled by useFileUrl hook or fileUrls map\n } else {\n // Clear displayOnly files when not in displayOnly mode or when category is specified\n setDisplayOnlyFileReference(null);\n }\n }, [displayOnly, category, fileReferences, fileUrls]);\n\n // Early return check after all hooks are called\n if (!supabase) {\n return (\n <figure className={className} title=\"Error\">\n <p className={getFallbackClasses(fallbackSize || 'md')}>\n Supabase client not available in authenticated context\n </p>\n </figure>\n );\n }\n\n // Delete operation - implementation pending\n const handleDelete = async () => {\n // TODO: Implement delete via FileReferenceService when delete functionality is needed\n };\n\n // Determine final file reference and URL based on mode\n let finalFileReference = fileReference;\n let finalFileUrl = fileUrl;\n let finalFileReferences = fileReferences;\n let finalFileCount = fileCount;\n let finalIsLoading = isLoading;\n let finalError = error;\n\n if (displayOnly && !category) {\n // DisplayOnly mode: use state-managed file reference and URL\n finalFileReference = displayOnlyFileReference;\n finalFileUrl = displayOnlyFileUrl;\n finalFileReferences = displayOnlyFileReference ? [displayOnlyFileReference] : [];\n finalFileCount = displayOnlyFileReference ? 1 : 0;\n // Include URL loading state in overall loading state\n if (!displayOnlyFileUrlFromMap) {\n finalIsLoading = isLoading || displayOnlyFileUrlHook.isLoading;\n finalError = error || displayOnlyFileUrlHook.error;\n }\n }\n\n return (\n <FileDisplayContent\n isLoading={finalIsLoading}\n error={finalError}\n fileUrl={finalFileUrl}\n fileReference={finalFileReference}\n fileReferences={finalFileReferences}\n fileUrls={fileUrls}\n fileCount={finalFileCount}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n onDelete={showDelete ? handleDelete : undefined}\n clearError={refetch}\n organisation_id={organisation_id}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n\n/**\n * Component for displaying file references with context-awareness\n * \n * This component is context-aware and automatically detects whether it's being used\n * in a public or authenticated context. It fetches and displays files from storage.\n * \n * The component automatically detects context and uses:\n * - PublicPageProvider context for public pages\n * - UnifiedAuthProvider context for authenticated pages\n * \n * @param props - File display configuration\n * @param props.displayOnly - Display only a single file instead of all files. Uses first file (prefers images) from all files, without category filtering. When true:\n * - **Image files**: Renders a simplified image-only display without metadata or wrapper divs\n * - **Non-image files** (PDFs, Word docs, Excel files, etc.): Renders as clickable links that open in a new tab with document icon, filename, and external link icon. Links include proper security attributes (`rel=\"noopener noreferrer\"`) and accessibility features (ARIA labels, keyboard navigation, visible focus states)\n * - If `showDelete={true}`, uses standard wrapper behavior instead of simplified display\n * @param props.category - Optional category filter. When specified, only displays files matching this category and uses single file display variant.\n * @returns React element with file display\n */\n/**\n * File display component.\n * Renders files from the file reference system with support for previews, downloads, and public/private access.\n * \n * @param props - File display configuration\n * @returns The rendered file display\n */\nexport function FileDisplay({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n imgClassName,\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSourceText,\n fallbackSize,\n enableChildren,\n showMetadata\n}: FileDisplayProps) {\n // Check which context we're in and route to the appropriate component\n const isPublicPage = useIsPublicPage();\n \n // If we're in a public page context, use the public component\n if (isPublicPage) {\n return (\n <FileDisplayPublic\n table_name={table_name}\n record_id={record_id}\n organisation_id={organisation_id}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n }\n\n // Otherwise, use the authenticated component\n // It will show an error if not in UnifiedAuthProvider\n return (\n <FileDisplayAuthenticated\n table_name={table_name}\n record_id={record_id}\n organisation_id={organisation_id}\n category={category}\n displayOnly={displayOnly}\n showDelete={showDelete}\n className={className}\n imgClassName={imgClassName}\n children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSourceText={fallbackSourceText}\n fallbackSize={fallbackSize}\n enableChildren={enableChildren}\n showMetadata={showMetadata}\n />\n );\n}\n","/**\n * @file Custom Hook for File URL Generation\n * @package @jmruthers/pace-core\n * @module Hooks/FileDisplay\n * \n * Extracts URL generation logic to eliminate duplication across FileDisplay components.\n * Handles both public and private file URL generation with proper error handling.\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { FileReference } from '../types/file-reference';\nimport { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useFileUrl');\n\n/**\n * Options for the useFileUrl hook.\n */\nexport interface UseFileUrlOptions {\n /** Organisation ID for signed URL generation */\n organisation_id: string | undefined;\n /** Supabase client instance */\n supabase: SupabaseClient | null;\n /** Whether to auto-load URLs on mount */\n autoLoad?: boolean;\n}\n\nexport interface UseFileUrlReturn {\n /** Generated URL for the file reference */\n url: string | null;\n /** Whether URL is currently being generated */\n isLoading: boolean;\n /** Error if URL generation failed */\n error: Error | null;\n /** Manually trigger URL generation */\n loadUrl: () => Promise<void>;\n /** Clear the current URL and error */\n clear: () => void;\n}\n\n/**\n * Custom hook for generating file URLs (public or signed) for a single file reference\n * \n * @param fileReference - The file reference to generate URL for (null if no file)\n * @param options - Configuration options\n * @returns Hook return object with URL, loading state, and controls\n */\nexport function useFileUrl(\n fileReference: FileReference | null,\n options: UseFileUrlOptions\n): UseFileUrlReturn {\n const { organisation_id, supabase, autoLoad = true } = options;\n \n const [url, setUrl] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n const fileReferenceIdRef = useRef<string | null>(null);\n\n const loadUrl = useCallback(async () => {\n if (!fileReference) {\n setUrl(null);\n setIsLoading(false);\n setError(null);\n return;\n }\n\n if (!supabase) {\n setUrl(null);\n setIsLoading(false);\n setError(new Error('Supabase client is required for URL generation'));\n return;\n }\n\n // Skip if already loading or URL already exists for this file\n if (isLoading || (url && fileReferenceIdRef.current === fileReference.id)) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n fileReferenceIdRef.current = fileReference.id;\n\n try {\n let generatedUrl: string | null = null;\n\n if (fileReference.is_public) {\n // Public files: generate public URL\n generatedUrl = getPublicUrl(supabase, fileReference.file_path, true);\n } else {\n // Private files: generate signed URL\n const signedUrlResult = await getSignedUrl(supabase, fileReference.file_path, {\n appName: 'file-reference',\n orgId: organisation_id,\n expiresIn: 3600\n });\n generatedUrl = signedUrlResult?.url || null;\n }\n\n setUrl(generatedUrl);\n setError(null);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to generate file URL');\n setError(error);\n setUrl(null);\n log.error('Error generating URL:', error);\n } finally {\n setIsLoading(false);\n }\n }, [fileReference, supabase, organisation_id, isLoading, url]);\n\n const clear = useCallback(() => {\n setUrl(null);\n setError(null);\n setIsLoading(false);\n fileReferenceIdRef.current = null;\n }, []);\n\n // Auto-load URL when fileReference changes\n useEffect(() => {\n if (autoLoad) {\n // Reset URL when file reference changes\n if (fileReferenceIdRef.current !== fileReference?.id) {\n setUrl(null);\n setError(null);\n }\n \n if (fileReference && !url && !isLoading) {\n loadUrl();\n }\n }\n }, [fileReference?.id, autoLoad, loadUrl, url, isLoading]);\n\n return {\n url,\n isLoading,\n error,\n loadUrl,\n clear\n };\n}\n\n","// File Reference React Hooks\n// Provides React hooks for managing file references\n\nimport { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { \n FileReference, \n FileUploadOptions, \n FileReferenceService,\n FileUploadResult,\n FileCategory\n} from '../types/file-reference';\nimport { createFileReferenceService, uploadFileWithReference } from '../utils/file-reference';\nimport { getPublicUrl, getSignedUrl, generateFileUrlsBatch } from '../utils/storage/helpers';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useFileReference');\n\ntype UrlRefreshCallback = () => void;\n\n/**\n * Shared interval manager to avoid spawning multiple intervals for the same file reference\n */\nconst urlRefreshManager = {\n subscriptions: new Map<string, { callbacks: Set<UrlRefreshCallback>; intervalId: NodeJS.Timeout | null }>(),\n\n subscribe(key: string, callback: UrlRefreshCallback) {\n let entry = this.subscriptions.get(key);\n if (!entry) {\n entry = { callbacks: new Set(), intervalId: null };\n this.subscriptions.set(key, entry);\n }\n\n entry.callbacks.add(callback);\n\n if (!entry.intervalId) {\n entry.intervalId = setInterval(() => {\n entry?.callbacks.forEach((cb) => cb());\n }, 55 * 60 * 1000);\n }\n\n return () => {\n this.unsubscribe(key, callback);\n };\n },\n\n unsubscribe(key: string, callback: UrlRefreshCallback) {\n const entry = this.subscriptions.get(key);\n if (!entry) return;\n\n entry.callbacks.delete(callback);\n\n if (entry.callbacks.size === 0) {\n if (entry.intervalId) {\n clearInterval(entry.intervalId);\n }\n this.subscriptions.delete(key);\n }\n }\n};\n\n/**\n * Hook for managing file references.\n * Provides file upload, retrieval, and URL generation functionality.\n * \n * @param supabase - Supabase client instance\n * @returns File reference service with upload, get, and URL methods\n */\nexport function useFileReference(supabase: SupabaseClient) {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const service = useMemo(() => createFileReferenceService(supabase), [supabase]);\n\n const uploadFile = useCallback(async (options: FileUploadOptions, file: File): Promise<FileUploadResult | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n const result = await uploadFileWithReference(supabase, options, file);\n return result;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Upload failed';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [supabase]);\n\n const getFileReference = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileReference(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file reference';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileUrl = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<string | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileUrl(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file URL';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getSignedUrl = useCallback(async (table_name: string, record_id: string, organisation_id: string, expires_in?: number): Promise<string | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getSignedUrl(table_name, record_id, organisation_id, expires_in);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get signed URL';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const updateFileReference = useCallback(async (id: string, updates: Partial<FileReference>): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.updateFileReference(id, updates);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to update file reference';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const deleteFileReference = useCallback(async (table_name: string, record_id: string, organisation_id: string, delete_file?: boolean): Promise<boolean> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.deleteFileReference(table_name, record_id, organisation_id, delete_file);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to delete file reference';\n setError(errorMessage);\n return false;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const listFileReferences = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<FileReference[]> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.listFileReferences(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to list file references';\n setError(errorMessage);\n return [];\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileCount = useCallback(async (table_name: string, record_id: string, organisation_id: string): Promise<number> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileCount(table_name, record_id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file count';\n setError(errorMessage);\n return 0;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFileReferenceById = useCallback(async (id: string, organisation_id: string): Promise<FileReference | null> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFileReferenceById(id, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get file reference by ID';\n setError(errorMessage);\n return null;\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const getFilesByCategory = useCallback(async (\n table_name: string, \n record_id: string, \n category: FileCategory, \n organisation_id: string\n ): Promise<FileReference[]> => {\n setIsLoading(true);\n setError(null);\n \n try {\n return await service.getFilesByCategory(table_name, record_id, category, organisation_id);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to get files by category';\n setError(errorMessage);\n return [];\n } finally {\n setIsLoading(false);\n }\n }, [service]);\n\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n return {\n isLoading,\n error,\n uploadFile,\n getFileReference,\n getFileReferenceById,\n getFileUrl,\n getSignedUrl,\n updateFileReference,\n deleteFileReference,\n listFileReferences,\n getFilesByCategory,\n getFileCount,\n clearError\n };\n}\n\nexport function useFileReferenceForRecord(\n supabase: SupabaseClient,\n table_name: string,\n record_id: string,\n organisation_id: string\n) {\n const {\n isLoading,\n error,\n getFileUrl,\n getFileReference,\n updateFileReference,\n deleteFileReference,\n listFileReferences,\n getFileCount,\n clearError\n } = useFileReference(supabase);\n\n const [fileUrl, setFileUrl] = useState<string | null>(null);\n const [fileReference, setFileReference] = useState<FileReference | null>(null);\n const [fileReferences, setFileReferences] = useState<FileReference[]>([]);\n const [fileCount, setFileCount] = useState<number>(0);\n const refreshSubscriptionRef = useRef<(() => void) | null>(null);\n\n const loadFileReference = useCallback(async () => {\n const reference = await getFileReference(table_name, record_id, organisation_id);\n setFileReference(reference);\n return reference;\n }, [getFileReference, table_name, record_id, organisation_id]);\n\n const loadFileUrl = useCallback(async () => {\n const url = await getFileUrl(table_name, record_id, organisation_id);\n setFileUrl(url);\n return url;\n }, [getFileUrl, table_name, record_id, organisation_id]);\n\n const loadFileReferences = useCallback(async () => {\n const references = await listFileReferences(table_name, record_id, organisation_id);\n setFileReferences(references);\n return references;\n }, [listFileReferences, table_name, record_id, organisation_id]);\n\n const loadFileCount = useCallback(async () => {\n const count = await getFileCount(table_name, record_id, organisation_id);\n setFileCount(count);\n return count;\n }, [getFileCount, table_name, record_id, organisation_id]);\n\n const deleteFile = useCallback(async (delete_file?: boolean) => {\n const success = await deleteFileReference(table_name, record_id, organisation_id, delete_file);\n if (success) {\n setFileReference(null);\n setFileUrl(null);\n await loadFileCount();\n }\n return success;\n }, [deleteFileReference, table_name, record_id, organisation_id, loadFileCount]);\n\n // Auto-refresh signed URLs before expiration (refresh 5 minutes before 1 hour expiry)\n useEffect(() => {\n if (refreshSubscriptionRef.current) {\n refreshSubscriptionRef.current();\n refreshSubscriptionRef.current = null;\n }\n\n if (!fileReference || fileReference.is_public) {\n // Only refresh private files (signed URLs expire)\n return;\n }\n\n // Refresh signed URL 5 minutes before expiration (55 minutes into the 1-hour expiry)\n const key = `${fileReference.table_name}:${fileReference.record_id}:${organisation_id}`;\n refreshSubscriptionRef.current = urlRefreshManager.subscribe(key, () => {\n loadFileUrl();\n });\n\n return () => {\n if (refreshSubscriptionRef.current) {\n refreshSubscriptionRef.current();\n refreshSubscriptionRef.current = null;\n }\n };\n }, [fileReference, loadFileUrl, organisation_id]);\n\n return {\n isLoading,\n error,\n fileUrl,\n fileReference,\n fileReferences,\n fileCount,\n loadFileReference,\n loadFileUrl,\n loadFileReferences,\n loadFileCount,\n deleteFile,\n updateFileReference,\n clearError\n };\n}\n\n/**\n * Hook for getting a file reference by ID\n */\nexport function useFileReferenceById(\n supabase: SupabaseClient,\n fileReferenceId: string | null,\n organisationId: string | null\n) {\n const {\n isLoading,\n error,\n getFileReferenceById,\n clearError\n } = useFileReference(supabase);\n\n const [fileReference, setFileReference] = useState<FileReference | null>(null);\n const [fileUrl, setFileUrl] = useState<string | null>(null);\n\n const loadFileReference = useCallback(async () => {\n if (!fileReferenceId || !organisationId) {\n setFileReference(null);\n setFileUrl(null);\n return null;\n }\n\n const reference = await getFileReferenceById(fileReferenceId, organisationId);\n setFileReference(reference);\n return reference;\n }, [getFileReferenceById, fileReferenceId, organisationId]);\n\n useEffect(() => {\n loadFileReference();\n }, [loadFileReference]);\n\n // Load URL when file reference changes\n useEffect(() => {\n if (!fileReference || !fileReferenceId || !organisationId) {\n setFileUrl(null);\n return;\n }\n\n const loadUrl = async () => {\n try {\n const service = createFileReferenceService(supabase);\n const url = await service.getFileUrl(\n fileReference.table_name,\n fileReference.record_id,\n organisationId\n );\n setFileUrl(url);\n } catch (error) {\n // Silently fail - component will handle missing URL\n setFileUrl(null);\n }\n };\n\n loadUrl();\n }, [fileReference, fileReferenceId, organisationId, supabase]);\n\n return {\n isLoading,\n error,\n fileReference,\n fileUrl,\n loadFileReference,\n clearError\n };\n}\n\n/**\n * Convenience hook for getting files by category with automatic URL loading.\n * \n * This hook wraps useFileReference().getFilesByCategory and automatically:\n * - Loads file references filtered by category\n * - Generates URLs for all files (public URLs for public files, signed URLs for private files)\n * - Manages state for fileReferences and fileUrls\n * - Auto-refetches when table_name, record_id, category, or organisation_id changes\n * \n * Use this hook when you need files by category with their URLs ready to display.\n * For more control, use useFileReference() directly and manage URLs yourself.\n */\nexport function useFilesByCategory(\n supabase: SupabaseClient,\n table_name: string,\n record_id: string,\n category: FileCategory | null,\n organisation_id: string | null\n) {\n const {\n isLoading,\n error,\n getFilesByCategory,\n clearError\n } = useFileReference(supabase);\n\n const [fileReferences, setFileReferences] = useState<FileReference[]>([]);\n const [fileUrls, setFileUrls] = useState<Map<string, string>>(new Map());\n\n const loadFiles = useCallback(async () => {\n if (!category || !organisation_id) {\n setFileReferences([]);\n setFileUrls(new Map());\n return [];\n }\n\n const files = await getFilesByCategory(table_name, record_id, category, organisation_id);\n setFileReferences(files);\n\n // Load URLs for all files in batch\n const urlMap = await generateFileUrlsBatch(supabase, files, {\n appName: 'file-reference',\n orgId: organisation_id,\n expiresIn: 3600\n });\n \n setFileUrls(urlMap);\n return files;\n }, [table_name, record_id, category, organisation_id, supabase, getFilesByCategory]);\n\n useEffect(() => {\n loadFiles();\n }, [loadFiles]);\n\n return {\n isLoading,\n error,\n fileReferences,\n fileUrls,\n loadFiles,\n clearError\n };\n}\n\n// Type definitions for the hooks\nexport type UseFileReferenceOptions = {\n table_name: string;\n record_id: string;\n organisation_id: string;\n};\n\n/**\n * Return value of the useFileReference hook.\n */\nexport type UseFileReferenceReturn = {\n isLoading: boolean;\n error: string | null;\n uploadFile: (options: FileUploadOptions, file: File) => Promise<FileUploadResult | null>;\n getFileReference: (table_name: string, record_id: string, organisation_id: string) => Promise<FileReference | null>;\n getFileUrl: (table_name: string, record_id: string, organisation_id: string) => Promise<string | null>;\n getSignedUrl: (table_name: string, record_id: string, organisation_id: string, expires_in?: number) => Promise<string | null>;\n updateFileReference: (id: string, updates: Partial<FileReference>) => Promise<FileReference | null>;\n deleteFileReference: (table_name: string, record_id: string, organisation_id: string, delete_file?: boolean) => Promise<boolean>;\n listFileReferences: (table_name: string, record_id: string, organisation_id: string) => Promise<FileReference[]>;\n getFileCount: (table_name: string, record_id: string, organisation_id: string) => Promise<number>;\n clearError: () => void;\n};\n\n/**\n * Return value of the useFileReferenceForRecord hook.\n */\nexport type UseFileReferenceForRecordReturn = {\n isLoading: boolean;\n error: string | null;\n fileUrl: string | null;\n fileReference: FileReference | null;\n fileReferences: FileReference[];\n fileCount: number;\n loadFileReference: () => Promise<FileReference | null>;\n loadFileUrl: () => Promise<string | null>;\n loadFileReferences: () => Promise<FileReference[]>;\n loadFileCount: () => Promise<number>;\n deleteFile: (delete_file?: boolean) => Promise<boolean>;\n updateFileReference: (id: string, updates: Partial<FileReference>) => Promise<FileReference | null>;\n clearError: () => void;\n};\n","/**\n * @file Avatar Component\n * @package @jmruthers/pace-core\n * @module Components\n * @since 0.1.0\n *\n * A simple and accessible avatar component for displaying user profile images or initials.\n * Supports three approaches for image display:\n * - File reference props (uses FileDisplay for Supabase storage)\n * - File ID (uses file reference lookup)\n * - Direct URL (simple img tag for public images)\n *\n * Features:\n * - Circular avatar display\n * - Image, fallback, and initials support\n * - Customizable size and style\n * - Keyboard and screen reader accessible\n * - Graceful fallback for missing images\n *\n * @example\n * ```tsx\n * // Avatar with direct URL\n * <Avatar \n * src=\"/user.jpg\" \n * alt=\"User\" \n * fallback=\"AB\"\n * />\n *\n * // Avatar with file reference props\n * <Avatar\n * table_name=\"user_profiles\"\n * record_id={userId}\n * organisation_id={orgId}\n * category={FileCategory.PROFILE_PHOTOS}\n * fallback=\"JD\"\n * />\n *\n * // Avatar with file ID\n * <Avatar\n * fileId={fileReferenceId}\n * organisation_id={orgId}\n * fallback=\"JD\"\n * />\n *\n * // Avatar with fallback only\n * <Avatar fallback=\"JD\" />\n * ```\n *\n * @accessibility\n * - Uses alt text for images\n * - Fallback content is accessible to screen readers\n * - Keyboard focusable and navigable\n */\n\nimport * as React from \"react\"\nimport { FileCategory } from \"../../types/file-reference\"\nimport { FileDisplay } from \"../FileDisplay/FileDisplay\"\nimport { useFileReferenceById } from \"../../hooks/useFileReference\"\nimport { useUnifiedAuth } from \"../../providers/services/UnifiedAuthProvider\"\nimport { cn } from \"../../utils/core/cn\"\n\n/**\n * Size variants for avatar\n */\nconst sizeClasses = {\n xs: 'size-4 text-xs',\n sm: 'size-6 text-sm',\n md: 'size-10 text-base',\n lg: 'size-12 text-lg',\n xl: 'size-16 text-xl',\n '2xl': 'size-20 text-2xl'\n}\n\ninterface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {\n // File reference approach (uses FileDisplay)\n table_name?: string\n record_id?: string\n organisation_id?: string\n category?: FileCategory\n \n // OR file ID approach (uses file reference lookup)\n fileId?: string\n \n // OR direct URL approach (simple <img> tag)\n src?: string\n alt?: string\n \n // Fallback (always required)\n fallback: string\n \n // Styling\n className?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n}\n\n/**\n * Avatar component for displaying user profile images or initials\n */\nconst Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(\n ({ \n table_name,\n record_id,\n organisation_id,\n category,\n fileId,\n src,\n alt,\n fallback,\n className,\n size = 'md',\n ...props \n }, ref) => {\n const [imageError, setImageError] = React.useState(false)\n const { supabase } = useUnifiedAuth()\n \n // For fileId approach, get file reference and URL\n // Only fetch if we have all required values\n const canFetchFileId = Boolean(fileId && organisation_id && supabase)\n const { fileReference, fileUrl: fileIdUrl, isLoading: fileIdLoading } = useFileReferenceById(\n supabase || ({} as any), // Hook requires SupabaseClient, but we check canFetchFileId before using result\n canFetchFileId ? fileId! : null,\n canFetchFileId ? organisation_id! : null\n )\n \n // Determine which approach to use\n const hasFileProps = table_name && record_id && organisation_id && category && supabase\n const hasFileId = canFetchFileId && fileIdUrl && !fileIdLoading\n const hasDirectUrl = src && !imageError\n \n // Determine if we should show fallback\n const showFallback = !hasDirectUrl && (!hasFileProps && !hasFileId) || imageError || (canFetchFileId && !fileIdUrl && !fileIdLoading)\n \n // Base classes for avatar container\n const baseClasses = size === 'md' \n ? \" size-10 overflow-hidden rounded-full\"\n : ` ${sizeClasses[size]} overflow-hidden rounded-full`\n \n // Fallback classes (don't include className to avoid conflicts)\n const fallbackClasses = \"size-full grid place-items-center text-center text-sec-50 bg-sec-500\"\n \n // Image classes for direct URL and fileId approaches\n const imageClasses = \"object-cover size-full\"\n \n // Container classes (include className here for container styling)\n const containerClasses = cn(baseClasses, className)\n \n // Handle image error for direct URL\n const handleImageError = React.useCallback(() => {\n setImageError(true)\n }, [])\n \n // Reset error when src changes\n React.useEffect(() => {\n if (src) {\n setImageError(false)\n }\n }, [src])\n \n return (\n <figure\n ref={ref}\n className={containerClasses}\n {...props}\n >\n {showFallback ? (\n <figcaption className={fallbackClasses} aria-label={alt || fallback}>\n {fallback}\n </figcaption>\n ) : hasFileProps ? (\n // File reference props approach - use FileDisplay\n <FileDisplay\n table_name={table_name!}\n record_id={record_id!}\n organisation_id={organisation_id!}\n category={category!}\n displayOnly={true}\n showFallback={true}\n fallbackText={fallback}\n className={cn(imageClasses, className)}\n />\n ) : hasFileId && fileIdUrl ? (\n // File ID approach - use img tag with fetched URL\n <img\n src={fileIdUrl}\n alt={alt || fallback}\n className={imageClasses}\n onError={handleImageError}\n />\n ) : hasDirectUrl ? (\n // Direct URL approach - use img tag\n <img\n src={src}\n alt={alt || fallback}\n className={imageClasses}\n onError={handleImageError}\n />\n ) : (\n // Fallback if nothing else works\n <figcaption className={fallbackClasses} aria-label={alt || fallback}>\n {fallback}\n </figcaption>\n )}\n </figure>\n )\n }\n)\n\nAvatar.displayName = \"Avatar\"\n\nexport { Avatar, type AvatarProps }\n","/**\n * @file Badge Component\n * @package @jmruthers/pace-core\n * @module Components\n * @since 0.1.0\n *\n * A small, non-interactive visual label component for displaying concise information\n * such as status indicators, tags, or labels. Acts as a visual alternative to buttons\n * for non-interactive content.\n *\n * Features:\n * - 27 combined variants (3 styles × 3 colors × 3 shades)\n * - Non-interactive by default (renders as <span>)\n * - Supports all pace-core color palettes (main, sec, acc)\n * - Customizable styling via className prop\n * - Accessible and screen reader friendly\n *\n * @example\n * ```tsx\n * // Basic badge with default variant\n * <Badge>New</Badge>\n *\n * // Badge with specific variant\n * <Badge variant=\"solid-main-normal\">Active</Badge>\n *\n * // Outline variant\n * <Badge variant=\"outline-sec-muted\">Pending</Badge>\n *\n * // Soft variant with accent color\n * <Badge variant=\"soft-acc-strong\">Featured</Badge>\n *\n * // Custom styling\n * <Badge variant=\"solid-main-normal\" className=\"px-4\">\n * Custom Badge\n * </Badge>\n * ```\n *\n * @accessibility\n * - Renders as semantic <span> element\n * - No focus styles (non-interactive by default)\n * - Screen reader friendly through semantic HTML\n * - Can be wrapped in interactive elements if needed\n */\n\nimport * as React from 'react';\nimport { cn } from '../../utils/core/cn';\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n/**\n * Badge variant type\n * Defines the visual style, color palette, and shade intensity of the badge.\n * Format: {style}-{color}-{shade}\n * - style: 'solid' | 'outline' | 'soft'\n * - color: 'main' | 'sec' | 'acc'\n * - shade: 'muted' | 'normal' | 'strong'\n */\nexport type BadgeVariant =\n | 'solid-main-muted' | 'solid-main-normal' | 'solid-main-strong'\n | 'solid-sec-muted' | 'solid-sec-normal' | 'solid-sec-strong'\n | 'solid-acc-muted' | 'solid-acc-normal' | 'solid-acc-strong'\n | 'outline-main-muted' | 'outline-main-normal' | 'outline-main-strong'\n | 'outline-sec-muted' | 'outline-sec-normal' | 'outline-sec-strong'\n | 'outline-acc-muted' | 'outline-acc-normal' | 'outline-acc-strong'\n | 'soft-main-muted' | 'soft-main-normal' | 'soft-main-strong'\n | 'soft-sec-muted' | 'soft-sec-normal' | 'soft-sec-strong'\n | 'soft-acc-muted' | 'soft-acc-normal' | 'soft-acc-strong';\n\n/**\n * Badge component props\n * Extends standard HTML span attributes with badge-specific styling options.\n * \n * @interface BadgeProps\n */\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Visual variant of the badge (style-color-shade) */\n variant?: BadgeVariant;\n}\n\n// ============================================================================\n// VARIANT CONFIGURATION\n// ============================================================================\n\n/**\n * Shade configuration mapping\n * Maps shade names to background, text, border, and outline text color shades\n */\nconst shadeConfig = {\n muted: {\n bg: 200,\n text: 600,\n border: 400,\n outlineText: 600,\n outlineBg: 100,\n },\n normal: {\n bg: 500,\n text: 50,\n border: 700,\n outlineText: 700,\n outlineBg: 200,\n },\n strong: {\n bg: 700,\n text: 50,\n border: 800,\n outlineText: 900,\n outlineBg: 400,\n },\n} as const;\n\ntype Shade = keyof typeof shadeConfig;\n\n/**\n * Color palette options\n */\nconst colors = ['main', 'sec', 'acc'] as const;\ntype Color = typeof colors[number];\n\n/**\n * Style options\n */\nconst styles = ['solid', 'outline', 'soft'] as const;\ntype Style = typeof styles[number];\n\n/**\n * Build variant class string for a given style, color, and shade\n * Generates classes programmatically from configuration\n */\nfunction buildVariantClasses(style: Style, color: Color, shade: Shade): string {\n const cfg = shadeConfig[shade];\n const parts: string[] = [];\n \n if (style === 'solid') {\n // Solid: flat background colors\n parts.push(`bg-${color}-${cfg.bg}`, `text-${color}-${cfg.text}`);\n } else if (style === 'outline') {\n // Outline: outlined with light background\n parts.push('outline outline-1 -outline-offset-1', `outline-${color}-${cfg.border}`, `bg-${color}-${cfg.outlineBg}`, `text-${color}-${cfg.outlineText}`);\n } else if (style === 'soft') {\n // Soft: uses shadow-badge-soft utility with colored shadows\n parts.push(\n `bg-${color}-${cfg.bg}`,\n 'shadow-badge-soft',\n `shadow-${color}-${cfg.bg}`,\n `text-${color}-${cfg.text}`,\n 'my-1', 'ml-1', 'mr-2', 'py-0', 'px-2'\n );\n }\n \n return parts.join(' ');\n}\n\n/**\n * Generate all class name patterns for Tailwind scanning\n * This ensures Tailwind can detect all dynamically generated classes\n * \n * Tailwind v4 content scanning: These classes are listed here so Tailwind\n * can detect them during content scanning, even when built dynamically.\n * \n * Classes used: shadow-badge-soft shadow-main-200 shadow-main-500 shadow-main-700\n * shadow-sec-200 shadow-sec-500 shadow-sec-700 shadow-acc-200 shadow-acc-500 shadow-acc-700\n */\nconst tailwindClassScan = [\n // Solid background classes\n 'bg-main-100', 'bg-main-600', 'bg-main-900',\n 'bg-sec-100', 'bg-sec-600', 'bg-sec-900',\n 'bg-acc-100', 'bg-acc-600', 'bg-acc-900',\n // Solid text classes\n 'text-main-50', 'text-main-900',\n 'text-sec-50', 'text-sec-900',\n 'text-acc-50', 'text-acc-900',\n // Outline classes\n 'outline outline-1',\n 'outline-main-400', 'outline-main-700', 'outline-main-800',\n 'outline-sec-400', 'outline-sec-700', 'outline-sec-800',\n 'outline-acc-400', 'outline-acc-700', 'outline-acc-800',\n // Outline background classes\n 'bg-main-100', 'bg-main-200', 'bg-main-300',\n 'bg-sec-100', 'bg-sec-200', 'bg-sec-300',\n 'bg-acc-100', 'bg-acc-200', 'bg-acc-300',\n // Outline text classes\n 'text-main-500', 'text-main-600', 'text-main-800',\n 'text-sec-500', 'text-sec-600', 'text-sec-800',\n 'text-acc-500', 'text-acc-600', 'text-acc-800',\n // Soft background classes (solid, no opacity)\n 'bg-main-200', 'bg-main-500', 'bg-main-700',\n 'bg-sec-200', 'bg-sec-500', 'bg-sec-700',\n 'bg-acc-200', 'bg-acc-500', 'bg-acc-700',\n // Soft shadow utility classes - CRITICAL: These must be detected by Tailwind\n 'shadow-badge-soft',\n 'shadow-main-200', 'shadow-main-500', 'shadow-main-700',\n 'shadow-sec-200', 'shadow-sec-500', 'shadow-sec-700',\n 'shadow-acc-200', 'shadow-acc-500', 'shadow-acc-700',\n // Soft margin/padding classes\n 'my-3', 'mx-3', 'py-0', 'px-2',\n] as const;\n\n/**\n * Generate all variant class combinations programmatically\n * Uses the configuration to build the lookup map dynamically\n */\nfunction generateVariantClasses(): Record<BadgeVariant, string> {\n const variantClasses = {} as Record<BadgeVariant, string>;\n \n for (const style of styles) {\n for (const color of colors) {\n for (const shade of Object.keys(shadeConfig) as Shade[]) {\n const variant = `${style}-${color}-${shade}` as BadgeVariant;\n variantClasses[variant] = buildVariantClasses(style, color, shade);\n }\n }\n }\n \n return variantClasses;\n}\n\n// Pre-generate all variant classes\nconst variantClassesMap = generateVariantClasses();\n\n// Ensure Tailwind detects shadow-badge-soft class\n// This string literal ensures Tailwind v4 content scanning includes the class\nconst _tailwindShadowDetection = 'shadow-badge-soft';\n\n// ============================================================================\n// CLASS GENERATION FUNCTION\n// ============================================================================\n\n/**\n * Get badge classes based on variant\n * \n * Variant format: {style}-{color}-{shade}\n * - style: solid (flat), outline (bordered), soft (blurred)\n * - color: main, sec, acc\n * - shade: muted (dark on light), normal (light on medium), strong (light on dark)\n */\nfunction getBadgeClasses(variant: BadgeVariant = 'solid-main-normal'): string {\n const baseClasses = 'text-balance rounded-2xl px-3 py-1 mr-1 text-xs font-medium transition-colors box-border';\n return `${baseClasses} ${variantClassesMap[variant]}`;\n}\n\n// ============================================================================\n// BADGE COMPONENT\n// ============================================================================\n\n/**\n * Badge Component\n * A small, non-interactive visual label for displaying concise information.\n * \n * @component\n * @example\n * ```tsx\n * // Default variant\n * <Badge>New</Badge>\n * \n * // Specific variant\n * <Badge variant=\"solid-main-normal\">Active</Badge>\n * \n * // Outline variant\n * <Badge variant=\"outline-sec-muted\">Pending</Badge>\n * \n * // Soft variant\n * <Badge variant=\"soft-acc-strong\">Featured</Badge>\n * ```\n */\nfunction Badge({ className, variant = 'solid-main-normal', ref, ...props }: BadgeProps & { ref?: React.Ref<HTMLSpanElement> }) {\n const isSoftVariant = variant.startsWith('soft-');\n \n if (isSoftVariant) {\n // For soft variants, we need both shadow-badge-soft and shadow color class\n // twMerge treats all shadow-* classes as conflicting, so we need to add them after merging\n const variantClasses = getBadgeClasses(variant);\n // Extract the shadow color class from variantClasses (e.g., shadow-main-200)\n const shadowColorMatch = variantClasses.match(/\\bshadow-(\\w+)-(\\d+)\\b/);\n const shadowColorClass = shadowColorMatch ? shadowColorMatch[0] : '';\n \n // Remove shadow classes from variantClasses to avoid twMerge conflicts\n const classesWithoutShadows = variantClasses\n .replace(/\\bshadow-badge-soft\\b/g, '')\n .replace(/\\bshadow-\\w+-\\d+\\b/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n \n // Merge non-shadow classes first, then append shadow classes to ensure both are present\n // shadow-badge-soft first (defines shape), then shadow color (defines color)\n const mergedClasses = cn(classesWithoutShadows, className);\n const finalClasses = `${mergedClasses} shadow-badge-soft ${shadowColorClass}`.trim();\n \n return (\n <span\n ref={ref}\n className={finalClasses}\n {...props}\n />\n );\n }\n \n return (\n <span\n ref={ref}\n className={cn(getBadgeClasses(variant), className)}\n {...props}\n />\n );\n}\n\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Badge };\n\n","/**\n * @file Switch Component\n * @package @jmruthers/pace-core\n * @module Components/Switch\n * @since 0.5.67\n * \n * A toggle switch component built on Radix UI primitives.\n * Provides an accessible, keyboard-navigable switch for boolean states.\n * \n * Features:\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Space/Enter)\n * - Focus visible indicators\n * - Disabled state support\n * - Smooth animations\n * - Tailwind v4 compatible\n * - Theme-aware colors\n * \n * @example\n * ```tsx\n * import { Switch } from '@jmruthers/pace-core';\n * \n * function Example() {\n * const [checked, setChecked] = React.useState(false);\n * \n * return (\n * <>\n * <Switch \n * checked={checked} \n * onCheckedChange={setChecked}\n * id=\"notifications\"\n * />\n * <label htmlFor=\"notifications\">\n * Enable notifications\n * </label>\n * </>\n * );\n * }\n * ```\n * \n * @example With Form\n * ```tsx\n * import { Switch, Label } from '@jmruthers/pace-core';\n * \n * function FormExample() {\n * return (\n * <>\n * <Switch id=\"terms\" />\n * <Label htmlFor=\"terms\">\n * I agree to the terms and conditions\n * </Label>\n * </>\n * );\n * }\n * ```\n * \n * @example Disabled State\n * ```tsx\n * <Switch disabled checked />\n * ```\n * \n * @accessibility\n * - Uses Radix UI's accessible switch primitive\n * - Proper keyboard navigation (Space to toggle)\n * - Screen reader announcements for state changes\n * - Focus visible styles for keyboard users\n * - ARIA attributes handled automatically\n */\n\nimport * as React from \"react\";\nimport * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport { cn } from \"../../utils/core/cn\";\n\n/**\n * Switch component props\n * Extends all props from Radix UI Switch.Root\n */\nexport interface SwitchProps\n extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {\n /**\n * Additional CSS classes to apply to the switch\n */\n className?: string;\n}\n\n/**\n * Switch component\n * \n * A toggle switch for boolean states. Built on Radix UI for accessibility.\n * \n * @component\n * @example\n * ```tsx\n * <Switch checked={isEnabled} onCheckedChange={setIsEnabled} />\n * ```\n */\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitive.Root>,\n SwitchProps\n>(({ className, ...props }, ref) => (\n <SwitchPrimitive.Root\n className={cn(\n // Base styles\n \"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full\",\n // Border\n \"border-2 border-transparent\",\n // Transitions\n \"transition-colors\",\n // Focus styles\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600\",\n \"focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n // State-based colors (using theme variables)\n \"data-[state=checked]:bg-main-600\",\n \"data-[state=unchecked]:bg-sec-200\",\n className\n )}\n {...props}\n ref={ref}\n >\n <SwitchPrimitive.Thumb\n className={cn(\n // Base styles\n \"pointer-events-none block size-5 rounded-full\",\n // Background and shadow\n \"bg-background shadow-lg ring-0\",\n // Transition\n \"transition-transform\",\n // State-based position\n \"data-[state=checked]:translate-x-5\",\n \"data-[state=unchecked]:translate-x-0\"\n )}\n />\n </SwitchPrimitive.Root>\n));\n\nSwitch.displayName = SwitchPrimitive.Root.displayName;\n\nexport { Switch };\n","/**\n * @file Tabs Component System\n * @package @jmruthers/pace-core\n * @module Components/Tabs\n * @since 0.5.141\n *\n * A comprehensive tabs component system built on top of Radix UI primitives.\n * Provides accessible tabbed interfaces with keyboard navigation and ARIA support.\n *\n * Features:\n * - Controlled and uncontrolled modes\n * - Keyboard navigation (arrow keys)\n * - Accessible ARIA attributes\n * - Customizable styling via className\n * - Support for icons in triggers\n * - Compound component pattern\n *\n * @example\n * ```tsx\n * // Basic tabs\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">Content 1</TabsContent>\n * <TabsContent value=\"tab2\">Content 2</TabsContent>\n * </Tabs>\n * \n * // Controlled tabs\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"transport\">\n * <Plane size={16} /> Transport\n * </TabsTrigger>\n * <TabsTrigger value=\"accommodation\">\n * <Building size={16} /> Accommodation\n * </TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"transport\">\n * <TransportPlanningView />\n * </TabsContent>\n * <TabsContent value=\"accommodation\">\n * <AccommodationPlanningView />\n * </TabsContent>\n * </Tabs>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Arrow keys, Home, End)\n * - Screen reader support with proper ARIA attributes\n * - Focus management\n * - Tab panel association\n */\n\nimport * as React from 'react';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cn } from '../../utils/core/cn';\nimport { Button, type ButtonProps } from '../Button/Button';\n\n// ============================================================================\n// TABS ROOT COMPONENT\n// ============================================================================\n\nexport interface TabsProps extends TabsPrimitive.TabsProps {}\n\n/**\n * Tabs root component\n * Provides the context for tab navigation and state management\n * \n * @component\n * @example\n * ```tsx\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>...</TabsList>\n * <TabsContent value=\"tab1\">...</TabsContent>\n * </Tabs>\n * ```\n */\nconst Tabs = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Root>,\n TabsProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Root asChild {...props}>\n <section ref={ref} className={className}>\n {children}\n </section>\n </TabsPrimitive.Root>\n));\n\nTabs.displayName = TabsPrimitive.Root.displayName || 'Tabs';\n\n// ============================================================================\n// TABS LIST COMPONENT\n// ============================================================================\n\nexport interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> {}\n\n/**\n * TabsList component\n * Container for tab triggers\n * \n * @component\n * @example\n * ```tsx\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n * </TabsList>\n * ```\n */\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.List asChild {...props}>\n <nav\n ref={ref}\n className={cn(\n 'mb-0',\n className\n )}\n >\n {children}\n </nav>\n </TabsPrimitive.List>\n));\n\nTabsList.displayName = TabsPrimitive.List.displayName || 'TabsList';\n\n// ============================================================================\n// TABS TRIGGER COMPONENT\n// ============================================================================\n\nexport interface TabsTriggerProps \n extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'asChild'>,\n Pick<ButtonProps, 'variant' | 'size'> {}\n\n/**\n * TabsTrigger component\n * Individual tab button that activates a tab panel\n * \n * Uses Button component internally, allowing Button props (variant, size) to be passed through.\n * \n * @component\n * @example\n * ```tsx\n * <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n * \n * // With icon\n * <TabsTrigger value=\"transport\">\n * <Plane size={16} /> Transport\n * </TabsTrigger>\n * \n * // With Button variant\n * <TabsTrigger value=\"tab1\" variant=\"outline\" size=\"sm\">\n * Tab 1\n * </TabsTrigger>\n * ```\n */\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, variant, size, children, ...props }, ref) => {\n return (\n <TabsPrimitive.Trigger asChild {...props}>\n <Button\n ref={ref}\n variant={variant}\n size={size}\n className={cn(\n 'rounded-b-none',\n 'data-[state=active]:bg-main-50 data-[state=active]:text-main-950 data-[state=active]:border-t-1 data-[state=active]:border-x-1 data-[state=active]:shadow-md',\n 'data-[state=inactive]:bg-main-300 data-[state=inactive]:text-main-800 ',\n 'data-[state=inactive]:hover:bg-acc-400',\n className\n )}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n});\n\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName || 'TabsTrigger';\n\n// ============================================================================\n// TABS CONTENT COMPONENT\n// ============================================================================\n\nexport interface TabsContentProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> {}\n\n/**\n * TabsContent component\n * Container for tab panel content\n * \n * @component\n * @example\n * ```tsx\n * <TabsContent value=\"tab1\">\n * <section>Content for tab 1</section>\n * </TabsContent>\n * ```\n */\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n TabsContentProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Content asChild {...props}>\n <aside\n ref={ref}\n className={cn(\n 'focus-visible:outline-none focus-visible:bg-main-300',\n className\n )}\n >\n {children}\n </aside>\n </TabsPrimitive.Content>\n));\n\nTabsContent.displayName = TabsPrimitive.Content.displayName || 'TabsContent';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n\n","/**\n * @file Calendar Component\n * @package @jmruthers/pace-core\n * @module Components/Calendar\n * @since 0.5.141\n *\n * A date picker calendar component built on react-day-picker.\n * Provides accessible date selection with keyboard navigation and ARIA support.\n *\n * Features:\n * - Single, range, and multiple date selection modes\n * - Date disabling (past dates, weekends, etc.)\n * - Localization support (defaults to Australian locale with Monday as first day of week)\n * - Keyboard navigation\n * - Accessible date selection\n * - Customizable styling\n *\n * @example\n * ```tsx\n * // Single date selection\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * />\n * \n * // Date range selection\n * <Calendar\n * mode=\"range\"\n * selected={dateRange}\n * onSelect={setDateRange}\n * />\n * \n * // Multiple date selection\n * <Calendar\n * mode=\"multiple\"\n * selected={dates}\n * onSelect={setDates}\n * />\n * \n * // With disabled dates\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * disabled={(date) => date < new Date()}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation (Arrow keys, Page Up/Down, Home, End)\n * - Screen reader support with proper ARIA attributes\n * - Focus management\n * - Date announcements\n */\n\nimport * as React from 'react';\nimport { \n DayPicker, \n type DayPickerProps,\n useDayPicker,\n type DayProps,\n type MonthsProps,\n type DateRange,\n} from 'react-day-picker';\nimport { enAU } from 'date-fns/locale';\nimport { cn } from '../../utils/core/cn';\n\n// Define custom types for components that don't have exported types\ntype MonthGridProps = React.TableHTMLAttributes<HTMLTableElement>;\ntype WeekdaysProps = React.HTMLAttributes<HTMLTableRowElement> & {\n children?: React.ReactNode;\n};\ntype MonthProps = {\n calendarMonth: { date: Date };\n displayIndex: number;\n className?: string;\n children?: React.ReactNode;\n};\ntype RootProps = {\n children?: React.ReactNode;\n rootRef?: React.Ref<HTMLDivElement>;\n className?: string;\n style?: React.CSSProperties;\n};\n\n// ============================================================================\n// CALENDAR COMPONENT\n// ============================================================================\n\n/**\n * Props for the Calendar component.\n * Extends DayPickerProps with pace-core specific customizations.\n */\nexport interface CalendarProps extends Omit<DayPickerProps, 'className' | 'classNames' | 'styles' | 'onSelect'> {\n /**\n * Additional CSS classes to apply to the calendar table\n */\n className?: string;\n /**\n * Custom classNames for DayPicker sub-components\n */\n classNames?: DayPickerProps['classNames'];\n /**\n * Currently selected value; mirrors DayPicker's `selected` prop so callers\n * can control the selection state.\n */\n selected?: Date | Date[] | DateRange | undefined;\n /**\n * Date selection handler. Signature depends on mode:\n * - mode=\"single\": (date: Date | undefined) => void\n * - mode=\"range\": (range: { from: Date; to?: Date } | undefined) => void\n * - mode=\"multiple\": (dates: Date[]) => void\n */\n onSelect?: ((date: Date | undefined) => void) | ((range: { from: Date; to?: Date } | undefined) => void) | ((dates: Date[]) => void);\n}\n\ntype StoredRootProps = {\n className?: string;\n style?: React.CSSProperties;\n rootRef?: React.Ref<HTMLDivElement>;\n restProps?: React.HTMLAttributes<HTMLTableElement>;\n};\n\nconst assignToRef = <T,>(ref: React.Ref<T | null> | undefined, value: T | null) => {\n if (!ref) {\n return;\n }\n if (typeof ref === 'function') {\n ref(value);\n return;\n }\n (ref as React.MutableRefObject<T | null>).current = value;\n};\n\n/**\n * Calendar component\n * A flexible, accessible calendar component for date selection.\n * Built on react-day-picker with pace-core styling.\n * \n * Defaults to Australian locale (en-AU) with Monday as the first day of the week.\n * The locale can be overridden by passing a `locale` prop.\n * \n * Month navigation is automatically managed internally when `month` and `onMonthChange` props\n * are not provided. The displayed month will sync with the selected date when available,\n * or default to the current month. Navigation buttons (prev/next) work automatically.\n * \n * For controlled month state, pass `month` and `onMonthChange` props.\n * \n * @param props - Calendar configuration and styling\n * @param ref - Forwarded ref (not used directly, but maintained for API consistency)\n * @returns JSX.Element - The rendered calendar element\n * \n * @example\n * ```tsx\n * // Single date selection (uses default Australian locale)\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * />\n * \n * // With disabled dates\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * disabled={(date) => date < new Date()}\n * />\n * \n * // Override locale (e.g., US locale with Sunday as first day)\n * import { enUS } from 'date-fns/locale';\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * locale={enUS}\n * />\n * \n * // Controlled month state (optional - month is auto-managed if not provided)\n * const [month, setMonth] = useState(new Date());\n * <Calendar\n * mode=\"single\"\n * selected={date}\n * onSelect={setDate}\n * month={month}\n * onMonthChange={setMonth}\n * />\n * ```\n */\nconst Calendar = React.forwardRef<HTMLTableElement, CalendarProps>(\n ({ className, classNames, mode, components, locale, month: controlledMonth, onMonthChange: controlledOnMonthChange, onSelect, ...props }, ref) => {\n const tableRef = React.useRef<HTMLTableElement | null>(null);\n const setForwardedRef = React.useCallback(\n (node: HTMLTableElement | null) => {\n tableRef.current = node;\n if (!ref) {\n return;\n }\n if (typeof ref === 'function') {\n ref(node);\n } else {\n (ref as React.MutableRefObject<HTMLTableElement | null>).current = node;\n }\n },\n [ref]\n );\n \n // Store root props so we can re-apply them to the table element\n const rootPropsRef = React.useRef<StoredRootProps | null>(null);\n // Get selected from props to avoid TypeScript union type issues\n const selected = (props as any).selected;\n // Determine if we're in controlled or uncontrolled mode for month\n const isMonthControlled = controlledMonth !== undefined;\n \n // Internal state for uncontrolled month mode - always default to current month\n const [internalMonth, setInternalMonth] = React.useState<Date>(() => {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1);\n });\n \n // Use controlled month if provided, otherwise use internal state\n // Normalize month to first day of month to ensure consistency\n const month = React.useMemo(() => {\n const monthToUse = isMonthControlled ? controlledMonth : internalMonth;\n if (!monthToUse) {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1);\n }\n // Ensure month is normalized to first day\n const normalized = new Date(monthToUse.getFullYear(), monthToUse.getMonth(), 1);\n return normalized;\n }, [isMonthControlled, controlledMonth, internalMonth]);\n \n // Handler for month changes - must be stable reference\n const handleMonthChange = React.useCallback((newMonth: Date) => {\n if (!isMonthControlled) {\n setInternalMonth(newMonth);\n }\n controlledOnMonthChange?.(newMonth);\n }, [isMonthControlled, controlledOnMonthChange]);\n \n // Create a wrapped handler to ensure it's always a function\n const wrappedHandleMonthChange = React.useCallback((newMonth: Date) => {\n handleMonthChange(newMonth);\n }, [handleMonthChange]);\n \n // Removed mount logging - was for debugging only\n \n // Custom Root: capture provided props so we can attach them to the table directly\n const CustomRoot = React.memo(({ children, rootRef: dayPickerRootRef, ...rootProps }: RootProps) => {\n const {\n className: rootClassName,\n style: rootStyle,\n children: _ignoredChildren,\n ...restProps\n } = rootProps as React.HTMLAttributes<HTMLDivElement> & { children?: React.ReactNode };\n \n rootPropsRef.current = {\n className: rootClassName,\n style: rootStyle as React.CSSProperties | undefined,\n rootRef: dayPickerRootRef,\n restProps: restProps as React.HTMLAttributes<HTMLTableElement>,\n };\n return <>{children}</>;\n });\n CustomRoot.displayName = 'CustomRoot';\n \n // Custom Months: Remove wrapper div, return children directly\n const CustomMonths = React.memo(({ children }: MonthsProps) => {\n return <>{children}</>;\n });\n CustomMonths.displayName = 'CustomMonths';\n \n const CustomMonthGrid = React.forwardRef<HTMLTableElement, MonthGridProps>((props, forwardedRef) => {\n return <table ref={forwardedRef} {...props} />;\n });\n CustomMonthGrid.displayName = 'CustomMonthGrid';\n \n // Custom Month: inject caption + navigation directly inside the <table>\n const CustomMonth = React.memo(({ calendarMonth, displayIndex, className, children }: MonthProps) => {\n const { formatters, components, labels, classNames, previousMonth, nextMonth, goToMonth } = useDayPicker();\n const caption = formatters.formatCaption(calendarMonth.date, {});\n const Chevron = components?.Chevron;\n \n const childrenArray = React.Children.toArray(children);\n const monthGridIndex = childrenArray.findIndex((child: any) => {\n if (!React.isValidElement(child)) return false;\n const childType = child.type as any;\n return (typeof childType === 'function' && childType.displayName === 'MonthGrid') ||\n child.type === 'table';\n });\n \n return (\n <>\n {childrenArray.map((child, index) => {\n if (React.isValidElement(child) && (child.type as any)?.displayName === 'MonthCaption') {\n return null;\n }\n \n if (index === monthGridIndex && React.isValidElement(child)) {\n const monthGridChild = child as React.ReactElement<MonthGridProps>;\n const applyRootProps = displayIndex === 0 && index === monthGridIndex;\n const storedRootProps = applyRootProps ? rootPropsRef.current : null;\n \n const { children: monthGridChildren, className: monthGridClassName, style: monthGridStyle, ...monthGridRest } =\n monthGridChild.props as React.TableHTMLAttributes<HTMLTableElement>;\n \n const mergedClassName = cn(\n 'w-full border-collapse rounded-md border border-sec-200 bg-background',\n applyRootProps ? storedRootProps?.className : undefined,\n className,\n monthGridClassName\n );\n \n const mergedStyle = {\n ...(applyRootProps ? storedRootProps?.style ?? {} : {}),\n ...(monthGridStyle ?? {}),\n };\n \n const tableProps: React.TableHTMLAttributes<HTMLTableElement> = {\n ...(applyRootProps && storedRootProps?.restProps ? storedRootProps.restProps : {}),\n ...monthGridRest,\n className: mergedClassName,\n ...(Object.keys(mergedStyle).length ? { style: mergedStyle } : {}),\n };\n \n if (mode && (tableProps as Record<string, unknown>)['data-mode'] === undefined) {\n (tableProps as Record<string, unknown>)['data-mode'] = mode;\n }\n \n const shouldAttachRef = applyRootProps || storedRootProps?.rootRef;\n const handleTableRef = shouldAttachRef\n ? (node: HTMLTableElement | null) => {\n if (applyRootProps) {\n setForwardedRef(node);\n }\n if (storedRootProps?.rootRef) {\n assignToRef(storedRootProps.rootRef as React.Ref<HTMLTableElement | null>, node);\n }\n }\n : undefined;\n \n const handlePreviousClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n if (!previousMonth) return;\n goToMonth(previousMonth);\n };\n \n const handleNextClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n if (!nextMonth) return;\n goToMonth(nextMonth);\n };\n \n const monthGridElement = monthGridChild as React.ReactElement<any> & {\n ref?: React.Ref<HTMLTableElement | null>;\n };\n const mergedRef =\n handleTableRef || monthGridElement.ref\n ? (node: HTMLTableElement | null) => {\n if (handleTableRef) {\n handleTableRef(node);\n }\n assignToRef(monthGridElement.ref as React.Ref<HTMLTableElement | null> | undefined, node);\n }\n : undefined;\n \n return React.cloneElement(\n monthGridElement,\n {\n key: child.key ?? `month-grid-${displayIndex}`,\n ...tableProps,\n ...(mergedRef ? { ref: mergedRef } : {}),\n },\n <>\n <caption className=\"relative\">\n <nav className=\"relative flex items-center justify-center gap-1\">\n <button\n type=\"button\"\n className={cn(\n 'h-7 w-7 bg-transparent p-0',\n 'inline-flex items-center justify-center rounded-md',\n 'hover:bg-acc-100',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'disabled:opacity-50 disabled:pointer-events-none',\n classNames?.button_previous\n )}\n tabIndex={previousMonth ? undefined : -1}\n aria-disabled={previousMonth ? undefined : true}\n aria-label={previousMonth ? labels.labelPrevious(previousMonth) : undefined}\n onClick={handlePreviousClick}\n disabled={!previousMonth}\n >\n {Chevron ? <Chevron orientation=\"left\" className=\"size-4\" disabled={!previousMonth} /> : <span>‹</span>}\n </button>\n <span className=\"text-sm font-medium\">{caption}</span>\n <button\n type=\"button\"\n className={cn(\n 'h-7 w-7 bg-transparent p-0',\n 'inline-flex items-center justify-center rounded-md',\n 'hover:bg-acc-100',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'disabled:opacity-50 disabled:pointer-events-none',\n classNames?.button_next\n )}\n tabIndex={nextMonth ? undefined : -1}\n aria-disabled={nextMonth ? undefined : true}\n aria-label={nextMonth ? labels.labelNext(nextMonth) : undefined}\n onClick={handleNextClick}\n disabled={!nextMonth}\n >\n {Chevron ? <Chevron orientation=\"right\" className=\"size-4\" disabled={!nextMonth} /> : <span>›</span>}\n </button>\n </nav>\n </caption>\n {monthGridChildren}\n </>\n );\n }\n\n return React.isValidElement(child) \n ? React.cloneElement(child, { key: child.key ?? `calendar-child-${index}` })\n : child;\n })}\n </>\n );\n });\n CustomMonth.displayName = 'CustomMonth';\n\n // Custom Weekdays: render table head with semantic row\n const CustomWeekdays = React.memo(({ className, children, ...props }: WeekdaysProps) => {\n return (\n <thead>\n <tr className={cn('text-xs text-sec-500', className)} {...props}>\n {children}\n </tr>\n </thead>\n );\n });\n CustomWeekdays.displayName = 'CustomWeekdays';\n\n // Memoize components to ensure stable references\n const defaultComponents = React.useMemo(() => ({\n Root: CustomRoot,\n Months: CustomMonths,\n Month: CustomMonth,\n MonthGrid: CustomMonthGrid,\n // MonthCaption is now handled inside CustomMonth (injected into table)\n Weekdays: CustomWeekdays,\n // Spread user components AFTER ours so ours take precedence\n ...(components || {}),\n }), [components, CustomRoot, CustomMonths, CustomMonth, CustomWeekdays]);\n\n return (\n <DayPicker\n {...(mode ? { mode } : {})}\n locale={locale ?? enAU}\n hideNavigation={true}\n {...(props as any)}\n // CRITICAL: Explicit props must come AFTER spread to ensure they override any props from spread\n // This ensures month, onMonthChange, selected, and onSelect are always correct\n selected={selected}\n onSelect={onSelect}\n month={month}\n onMonthChange={wrappedHandleMonthChange}\n className={className}\n classNames={{\n // v9 API: Updated for table-based structure\n months: '', // No wrapper - removed by CustomMonths\n month: '', // No wrapper - removed by CustomMonth\n month_caption: '', // Now handled by custom component (renders as <caption>)\n caption_label: 'text-sm font-medium',\n nav: 'relative flex items-center justify-center space-x-1',\n // v9: button_previous and button_next for navigation buttons\n button_previous: cn(\n 'absolute left-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n 'border border-input hover:bg-acc-100',\n 'inline-flex items-center justify-center rounded-md',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'\n ),\n button_next: cn(\n 'absolute right-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n 'border border-input hover:bg-acc-100',\n 'inline-flex items-center justify-center rounded-md',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'\n ),\n // v9: table -> month_grid (now a proper <table>)\n month_grid: '', // Styles applied directly to table in CustomMonth\n // v9: head_row -> weekdays (now wrapped in <thead> by custom component)\n weekdays: '', // Styles applied to <tr> inside <thead>\n weekday: 'text-sec-600 rounded-md w-9 font-normal text-[0.8rem]',\n // v9: row -> week (now a proper <tr>)\n week: 'mt-2',\n // v9: cell -> day (now a proper <td> by custom component)\n day: '', // Styles moved to <td> in custom component\n // v9: day -> day_button (the button inside the cell)\n day_button: cn(\n 'h-9 w-9 p-0 font-normal aria-selected:opacity-100',\n 'hover:bg-acc-100 hover:text-main-600',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n 'inline-flex items-center justify-center rounded-md'\n ),\n // v9: day_range_end -> range_end\n range_end: 'range-end',\n // v9: day_selected -> selected\n selected: 'bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50 focus:bg-main-600 focus:text-main-50',\n // v9: day_today -> today\n today: 'bg-sec-100 text-main-600 font-semibold',\n // v9: day_outside -> outside\n outside: 'outside text-sec-400 opacity-50 aria-selected:bg-acc-50/50 aria-selected:text-sec-400 aria-selected:opacity-30',\n // v9: day_disabled -> disabled\n disabled: 'text-sec-400 opacity-50 cursor-not-allowed',\n // v9: day_range_middle -> range_middle\n range_middle: 'aria-selected:bg-acc-100 aria-selected:text-main-600',\n // v9: day_hidden -> hidden\n hidden: 'invisible',\n ...classNames,\n }}\n components={defaultComponents}\n />\n );\n }\n);\n\nCalendar.displayName = 'Calendar';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Calendar };\n\n","/**\n * @file Toast Component System\n * @package @jmruthers/pace-core\n * @module Components/Toast\n * @since 0.1.0\n *\n * A comprehensive toast notification system built on top of Radix UI primitives.\n * Provides accessible, customizable toast notifications with smooth animations.\n *\n * Features:\n * - Multiple toast types (success, error, warning, info)\n * - Customizable positioning and styling\n * - Swipe gestures for dismissal\n * - Keyboard navigation support\n * - Auto-dismiss with default 5 second duration managed internally\n * - Action buttons and close functionality\n * - Responsive design\n * - Accessibility compliant\n * - Smooth animations and transitions\n * - Toast queue management\n *\n * @example\n * ```tsx\n * // Basic toast usage\n * import { useToast } from '@jmruthers/pace-core';\n * \n * function MyComponent() {\n * const { toast } = useToast();\n * \n * const handleSuccess = () => {\n * toast({\n * title: \"Success!\",\n * description: \"Your changes have been saved.\",\n * variant: \"success\"\n * });\n * };\n * \n * return <button onClick={handleSuccess}>Save Changes</button>;\n * }\n * \n * // Toast with action\n * toast({\n * title: \"Undo Changes\",\n * description: \"Your changes have been saved.\",\n * action: <ToastAction altText=\"Undo\">Undo</ToastAction>\n * });\n * \n * // Custom toast component\n * <Toast>\n * <ToastTitle>Custom Toast</ToastTitle>\n * <ToastDescription>This is a custom toast message.</ToastDescription>\n * <ToastClose />\n * </Toast>\n * \n * // Toast provider setup\n * function App() {\n * return (\n * <ToastProvider>\n * <YourApp />\n * <Toaster />\n * </ToastProvider>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA attributes and roles\n * - Keyboard navigation support\n * - Screen reader announcements\n * - Focus management\n * - High contrast support\n * - Swipe gesture alternatives\n *\n * @performance\n * - Efficient toast queue management\n * - Optimized animations\n * - Memory leak prevention\n * - Lazy rendering\n *\n * @dependencies\n * - @radix-ui/react-toast - Core toast functionality\n * - lucide-react - Icons\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from \"react\"\nimport * as ToastPrimitives from \"@radix-ui/react-toast\"\nimport { X } from \"lucide-react\"\nimport { cn } from \"../../utils/core/cn\"\nimport { useToast, type ToasterToast } from \"../../hooks/useToast\"\n\nconst ToastProvider = ToastPrimitives.Provider\n\n/**\n * ToastViewport component\n * Container for all toast notifications with customizable positioning\n * \n * @param props - Viewport configuration and styling\n * @param ref - Forwarded ref to the viewport element\n * @returns JSX.Element - The toast viewport container\n */\nconst ToastViewport = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Viewport>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Viewport\n ref={ref}\n data-testid=\"toast-viewport\"\n className={cn(\n \"fixed top-0 z-[9999] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]\",\n className\n )}\n {...props}\n />\n))\nToastViewport.displayName = ToastPrimitives.Viewport.displayName\n\n/**\n * Toast component\n * The main toast notification component with animations and interactions\n * \n * @param props - Toast configuration and content\n * @param ref - Forwarded ref to the toast element\n * @returns JSX.Element - The rendered toast notification\n * \n * @example\n * ```tsx\n * <Toast>\n * <ToastTitle>Success!</ToastTitle>\n * <ToastDescription>Your changes have been saved.</ToastDescription>\n * <ToastClose />\n * </Toast>\n * ```\n */\nconst Toast = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Root>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root>\n>(({ className, ...props }, ref) => {\n return (\n <ToastPrimitives.Root\n ref={ref}\n data-testid=\"toast-root\"\n className={cn(\n \"group pointer-events-auto bg-background relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full\",\n className\n )}\n {...props}\n />\n )\n})\nToast.displayName = ToastPrimitives.Root.displayName\n\n/**\n * ToastAction component\n * Action button within a toast notification\n * \n * @param props - Action button configuration\n * @param ref - Forwarded ref to the action button\n * @returns JSX.Element - The action button element\n * \n * @example\n * ```tsx\n * <ToastAction altText=\"Undo changes\">Undo</ToastAction>\n * ```\n */\nconst ToastAction = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Action>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Action\n ref={ref}\n data-testid=\"toast-action\"\n className={cn(\n \"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive\",\n className\n )}\n {...props}\n />\n))\nToastAction.displayName = ToastPrimitives.Action.displayName\n\n/**\n * ToastClose component\n * Close button for dismissing toast notifications\n * \n * @param props - Close button configuration\n * @param ref - Forwarded ref to the close button\n * @returns JSX.Element - The close button with X icon\n * \n * @example\n * ```tsx\n * <ToastClose />\n * ```\n */\nconst ToastClose = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Close>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Close\n ref={ref}\n data-testid=\"toast-close\"\n className={cn(\n \"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-acc-300 group-[.destructive]:hover:text-acc-50 group-[.destructive]:focus:ring-acc-400 group-[.destructive]:focus:ring-offset-acc-600\",\n className\n )}\n toast-close=\"\"\n {...props}\n >\n <X className=\"size-4\" />\n </ToastPrimitives.Close>\n))\nToastClose.displayName = ToastPrimitives.Close.displayName\n\n/**\n * ToastTitle component\n * Title text for toast notifications\n * \n * @param props - Title configuration and styling\n * @param ref - Forwarded ref to the title element\n * @returns JSX.Element - The toast title\n * \n * @example\n * ```tsx\n * <ToastTitle>Success!</ToastTitle>\n * ```\n */\nconst ToastTitle = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Title>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Title\n ref={ref}\n data-testid=\"toast-title\"\n className={cn(\"text-sm font-semibold\", className)}\n {...props}\n />\n))\nToastTitle.displayName = ToastPrimitives.Title.displayName\n\n/**\n * ToastDescription component\n * Description text for toast notifications\n * \n * @param props - Description configuration and styling\n * @param ref - Forwarded ref to the description element\n * @returns JSX.Element - The toast description\n * \n * @example\n * ```tsx\n * <ToastDescription>Your changes have been saved successfully.</ToastDescription>\n * ```\n */\nconst ToastDescription = React.forwardRef<\n React.ElementRef<typeof ToastPrimitives.Description>,\n React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>\n>(({ className, ...props }, ref) => (\n <ToastPrimitives.Description\n ref={ref}\n data-testid=\"toast-description\"\n className={cn(\"text-sm opacity-90\", className)}\n {...props}\n />\n))\nToastDescription.displayName = ToastPrimitives.Description.displayName\n\nexport interface ToastProps extends React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> {}\n\n/**\n * Type for toast action elements.\n * Represents a React element that can be used as a toast action button.\n */\nexport interface ToastActionElement extends React.ReactElement<typeof ToastAction> {}\n\n/**\n * Toaster component\n * Container component that renders actual toast notifications\n * Should be placed at the root of your application\n * \n * @returns JSX.Element - The toast provider with viewport and rendered toasts\n * \n * @example\n * ```tsx\n * function App() {\n * return (\n * <ToastProvider>\n * <YourApp />\n * <Toaster />\n * </ToastProvider>\n * );\n * }\n * ```\n */\nexport function Toaster() {\n const { toasts } = useToast();\n \n return (\n <ToastProvider data-testid=\"toast-provider\">\n <ToastViewport />\n {toasts.map((toast: ToasterToast) => {\n // Destructure custom properties that shouldn't be passed to DOM\n const { id, title, description, action, dismiss, duration, ...toastProps } = toast;\n\n return (\n <Toast key={id} {...toastProps} duration={duration}>\n {title && <ToastTitle>{title}</ToastTitle>}\n {description && <ToastDescription>{description}</ToastDescription>}\n {action && action}\n <ToastClose onClick={dismiss} />\n </Toast>\n );\n })}\n </ToastProvider>\n );\n}\n\nexport {\n ToastProvider,\n ToastViewport,\n Toast,\n ToastTitle,\n ToastDescription,\n ToastClose,\n ToastAction,\n}\n","/**\n * @file Form Component\n * @package @jmruthers/pace-core\n * @module Components/Form\n * @since 0.1.0\n *\n * A comprehensive form component with React Hook Form integration and Zod validation.\n * Provides a clean, accessible form interface with built-in validation and error handling.\n *\n * Features:\n * - React Hook Form integration for efficient form state management\n * - Zod schema validation with type safety\n * - Flexible rendering with children function or JSX\n * - Built-in error handling and validation modes\n * - Accessible form structure\n * - TypeScript support with generic field values\n * - Customizable styling and layout\n *\n * @example\n * ```tsx\n * // Basic form with schema validation\n * const userSchema = z.object({\n * name: z.string().min(2, \"Name must be at least 2 characters\"),\n * email: z.string().email(\"Invalid email address\"),\n * age: z.number().min(18, \"Must be at least 18 years old\")\n * });\n * \n * <Form\n * schema={userSchema}\n * defaultValues={{ name: \"\", email: \"\", age: 0 }}\n * onSubmit={(data) => console.log(data)}\n * onError={(errors) => console.error(errors)}\n * >\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" type=\"email\" />\n * <FormField name=\"age\" label=\"Age\" type=\"number\" />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * \n * // Form with render function\n * <Form\n * schema={userSchema}\n * onSubmit={handleSubmit}\n * >\n * {(methods) => (\n * <>\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" />\n * <Button \n * type=\"submit\" \n * disabled={methods.formState.isSubmitting}\n * >\n * {methods.formState.isSubmitting ? \"Submitting...\" : \"Submit\"}\n * </Button>\n * </>\n * )}\n * </Form>\n * ```\n *\n * @accessibility\n * - Proper form structure with labels and descriptions\n * - Error announcements for screen readers\n * - Keyboard navigation support\n * - Focus management\n * - ARIA attributes for form validation\n *\n * @dependencies\n * - react-hook-form - Form state management\n * - @hookform/resolvers/zod - Zod validation integration\n * - zod - Schema validation\n * - React 19+ - Hooks and context\n */\n\nimport React from 'react';\nimport { useForm, FormProvider, UseFormReturn, FieldValues, DefaultValues, SubmitHandler, SubmitErrorHandler, useFormContext, Controller, FieldPath, ControllerRenderProps, ControllerFieldState, UseFormStateReturn } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { cn } from '../../utils/core/cn';\nimport { Label } from '../Label';\n\n/**\n * Props for the Form component\n */\nexport interface FormProps<TFieldValues extends FieldValues = FieldValues> {\n /**\n * Form schema for validation\n */\n schema?: z.ZodType<TFieldValues>;\n \n /**\n * Default values for the form\n */\n defaultValues?: DefaultValues<TFieldValues>;\n \n /**\n * Handler called when form is submitted successfully\n */\n onSubmit: SubmitHandler<TFieldValues>;\n \n /**\n * Handler called when form submission has errors\n */\n onError?: SubmitErrorHandler<TFieldValues>;\n \n /**\n * Form mode for react-hook-form\n * @default \"onSubmit\"\n */\n mode?: \"onSubmit\" | \"onChange\" | \"onBlur\" | \"onTouched\" | \"all\";\n \n /**\n * Children components or render function\n */\n children: React.ReactNode | ((methods: UseFormReturn<TFieldValues>) => React.ReactNode);\n \n /**\n * Class name for the form\n */\n className?: string;\n}\n\n/**\n * Form component with validation and React Hook Form integration\n * \n * @template TFieldValues - The type of form field values\n * @param props - Form configuration and handlers\n * @returns JSX.Element - The rendered form with FormProvider context\n * \n * @example\n * ```tsx\n * <Form\n * schema={userSchema}\n * defaultValues={{ name: \"\", email: \"\" }}\n * onSubmit={handleSubmit}\n * mode=\"onBlur\"\n * >\n * <FormField name=\"name\" label=\"Name\" />\n * <FormField name=\"email\" label=\"Email\" />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * ```\n */\nexport function Form<TFieldValues extends FieldValues = FieldValues>({\n schema,\n defaultValues,\n onSubmit,\n onError,\n mode = \"onSubmit\",\n children,\n className,\n}: FormProps<TFieldValues>) {\n const methods = useForm<TFieldValues>({\n resolver: schema ? zodResolver(schema) : undefined,\n defaultValues,\n mode,\n shouldUnregister: false,\n });\n\n const handleSubmit = methods.handleSubmit(onSubmit, onError);\n\n return (\n <FormProvider {...methods}>\n <form onSubmit={handleSubmit} className={cn(\"space-y-4\", className)}>\n {typeof children === 'function' ? children(methods) : children}\n </form>\n </FormProvider>\n );\n}\n\n/**\n * Props for the FormField component\n */\nexport interface FormFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> {\n /**\n * Field name\n */\n name: TName;\n \n /**\n * Field label\n */\n label?: string;\n \n /**\n * Field type\n */\n type?: string;\n \n /**\n * Placeholder text\n */\n placeholder?: string;\n \n /**\n * Additional props for the input\n */\n inputProps?: React.InputHTMLAttributes<HTMLInputElement>;\n \n /**\n * Validation rules\n */\n validation?: {\n required?: boolean;\n pattern?: {\n value: RegExp;\n message: string;\n };\n minLength?: {\n value: number;\n message: string;\n };\n maxLength?: {\n value: number;\n message: string;\n };\n };\n \n /**\n * Custom render function\n */\n render?: (props: {\n field: ControllerRenderProps<TFieldValues, TName>;\n fieldState: ControllerFieldState;\n formState: UseFormStateReturn<TFieldValues>;\n }) => React.ReactElement<any>;\n \n /**\n * Test ID\n */\n 'data-testid'?: string;\n \n /**\n * Class name\n */\n className?: string;\n}\n\n/**\n * FormField component for React Hook Form integration\n * \n * A flexible form field component that integrates with React Hook Form and provides\n * built-in validation, error handling, and accessibility features.\n * \n * Features:\n * - React Hook Form integration with Controller\n * - Built-in validation with error display\n * - Accessible labels and error messages\n * - Custom render function support\n * - TypeScript support with generic field paths\n * - Consistent styling with error states\n * - Test ID support for testing\n * - Flexible input types and props\n * \n * @template TFieldValues - The type of form field values\n * @template TName - The type of the field name (must be a valid field path)\n * @param props - Form field configuration and validation\n * @returns JSX.Element - The rendered form field with validation\n * \n * @example\n * ```tsx\n * // Basic text field\n * <FormField\n * name=\"username\"\n * label=\"Username\"\n * placeholder=\"Enter your username\"\n * validation={{ required: true }}\n * />\n * \n * // Email field with custom validation\n * <FormField\n * name=\"email\"\n * label=\"Email Address\"\n * type=\"email\"\n * validation={{\n * required: true,\n * pattern: {\n * value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$/i,\n * message: \"Invalid email address\"\n * }\n * }}\n * />\n * \n * // Custom render function\n * <FormField\n * name=\"avatar\"\n * label=\"Profile Picture\"\n * render={({ field }) => (\n * <input\n * {...field}\n * type=\"file\"\n * accept=\"image/*\"\n * />\n * )}\n * />\n * ```\n * \n * @accessibility\n * - Proper label association with htmlFor\n * - Error messages with role=\"alert\"\n * - Required field indicators\n * - Focus management\n * - Screen reader friendly error announcements\n * - Keyboard navigation support\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n name,\n label,\n type = \"text\",\n placeholder,\n inputProps,\n validation,\n render,\n 'data-testid': testId,\n className,\n}: FormFieldProps<TFieldValues, TName>) {\n const { control } = useFormContext<TFieldValues>();\n\n return (\n <div className={cn(\"space-y-2\", className)}>\n {label && (\n <Label htmlFor={name}>\n {label}\n {validation?.required && (\n <span className=\"text-destructive ml-1\" aria-label=\"required\">\n *\n </span>\n )}\n </Label>\n )}\n \n <Controller\n name={name}\n control={control}\n rules={validation}\n render={(props) => {\n const { field, fieldState } = props;\n const fieldError = fieldState.error;\n \n // Safely extract error message\n const errorMessage = fieldError && typeof fieldError === 'object' && 'message' in fieldError \n ? String(fieldError.message) \n : undefined;\n\n if (render) {\n return render(props);\n }\n \n return (\n <>\n <input\n {...field}\n id={name}\n type={type}\n placeholder={placeholder}\n data-testid={testId}\n aria-label={label || placeholder || name}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n fieldError && \"border-destructive focus-visible:ring-destructive\"\n )}\n {...inputProps}\n />\n {errorMessage && (\n <p className=\"text-destructive\" role=\"alert\">\n {errorMessage}\n </p>\n )}\n </>\n );\n }}\n />\n </div>\n );\n}\n","/**\n * @file LoginForm Component\n * @package @jmruthers/pace-core\n * @module Components/LoginForm\n * @since 0.1.0\n *\n * A comprehensive login form component with built-in validation, error handling,\n * and loading states for user authentication.\n *\n * Features:\n * - Email and password validation\n * - Loading states with disabled form\n * - Error handling and display\n * - Customizable branding and messaging\n * - Sign-up link integration\n * - Performance optimized with React.memo\n * - Accessibility compliant\n * - Responsive design\n * - Form validation\n * - Success and error callbacks\n *\n * @example\n * ```tsx\n * // Basic login form\n * <LoginForm\n * onSignIn={async (data) => {\n * await signIn(data.email, data.password);\n * }}\n * onSuccess={() => navigate('/dashboard')}\n * onError={(error) => console.error('Login failed:', error)}\n * />\n * \n * // Login form with custom branding\n * <LoginForm\n * appName=\"My Application\"\n * title=\"Welcome Back\"\n * subtitle=\"Please sign in to access your account\"\n * onSignIn={handleSignIn}\n * onSuccess={handleSuccess}\n * onError={handleError}\n * />\n * \n * // Login form with sign-up integration\n * <LoginForm\n * appName=\"My App\"\n * showSignUp={true}\n * onSignUp={() => navigate('/signup')}\n * onSignIn={handleSignIn}\n * isLoading={isAuthenticating}\n * />\n * \n * // Login form with custom error handling\n * <LoginForm\n * onSignIn={async (data) => {\n * try {\n * const result = await authService.signIn(data);\n * if (result.success) {\n * onSuccess();\n * } else {\n * throw new Error(result.error);\n * }\n * } catch (error) {\n * onError(error);\n * }\n * }}\n * onSuccess={() => {\n * toast.success('Successfully signed in!');\n * navigate('/dashboard');\n * }}\n * onError={(error) => {\n * toast.error(`Sign in failed: ${error.message}`);\n * }}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper form labels and associations\n * - Screen reader friendly error messages\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear error identification\n *\n * @performance\n * - React.memo for efficient re-rendering\n * - useCallback for stable event handlers\n * - useMemo for computed values\n * - Minimal re-renders\n *\n * @dependencies\n * - React 19+ - Hooks and memo\n * - Button component\n * - Input component\n * - Label component\n * - Card components\n * - Alert component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState, useCallback, useMemo } from 'react';\nimport { Button } from '../Button/Button';\nimport { Input } from '../Input/Input';\nimport { Label } from '../Label/Label';\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '../Card/index';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { cn } from '../../utils/core/cn';\n\n/**\n * Props for the LoginForm component.\n * Configures login form behavior, validation, and callbacks.\n */\nexport interface LoginFormProps {\n /** Callback invoked when the form is submitted */\n onSignIn: (data: { email: string; password: string }) => Promise<void>;\n /** Callback invoked on successful sign-in */\n onSuccess?: () => void;\n /** Callback invoked if sign-in fails */\n onError?: (error: Error) => void;\n /** Show loading spinner and disable form while true */\n isLoading?: boolean;\n /** Application name for display in the form */\n appName?: string;\n /** Custom title for the form */\n title?: string;\n /** Custom subtitle for the form */\n subtitle?: string;\n /** Show a sign-up link or button */\n showSignUp?: boolean;\n /** Optional callback for sign-up button */\n onSignUp?: () => void;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * LoginForm component that provides a ready-to-use authentication form for user sign-in.\n * It supports validation, loading state, error handling, and can be customized via props.\n * Now includes performance optimizations and onSignUp support.\n * \n * @param props - Login form configuration and handlers\n * @returns JSX.Element - The rendered login form\n * \n * @example\n * ```tsx\n * <LoginForm\n * onSignIn={handleSignIn}\n * onSuccess={() => navigate('/dashboard')}\n * onError={(error) => toast.error(error.message)}\n * isLoading={isAuthenticating}\n * />\n * ```\n */\nexport const LoginForm = React.memo<LoginFormProps>(({\n onSignIn,\n onSuccess,\n onError,\n isLoading = false,\n appName,\n title,\n subtitle,\n showSignUp = false,\n onSignUp,\n className\n}) => {\n const [formData, setFormData] = useState({ email: '', password: '' });\n const [error, setError] = useState<string | null>(null);\n\n // Memoized validation state\n const isFormValid = useMemo(() => {\n return formData.email.length > 0 && formData.password.length > 0;\n }, [formData.email, formData.password]);\n\n // React Compiler handles memoization automatically\n const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData(prev => ({ ...prev, email: e.target.value }));\n };\n\n const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData(prev => ({ ...prev, password: e.target.value }));\n };\n\n const handleSubmit = useCallback(async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!isFormValid || isLoading) return;\n try {\n await onSignIn(formData);\n onSuccess?.();\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Sign in failed';\n setError(errorMessage);\n onError?.(err instanceof Error ? err : new Error(errorMessage));\n }\n }, [formData, isFormValid, isLoading, onSignIn, onSuccess, onError]);\n\n const handleSignUpClick = () => {\n onSignUp?.();\n };\n\n const displayTitle = useMemo(() => title || (appName ? `Sign in to ${appName}` : 'Sign In'), [title, appName]);\n const displaySubtitle = useMemo(() => subtitle || 'Enter your credentials to continue.', [subtitle]);\n\n return (\n <Card className={cn('w-full max-w-md mx-auto', className)}>\n <form onSubmit={handleSubmit} data-testid=\"login-form\">\n <CardHeader className=\"space-y-1\">\n <CardTitle className=\"text-2xl text-center\">{displayTitle}</CardTitle>\n <CardDescription className=\"text-center\">\n {displaySubtitle}\n </CardDescription>\n </CardHeader>\n\n <CardContent className=\"space-y-4\">\n {error && (\n <Alert variant=\"destructive\" role=\"alert\" aria-live=\"assertive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n \n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"Enter your email\"\n value={formData.email}\n onChange={handleEmailChange}\n required\n disabled={isLoading}\n />\n \n \n <Label htmlFor=\"password\">Password</Label>\n <Input\n id=\"password\"\n type=\"password\"\n placeholder=\"Enter your password\"\n value={formData.password}\n onChange={handlePasswordChange}\n required\n disabled={isLoading}\n />\n \n </CardContent>\n <CardFooter className=\"flex flex-col space-y-4\">\n <Button \n type=\"submit\" \n className=\"w-full\" \n disabled={isLoading || !isFormValid}\n >\n {isLoading ? 'Signing in...' : 'Sign In'}\n </Button>\n {showSignUp && (\n onSignUp ? (\n <div className=\"text-sm text-center text-muted-foreground\">\n <button\n type=\"button\"\n onClick={handleSignUpClick}\n className=\"text-primary hover:underline\"\n >\n Don't have an account? Sign up\n </button>\n </div>\n ) : (\n <p className=\"text-center text-muted-foreground\">\n Don't have an account?{' '}\n <a href=\"/signup\" className=\"text-primary hover:underline\">\n Sign up\n </a>\n </p>\n )\n )}\n </CardFooter>\n </form>\n </Card>\n );\n});\n","/**\n * @file Context Selector Component\n * @package @jmruthers/pace-core\n * @module Components/ContextSelector\n * @since 0.6.4\n *\n * A unified intelligent selector component that shows all organisations and events\n * a user can access based on their roles and permissions. This is the single\n * selector for all apps - it intelligently determines what to show based on:\n * - User's organisation roles\n * - User's event-app roles\n * - Super admin status (shows all)\n *\n * Features:\n * - Intelligent display of accessible organisations and events\n * - Grouped display (Organisations / Events sections)\n * - Visual distinction between orgs and events\n * - Super admin support (shows all orgs and events)\n * - Loading states and error handling\n * - Accessible interface design\n * - Integration with OrganisationProvider and EventService\n * - Automatically shows superset of what user can access\n *\n * @example\n * ```tsx\n * <ContextSelector\n * onOrganisationSelect={(org) => {\n * switchOrganisation(org.id);\n * }}\n * onEventSelect={(event) => {\n * setSelectedEvent(event);\n * }}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - ARIA labels and descriptions\n * - High contrast support\n *\n * @security\n * - Only shows organisations/events user has access to\n * - Super admins see all items\n * - Validates access before selection\n */\n\nimport React, { useMemo } from 'react';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectGroup, SelectLabel, SelectSeparator } from '../Select';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { RefreshCw, AlertCircle, Building2, Calendar } from 'lucide-react';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useRBAC } from '../../rbac/hooks/useRBAC';\nimport type { Organisation } from '../../types/organisation';\nimport type { Event } from '../../types/event';\nimport { logger } from '../../utils/core/logger';\n\n/**\n * Props for the ContextSelector component.\n */\nexport interface ContextSelectorProps {\n /** Placeholder text for the dropdown */\n placeholder?: string;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when an organisation is selected */\n onOrganisationSelect?: (org: Organisation) => void;\n /** Callback fired when an event is selected */\n onEventSelect?: (event: Event) => void;\n /** Show friendly message when no items available */\n showNoItemsMessage?: boolean;\n /** Show retry button on errors */\n showRetryButton?: boolean;\n /** Compact display mode */\n compact?: boolean;\n /** Disabled state */\n disabled?: boolean;\n /** Show organisations section (default: true) */\n showOrganisations?: boolean;\n /** Show events section (default: true) */\n showEvents?: boolean;\n}\n\n/**\n * ContextSelector component for selecting organisations or events\n * \n * This is the unified intelligent selector that shows all organisations and events\n * a user can access. It automatically determines what to show based on the user's\n * roles and permissions - no need to configure separate org/event selectors.\n * \n * The selector intelligently shows:\n * - All organisations the user has access to (via organisation roles)\n * - All events the user has access to (via event-app roles or organisation membership)\n * - Everything for super admins\n * \n * @component\n * @example\n * <ContextSelector\n * onOrganisationSelect={(org) => switchOrganisation(org)}\n * onEventSelect={(event) => setSelectedEvent(event)}\n * />\n */\nexport function ContextSelector({\n placeholder = \"Select organisation or event\",\n className,\n onOrganisationSelect,\n onEventSelect,\n showNoItemsMessage = true,\n showRetryButton = true,\n compact = false,\n disabled = false,\n showOrganisations = true,\n showEvents = true\n}: ContextSelectorProps) {\n const { \n organisations, \n selectedOrganisation,\n isLoading: orgLoading,\n error: orgError,\n refreshOrganisations\n } = useOrganisations();\n \n const { \n events, \n selectedEvent, \n isLoading: eventLoading, \n error: eventError, \n refreshEvents\n } = useEvents();\n \n const { isSuperAdmin } = useRBAC();\n \n const isLoading = (showOrganisations && orgLoading) || (showEvents && eventLoading);\n const hasError = (showOrganisations && orgError) || (showEvents && eventError);\n const hasItems = \n (showOrganisations && (organisations?.length || 0) > 0) || \n (showEvents && (events?.length || 0) > 0);\n \n // Determine current selection value\n // Priority: Event selection takes precedence over organisation selection\n // When an event is selected, show the event (even if an org is also selected)\n // The organisation remains in context (derived from event) but selector shows the active selection\n const currentValue = useMemo(() => {\n if (showEvents && selectedEvent) {\n return `event:${selectedEvent.event_id || selectedEvent.id}`;\n }\n if (showOrganisations && selectedOrganisation) {\n return `org:${selectedOrganisation.id}`;\n }\n return '';\n }, [showOrganisations, showEvents, selectedOrganisation?.id, selectedEvent]);\n \n const handleValueChange = (value: string) => {\n if (disabled || isLoading) return;\n \n if (value.startsWith('org:') && showOrganisations) {\n const orgId = value.replace('org:', '');\n const org = organisations?.find(o => o.id === orgId);\n if (org && onOrganisationSelect) {\n onOrganisationSelect(org);\n }\n } else if (value.startsWith('event:') && showEvents) {\n const eventId = value.replace('event:', '');\n const event = events?.find(e => (e.event_id || e.id) === eventId);\n if (event && onEventSelect) {\n onEventSelect(event);\n }\n }\n };\n \n const handleRetry = async () => {\n try {\n if (showOrganisations && orgError) {\n await refreshOrganisations();\n }\n if (showEvents && eventError) {\n await refreshEvents();\n }\n } catch (error) {\n logger.error('ContextSelector', 'Failed to refresh:', error);\n }\n };\n \n // Loading state - only show loading if we don't have any items yet\n // This prevents the selector from being stuck in loading when data exists\n if (isLoading && !hasItems) {\n const loadingText = compact ? \"Loading...\" : \n showOrganisations && showEvents ? \"Loading organisations and events...\" :\n showOrganisations ? \"Loading organisations...\" :\n \"Loading events...\";\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n <LoadingSpinner size=\"sm\" />\n <span className=\"text-sm text-muted-foreground\">\n {loadingText}\n </span>\n </div>\n );\n }\n \n // Error state\n if (hasError) {\n const errorMessages = [];\n if (showOrganisations && orgError) {\n errorMessages.push(`Failed to load organisations: ${orgError.message}`);\n }\n if (showEvents && eventError) {\n errorMessages.push(`Failed to load events: ${eventError.message}`);\n }\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert variant=\"destructive\">\n <AlertCircle className=\"size-4\" />\n <AlertDescription>\n {errorMessages.join(' ')}\n </AlertDescription>\n </Alert>\n {showRetryButton && (\n <Button \n variant=\"outline\" \n size=\"sm\" \n onClick={handleRetry}\n disabled={isLoading}\n className=\"w-full\"\n >\n <RefreshCw className={`size-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Retry\n </Button>\n )}\n </div>\n );\n }\n \n // No items available\n if (!hasItems) {\n if (showNoItemsMessage) {\n const noItemsText = \n showOrganisations && showEvents ? \"No organisations or events available. Please contact your administrator.\" :\n showOrganisations ? \"No organisations available. Please contact your administrator.\" :\n \"No events available. Please contact your administrator.\";\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert>\n <AlertCircle className=\"size-4\" />\n <AlertDescription>\n {noItemsText}\n </AlertDescription>\n </Alert>\n {showRetryButton && (\n <Button \n variant=\"outline\" \n size=\"sm\" \n onClick={handleRetry}\n disabled={isLoading}\n className=\"w-full\"\n >\n <RefreshCw className={`size-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Check Again\n </Button>\n )}\n </div>\n );\n }\n return null;\n }\n \n // Format display value\n // Priority: Event selection takes precedence over organisation selection (matches currentValue)\n const displayValue = useMemo(() => {\n if (showEvents && selectedEvent) {\n return (\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"size-4 flex-shrink-0\" />\n <span className=\"truncate\">{selectedEvent.event_name}</span>\n </div>\n );\n }\n if (showOrganisations && selectedOrganisation) {\n return (\n <div className=\"flex items-center gap-2\">\n <Building2 className=\"size-4 flex-shrink-0\" />\n <span className=\"truncate\">{selectedOrganisation.display_name}</span>\n </div>\n );\n }\n return null;\n }, [showOrganisations, showEvents, selectedOrganisation, selectedEvent]);\n \n // Determine placeholder text based on what's shown\n const effectivePlaceholder = useMemo(() => {\n if (placeholder !== \"Select organisation or event\") {\n return placeholder;\n }\n if (showOrganisations && showEvents) {\n return \"Select organisation or event\";\n }\n if (showOrganisations) {\n return \"Select organisation\";\n }\n if (showEvents) {\n return \"Select event\";\n }\n return placeholder;\n }, [placeholder, showOrganisations, showEvents]);\n \n return (\n <div className={className} data-testid=\"context-selector\">\n <Select \n value={currentValue}\n onValueChange={handleValueChange}\n disabled={disabled || isLoading}\n >\n <SelectTrigger \n className=\"text-left\"\n variant=\"outline\"\n >\n <SelectValue placeholder={effectivePlaceholder}>\n {displayValue}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {/* Organisations Section */}\n {showOrganisations && organisations && organisations.length > 0 && (\n <>\n <SelectGroup>\n <SelectLabel>Organisations</SelectLabel>\n {organisations.map((org) => (\n <SelectItem \n key={org.id} \n value={`org:${org.id}`}\n >\n <div className=\"flex items-center gap-2\">\n <Building2 className=\"size-4\" />\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{org.display_name}</span>\n {!compact && org.description && (\n <span className=\"text-xs text-muted-foreground truncate max-w-40\">\n {org.description}\n </span>\n )}\n </div>\n </div>\n </SelectItem>\n ))}\n </SelectGroup>\n {showEvents && events && events.length > 0 && <SelectSeparator />}\n </>\n )}\n \n {/* Events Section */}\n {showEvents && events && events.length > 0 && (\n <SelectGroup>\n <SelectLabel>Events</SelectLabel>\n {events.map((event) => (\n <SelectItem \n key={event.event_id || event.id} \n value={`event:${event.event_id || event.id}`}\n >\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"size-4\" />\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{event.event_name}</span>\n {!compact && event.event_date && (\n <span className=\"text-xs text-muted-foreground\">\n {new Date(event.event_date).toLocaleDateString()}\n </span>\n )}\n </div>\n </div>\n </SelectItem>\n ))}\n </SelectGroup>\n )}\n </SelectContent>\n </Select>\n </div>\n );\n}\n\n","/**\n * @file Password Change Form Component\n * @package @jmruthers/pace-core\n * @module Components/PasswordChange\n * @since 0.1.0\n *\n * A secure password change form component with validation, confirmation matching,\n * and proper error handling for updating user passwords.\n *\n * Features:\n * - Password strength validation (minimum 8 characters)\n * - Password confirmation matching\n * - Loading states with disabled form\n * - Error handling and display\n * - Accessibility compliant\n * - Responsive design\n * - Form validation\n * - Secure password input\n * - Success and error callbacks\n *\n * @example\n * ```tsx\n * // Basic password change form\n * <PasswordChangeForm\n * onSubmit={async (values) => {\n * try {\n * await updatePassword(values.newPassword);\n * toast.success('Password updated successfully!');\n * return {};\n * } catch (error) {\n * return { error: { message: error.message } };\n * }\n * }}\n * />\n * \n * // Password change form with custom styling\n * <PasswordChangeForm\n * className=\"max-w-md mx-auto p-6 bg-main-50 rounded-lg shadow-md\"\n * onSubmit={async (values) => {\n * const result = await authService.changePassword(values.newPassword);\n * if (result.success) {\n * navigate('/profile');\n * return {};\n * } else {\n * return { error: { message: result.error } };\n * }\n * }}\n * />\n * \n * // Password change form in a modal\n * <Modal isOpen={showPasswordChange} onClose={() => setShowPasswordChange(false)}>\n * <ModalContent>\n * <ModalHeader>\n * <ModalTitle>Change Password</ModalTitle>\n * </ModalHeader>\n * <ModalBody>\n * <PasswordChangeForm\n * onSubmit={async (values) => {\n * const result = await changePassword(values.newPassword);\n * if (result.success) {\n * setShowPasswordChange(false);\n * toast.success('Password changed successfully');\n * return {};\n * } else {\n * return { error: { message: result.error } };\n * }\n * }}\n * />\n * </ModalBody>\n * </ModalContent>\n * </Modal>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper form labels and associations\n * - Screen reader friendly error messages\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear error identification\n * - Role=\"alert\" for error announcements\n * - Password field security\n *\n * @security\n * - Password strength validation\n * - Secure password input fields\n * - Confirmation matching\n * - No password logging\n * - Proper error handling\n *\n * @dependencies\n * - React 19+ - Hooks and state\n * - Button component\n * - Input component\n * - Label component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState } from 'react';\nimport { Button } from '../Button/Button';\nimport { Input } from '../Input/Input';\nimport { Label } from '../Label';\nimport { cn } from '../../utils/core/cn';\n\n/**\n * Form values for password change.\n */\nexport interface PasswordChangeFormValues {\n newPassword: string;\n confirmPassword: string;\n}\n\n/**\n * Error structure for password change form.\n */\nexport interface PasswordChangeFormError {\n message?: string;\n code?: string;\n}\n\n/**\n * Props for the PasswordChangeForm component.\n */\nexport interface PasswordChangeFormProps {\n onSubmit: (values: PasswordChangeFormValues) => Promise<{ error?: PasswordChangeFormError }>;\n className?: string;\n}\n\nexport function PasswordChangeForm({ onSubmit, className }: PasswordChangeFormProps) {\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (newPassword.length < 8) {\n setError('Password must be at least 8 characters.');\n return;\n }\n if (newPassword !== confirmPassword) {\n setError('Passwords do not match.');\n return;\n }\n\n setIsSubmitting(true);\n try {\n const result = await onSubmit({ newPassword, confirmPassword });\n if (result && result.error) {\n setError(result.error.message || 'Failed to change password.');\n }\n } catch (err) {\n const errorObj = err instanceof Error ? err : new Error('An unexpected error occurred');\n setError(errorObj.message);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <form onSubmit={handleSubmit} className={cn('space-y-4', className)}>\n {error && (\n <div role=\"alert\">\n {error}\n </div>\n )}\n <div className=\"space-y-2\">\n <Label htmlFor=\"new-password\">New Password</Label>\n <Input\n id=\"new-password\"\n type=\"password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n required\n disabled={isSubmitting}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"confirm-password\">Confirm Password</Label>\n <Input\n id=\"confirm-password\"\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n required\n disabled={isSubmitting}\n />\n </div>\n <Button\n type=\"submit\"\n className=\"w-full\"\n disabled={isSubmitting || !newPassword || !confirmPassword}\n >\n {isSubmitting ? 'Changing...' : 'Change Password'}\n </Button>\n </form>\n );\n} ","/**\n * @file User Menu Component\n * @package @jmruthers/pace-core\n * @module Components/UserMenu\n * @since 0.1.0\n *\n * A comprehensive user menu component that displays user information and provides\n * access to user-specific actions like password changes and sign out.\n *\n * Features:\n * - User avatar and display name\n * - Dropdown menu with user actions\n * - Password change functionality\n * - Sign out capability\n * - Loading state component\n * - Responsive design\n * - Accessibility compliant\n * - Performance optimized with React.memo\n * - Integration with Supabase User\n * - Customizable styling\n *\n * @example\n * ```tsx\n * // Basic user menu\n * <UserMenu\n * user={currentUser}\n * onSignOut={async () => {\n * await signOut();\n * navigate('/login');\n * }}\n * onChangePassword={async (newPassword, confirmPassword) => {\n * try {\n * await updatePassword(newPassword);\n * toast.success('Password updated successfully!');\n * return {};\n * } catch (error) {\n * return { error: { message: error.message } };\n * }\n * }}\n * />\n * \n * // User menu without avatar\n * <UserMenu\n * user={currentUser}\n * showAvatar={false}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * />\n * \n * // User menu with loading state\n * {isLoading ? (\n * <UserMenu.Loading />\n * ) : (\n * <UserMenu\n * user={user}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * />\n * )}\n * \n * // User menu in header\n * <Header>\n * <nav className=\"flex items-center gap-4\">\n * <Navigation />\n * <UserMenu\n * user={user}\n * onSignOut={handleSignOut}\n * onChangePassword={handlePasswordChange}\n * className=\"ml-auto\"\n * />\n * </nav>\n * </Header>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA labels and roles\n * - Keyboard navigation support\n * - Focus management\n * - Screen reader friendly\n * - High contrast support\n * - Loading state announcements\n * - Clear action identification\n *\n * @performance\n * - React.memo for efficient re-rendering\n * - useCallback for stable event handlers\n * - useMemo for computed values\n * - Minimal re-renders\n * - Optimized avatar rendering\n *\n * @dependencies\n * - React 19+ - Hooks and memo\n * - @supabase/supabase-js - User type\n * - lucide-react - Icons\n * - DropdownMenu components\n * - Dialog components\n * - PasswordChangeForm component\n * - Avatar component\n * - Button component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useCallback, useMemo, useState } from 'react';\nimport { User } from '@supabase/supabase-js';\nimport { ChevronDown, LogOut, KeyRound } from 'lucide-react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n} from '../Select';\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n DialogOverlay\n} from '../Dialog';\nimport { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\nimport { Avatar } from '../Avatar';\nimport { Button } from '../Button';\nimport { LoadingSpinner } from '../LoadingSpinner';\n\n/**\n * Props for the UserMenu component.\n */\nexport interface UserMenuProps {\n user: User | null;\n onSignOut?: () => Promise<void>;\n onChangePassword?: (newPassword: string, confirmPassword: string) => Promise<{ error?: PasswordChangeFormError }>;\n className?: string;\n showAvatar?: boolean;\n}\n\nexport const UserMenu = React.memo<UserMenuProps>(function UserMenu({\n user,\n onSignOut,\n onChangePassword,\n className,\n showAvatar = true,\n}) {\n const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);\n\n const userInfo = useMemo(() => {\n if (!user) return null;\n return {\n email: user.email,\n displayName: user.user_metadata?.display_name || user.user_metadata?.full_name || user.email?.split('@')[0],\n avatarUrl: user.user_metadata?.avatar_url,\n initial: (user.user_metadata?.display_name || user.user_metadata?.full_name || user.email || 'U').charAt(0).toUpperCase(),\n };\n }, [user]);\n\n const handleSignOut = useCallback(async () => {\n if (onSignOut) await onSignOut();\n }, [onSignOut]);\n\n if (!user || !userInfo) {\n return null; // Or a loading/login button\n }\n\n return (\n <Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>\n <Select className={className}>\n <SelectTrigger asChild>\n <Button variant=\"outline\" className=\"flex items-center gap-2\" aria-label={userInfo.displayName}>\n {showAvatar && (\n <Avatar \n src={userInfo.avatarUrl} \n alt={userInfo.displayName}\n fallback={userInfo.initial}\n className=\"size-7\"\n />\n )}\n <span>{userInfo.displayName}</span>\n <ChevronDown className=\"size-4\" />\n </Button>\n </SelectTrigger>\n <SelectContent>\n <SelectLabel className=\"font-normal\">\n <li className=\"pt-2\">\n {userInfo.displayName}<br/>\n <span className=\"text-muted-foreground\">{userInfo.email}</span>\n </li>\n </SelectLabel>\n <SelectSeparator />\n <DialogTrigger asChild>\n <SelectItem value=\"change-password\">\n <KeyRound className=\"mr-2 size-4\" />\n <span>Change Password</span>\n </SelectItem>\n </DialogTrigger>\n <SelectItem value=\"sign-out\" onClick={handleSignOut}>\n <LogOut className=\"mr-2 size-4\" />\n <span>Sign out</span>\n </SelectItem>\n </SelectContent>\n </Select>\n \n <DialogOverlay />\n <DialogContent className={className}>\n <DialogHeader>\n <DialogTitle>Change Password</DialogTitle>\n </DialogHeader>\n <PasswordChangeForm\n onSubmit={async ({ newPassword, confirmPassword }) => {\n if (onChangePassword) {\n const { error } = await onChangePassword(newPassword, confirmPassword);\n if (!error) {\n setPasswordDialogOpen(false);\n }\n return { error };\n }\n return {};\n }}\n />\n </DialogContent>\n </Dialog>\n );\n});\n\nexport const UserMenuLoading = React.memo(function UserMenuLoading() {\n return (\n <Button\n type=\"button\"\n disabled\n variant=\"outline\"\n className=\"flex items-center space-x-2\"\n aria-label=\"Loading user menu\"\n >\n <LoadingSpinner size=\"sm\" className=\"inline-block mr-2\" />\n <span className=\"truncate max-w-[150px]\">Loading...</span>\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n </Button>\n );\n});\n\n// Add Loading as a property to UserMenu for backward compatibility\ntype UserMenuWithLoading = typeof UserMenu & {\n Loading: typeof UserMenuLoading;\n};\n\n(UserMenu as UserMenuWithLoading).Loading = UserMenuLoading;\n","/**\n * @file Unified Navigation Menu Component\n * @package @jmruthers/pace-core\n * @module Navigation\n * @since 0.1.0\n * \n * A flexible navigation menu component that supports both dropdown and hierarchical modes.\n * \n * Features:\n * - Dropdown mode: Menu button that opens a dropdown list\n * - Hierarchical mode: Expandable tree navigation with nested items\n * - Icon support for navigation items\n * - Current page highlighting\n * - Keyboard navigation support\n * - Accessible design with proper ARIA attributes\n * - Click outside to close (dropdown mode)\n * - Recursive rendering for nested items (hierarchical mode)\n * \n * @example\n * Basic dropdown navigation (most common use case):\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * { id: 'reports', label: 'Reports', href: '/reports', icon: 'FileText' },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Main Menu\"\n * showIcons={true}\n * />\n * );\n * }\n * \n * @example\n * Hierarchical navigation with nested items:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function SidebarNavigation() {\n * const hierarchicalItems = [\n * { \n * id: 'user-management', \n * label: 'User Management',\n * icon: 'Users',\n * children: [\n * { id: 'users-list', label: 'All Users', href: '/users' },\n * { id: 'users-create', label: 'Create User', href: '/users/create' },\n * { id: 'user-roles', label: 'User Roles', href: '/users/roles' }\n * ]\n * },\n * { \n * id: 'reports', \n * label: 'Reports',\n * icon: 'BarChart',\n * children: [\n * { id: 'sales-reports', label: 'Sales Reports', href: '/reports/sales' },\n * { id: 'user-reports', label: 'User Reports', href: '/reports/users' }\n * ]\n * },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={hierarchicalItems}\n * mode=\"hierarchical\"\n * currentPath={window.location.pathname}\n * onNavigate={(item) => {\n * if (item.href) {\n * window.location.href = item.href;\n * }\n * }}\n * className=\"w-64 bg-sec-50 p-4\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * Integration with React Router and authentication:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * import { useUnifiedAuth } from '@jmruthers/pace-core/providers';\n * \n * function AuthenticatedNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const { hasRole, hasPermission } = useUnifiedAuth();\n * \n * // Build navigation items based on user permissions\n * const navItems = [\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * ...(hasPermission('meals:read') ? [\n * { id: 'meals', label: 'Meals', href: '/meals', icon: 'UtensilsCrossed' }\n * ] : []),\n * ...(hasRole('admin') ? [\n * { id: 'admin', label: 'Admin Panel', href: '/admin', icon: 'Shield' }\n * ] : []),\n * { id: 'profile', label: 'Profile', href: '/profile', icon: 'User' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Navigation\"\n * navigationLabel=\"Main application navigation\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * ```tsx\n * // Custom navigation with external links and actions\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function CustomNavigation() {\n * const handleNavigation = (item) => {\n * if (item.id === 'logout') {\n * // Handle logout action\n * handleLogout();\n * } else if (item.href?.startsWith('http')) {\n * // Handle external links\n * window.open(item.href, '_blank');\n * } else if (item.href) {\n * // Handle internal navigation\n * navigate(item.href);\n * }\n * };\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'help', label: 'Help Center', href: 'https://help.example.com', icon: 'HelpCircle' },\n * { id: 'logout', label: 'Sign Out', icon: 'LogOut' } // No href for actions\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * onNavigate={handleNavigation}\n * buttonText=\"Menu\"\n * disabled={false}\n * />\n * );\n * }\n * ```\n * \n * @accessibility\n * - WCAG 2.1 AA compliant navigation structure\n * - Proper ARIA attributes for screen readers\n * - Keyboard navigation with Enter, Space, and Escape keys\n * - Focus management for dropdown menus\n * - Semantic HTML structure with nav, menu, and menuitem roles\n * - Clear visual indicators for active/current page\n * \n * @performance\n * - Lightweight component with minimal re-renders\n * - Efficient click outside detection\n * - Optimized keyboard event handling\n * - Memory cleanup for event listeners\n * \n * @styling\n * - Uses Tailwind CSS for consistent styling\n * - Supports custom className for additional styling\n * - Responsive design considerations\n * \n * @dependencies\n * - React 19+ - Component framework and hooks\n * - Lucide React - Icon components\n * - Radix UI - Dropdown menu primitives\n * - React Router (optional) - For navigation handling\n * - Tailwind CSS - Styling system\n */\n\nimport * as React from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../Select\";\nimport { logger } from \"../../utils/core/logger\";\nimport { useNavigationFiltering } from \"./useNavigationFiltering\";\nimport type { NavigationItem, NavigationMenuProps } from \"./types\";\nimport type { Permission } from \"../../rbac/types\";\n\n/**\n * Unified NavigationMenu component that supports both dropdown and hierarchical navigation modes.\n * \n * A flexible navigation menu component with support for icons, current page highlighting,\n * keyboard navigation, and nested menu items.\n * \n * Features:\n * - Dropdown mode: Menu button that opens a dropdown list\n * - Hierarchical mode: Expandable tree navigation with nested items\n * - Icon support for navigation items\n * - Current page highlighting\n * - Keyboard navigation support (Enter, Space, Escape)\n * - Accessible design with proper ARIA attributes\n * - Click outside to close (dropdown mode)\n * - Recursive rendering for nested items (hierarchical mode)\n * \n * @example\n * Basic dropdown navigation (most common use case):\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n * { id: 'reports', label: 'Reports', href: '/reports', icon: 'FileText' },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Main Menu\"\n * showIcons={true}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Hierarchical navigation with nested items:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function SidebarNavigation() {\n * const hierarchicalItems = [\n * { \n * id: 'user-management', \n * label: 'User Management',\n * icon: 'Users',\n * children: [\n * { id: 'users-list', label: 'All Users', href: '/users' },\n * { id: 'users-create', label: 'Create User', href: '/users/create' },\n * { id: 'user-roles', label: 'User Roles', href: '/users/roles' }\n * ]\n * },\n * { \n * id: 'reports', \n * label: 'Reports',\n * icon: 'BarChart',\n * children: [\n * { id: 'sales-reports', label: 'Sales Reports', href: '/reports/sales' },\n * { id: 'user-reports', label: 'User Reports', href: '/reports/users' }\n * ]\n * },\n * { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={hierarchicalItems}\n * mode=\"hierarchical\"\n * currentPath={window.location.pathname}\n * onNavigate={(item) => {\n * if (item.href) {\n * window.location.href = item.href;\n * }\n * }}\n * className=\"w-64 bg-sec-50 p-4\"\n * />\n * );\n * }\n * ```\n * \n * @example\n * Integration with React Router and authentication:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * import { useUnifiedAuth } from '@jmruthers/pace-core/providers';\n * \n * function AuthenticatedNavigation() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * const { hasRole, hasPermission } = useUnifiedAuth();\n * \n * // Build navigation items with permission requirements\n * const navItems = [\n * { \n * id: 'dashboard', \n * label: 'Dashboard', \n * href: '/dashboard', \n * icon: 'LayoutDashboard',\n * permissions: ['dashboard:read']\n * },\n * { \n * id: 'meals', \n * label: 'Meals', \n * href: '/meals', \n * icon: 'UtensilsCrossed',\n * permissions: ['meals:read']\n * },\n * { \n * id: 'admin', \n * label: 'Admin Panel', \n * href: '/admin', \n * icon: 'Shield',\n * roles: ['admin', 'super_admin']\n * },\n * { \n * id: 'profile', \n * label: 'Profile', \n * href: '/profile', \n * icon: 'User'\n * }\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * buttonText=\"Navigation\"\n * navigationLabel=\"Main application navigation\"\n * // Permission filtering is always enabled - no prop needed\n * auditLog={true}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Custom navigation with external links and actions:\n * ```tsx\n * import { NavigationMenu } from '@jmruthers/pace-core';\n * \n * function CustomNavigation() {\n * const handleNavigation = (item) => {\n * if (item.id === 'logout') {\n * // Handle logout action\n * handleLogout();\n * } else if (item.href?.startsWith('http')) {\n * // Handle external links\n * window.open(item.href, '_blank');\n * } else if (item.href) {\n * // Handle internal navigation\n * navigate(item.href);\n * }\n * };\n * \n * const navItems = [\n * { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n * { id: 'help', label: 'Help Center', href: 'https://help.example.com', icon: 'HelpCircle' },\n * { id: 'logout', label: 'Sign Out', icon: 'LogOut' } // No href for actions\n * ];\n * \n * return (\n * <NavigationMenu \n * items={navItems}\n * mode=\"dropdown\"\n * onNavigate={handleNavigation}\n * buttonText=\"Menu\"\n * disabled={false}\n * />\n * );\n * }\n * ```\n * \n * @param props - NavigationMenu component props including items, mode, navigation handlers, and styling options\n * @returns React element with navigation menu functionality\n * \n * @since 0.1.0\n */\nexport const NavigationMenu = React.forwardRef<\n HTMLDivElement,\n NavigationMenuProps\n>(({ \n items, \n mode = 'dropdown',\n currentPath, \n onNavigate, \n className, \n disabled = false,\n buttonText = \"Menu\",\n showIcons = true,\n navigationLabel = \"Main navigation\",\n // NEW: Phase 2 - Enhanced Security Features\n strictMode = true,\n auditLog = true,\n onNavigationAccessDenied,\n onStrictModeViolation,\n itemsPreFiltered = false,\n ...props \n}, ref) => {\n const [expandedItems, setExpandedItems] = React.useState<Set<string>>(new Set());\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n\n const { authContext, rbacContext, filteredItems, permissionMap, hasAnyPermission } =\n useNavigationFiltering({ items, itemsPreFiltered, auditLog });\n\n // Note: Navigation access attempts are logged in handleItemClick, not here\n // This prevents excessive logging on every render\n\n\n // Handle keyboard navigation for hierarchical mode\n const handleHierarchicalKeyDown = (event: React.KeyboardEvent, item: NavigationItem) => {\n switch (event.key) {\n case 'Enter':\n case ' ':\n event.preventDefault();\n if (item.children && item.children.length > 0) {\n toggleExpanded(item.id);\n } else if (item.href) {\n onNavigate?.(item);\n }\n break;\n case 'Escape':\n if (expandedItems.has(item.id)) {\n toggleExpanded(item.id);\n }\n break;\n }\n };\n\n // Toggle expanded state for hierarchical items\n const toggleExpanded = (itemId: string) => {\n const newExpanded = new Set(expandedItems);\n if (newExpanded.has(itemId)) {\n newExpanded.delete(itemId);\n } else {\n newExpanded.add(itemId);\n }\n setExpandedItems(newExpanded);\n };\n\n // Handle navigation item click\n const handleItemClick = (item: NavigationItem) => {\n // NEW: Phase 2 - Enhanced Security Features\n // Log navigation access attempt for audit (minimal logging)\n if (auditLog) {\n // Navigation access attempt logged\n }\n \n // Check if user has permission to access this navigation item\n if (!authContext) {\n // No auth context - allow access (for unauthenticated scenarios)\n if (onNavigate) {\n onNavigate(item);\n } else if (item.href) {\n window.location.href = item.href;\n }\n return;\n }\n \n // Check if item should be visible (already filtered)\n // If item is in filteredItems, it has already passed permission checks in PaceAppLayout\n const isItemVisible = filteredItems.some(filtered => filtered.id === item.id);\n \n // If item is not visible, it was filtered out - don't allow navigation\n if (!isItemVisible) {\n logger.warn('NavigationMenu', 'Navigation attempt to filtered item blocked', {\n itemId: item.id,\n label: item.label,\n href: item.href\n });\n return;\n }\n \n // Check permissions if the item requires them using RBAC hooks\n // Only check if item has explicit permission requirements AND we have permission checking capability\n let hasPermission = true; // Default to true if no permission requirements\n \n // Only check permissions if:\n // 1. Item has explicit permission requirements\n // 2. We have RBAC context\n // 3. We have hasAnyPermission function AND permission map is loaded (not empty)\n if (item.permissions && item.permissions.length > 0 && rbacContext && hasAnyPermission && permissionMap && Object.keys(permissionMap).length > 0) {\n // Convert string permissions to Permission type and check\n const permissions = item.permissions\n .filter((p): p is string => typeof p === 'string')\n .map(p => p as Permission);\n \n if (permissions.length > 0) {\n hasPermission = hasAnyPermission(permissions);\n }\n }\n \n // If permission check failed, try role-based access\n if (!hasPermission && rbacContext) {\n // Check roles if permissions check failed or item has role requirements\n if (item.roles && item.roles.length > 0) {\n hasPermission = item.roles.some(role => {\n if (typeof role !== 'string') return true;\n \n // Map role strings to RBAC role checks (same logic as filtering)\n switch (role.toLowerCase()) {\n case 'super_admin':\n case 'super admin':\n return rbacContext.isSuperAdmin;\n case 'org_admin':\n case 'org admin':\n case 'admin':\n return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;\n case 'event_admin':\n case 'event admin':\n return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;\n default:\n // For other roles, check against organisationRole or eventAppRole\n return (\n rbacContext.organisationRole === role ||\n rbacContext.eventAppRole === role ||\n rbacContext.isSuperAdmin\n );\n }\n });\n }\n }\n \n // If permission map is empty but item is in filteredItems, trust PaceAppLayout's filtering\n // This handles the case where NavigationMenu's usePermissions returns empty map\n // but PaceAppLayout already filtered items correctly\n if (!hasPermission && (!permissionMap || Object.keys(permissionMap).length === 0) && isItemVisible) {\n // Permission map is empty but item passed filtering - trust PaceAppLayout\n // Permission map empty but item passed filtering - trusting PaceAppLayout (removed verbose logging)\n hasPermission = true;\n }\n \n if (!hasPermission) {\n // Handle access denied\n if (onNavigationAccessDenied) {\n onNavigationAccessDenied(item);\n }\n \n if (strictMode) {\n logger.error('NavigationMenu', 'STRICT MODE VIOLATION: User attempted to access protected navigation item without permission', {\n itemId: item.id,\n label: item.label,\n href: item.href,\n permissions: item.permissions,\n roles: item.roles,\n accessLevel: item.accessLevel,\n timestamp: new Date().toISOString()\n });\n \n if (onStrictModeViolation) {\n onStrictModeViolation(item, 'Insufficient permissions');\n }\n }\n \n return; // Don't navigate if access is denied\n }\n \n if (onNavigate) {\n onNavigate(item);\n } else if (item.href) {\n // Default navigation behavior\n window.location.href = item.href;\n }\n };\n\n // Check if item is currently active\n const isActiveItem = (item: NavigationItem): boolean => {\n if (currentPath === item.href) return true;\n if (item.children && item.children.length > 0) {\n return item.children.some(child => isActiveItem(child));\n }\n return false;\n };\n\n // Handle navigation item selection\n const handleNavigationSelect = (itemId: string) => {\n const item = filteredItems.find(i => i.id === itemId);\n if (item) {\n handleItemClick(item);\n }\n };\n\n // Render hierarchical navigation item\n const renderHierarchicalItem = (item: NavigationItem, level: number = 0) => {\n const hasChildren = item.children && item.children.length > 0;\n const isExpanded = expandedItems.has(item.id);\n const itemIsActive = isActiveItem(item);\n\n return (\n <li role=\"none\">\n {hasChildren ? (\n <div>\n <button\n onClick={() => toggleExpanded(item.id)}\n onKeyDown={(e) => handleHierarchicalKeyDown(e, item)}\n aria-expanded={isExpanded}\n aria-controls={`submenu-${item.id}`}\n aria-current={itemIsActive ? \"page\" : undefined}\n >\n <span>{item.label}</span>\n <ChevronDown aria-hidden=\"true\" />\n </button>\n \n {isExpanded && item.children && (\n <ul\n id={`submenu-${item.id}`}\n role=\"menu\"\n aria-label={`${item.label} submenu`}\n >\n {item.children.map(child => (\n <React.Fragment key={child.id}>\n {renderHierarchicalItem(child, level + 1)}\n </React.Fragment>\n ))}\n </ul>\n )}\n </div>\n ) : (\n <a\n href={item.href || '#'}\n onClick={(e) => {\n if (onNavigate && item.href) {\n e.preventDefault();\n onNavigate(item);\n }\n }}\n onKeyDown={(e) => handleHierarchicalKeyDown(e, item)}\n role=\"menuitem\"\n aria-current={itemIsActive ? \"page\" : undefined}\n >\n {item.label}\n </a>\n )}\n </li>\n );\n };\n\n // Render based on mode\n if (mode === 'dropdown') {\n return (\n <Select \n onValueChange={handleNavigationSelect}\n className={className}\n data-testid=\"navigation-menu-root\"\n >\n <SelectTrigger \n ref={buttonRef}\n disabled={disabled} \n aria-label={buttonText}\n data-testid=\"navigation-menu-trigger\"\n >\n <SelectValue placeholder={buttonText} />\n </SelectTrigger>\n <SelectContent>\n {filteredItems.map((item) => {\n const isActive = isActiveItem(item);\n return (\n <SelectItem\n key={item.id}\n value={item.id}\n disabled={!item.href}\n data-testid={`navigation-menu-item-${item.id}`}\n >\n {item.label}\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n );\n }\n\n // Hierarchical mode\n return (\n <nav \n ref={ref}\n className={className}\n aria-label={navigationLabel}\n {...props}\n >\n <ul role=\"menubar\">\n {filteredItems.map(item => (\n <React.Fragment key={item.id}>\n {renderHierarchicalItem(item, 0)}\n </React.Fragment>\n ))}\n </ul>\n </nav>\n );\n});\n\nNavigationMenu.displayName = \"NavigationMenu\";\n\nexport type {\n NavigationMode,\n NavigationItemMeta,\n NavigationItem,\n NavigationMenuProps,\n} from \"./types\";\n","import * as React from \"react\";\nimport { useUnifiedAuth } from \"../../providers/services/UnifiedAuthProvider\";\nimport { useRBAC } from \"../../rbac/hooks/useRBAC\";\nimport { useResolvedScope } from \"../../rbac/hooks\";\nimport { usePermissions } from \"../../rbac/hooks/usePermissions\";\nimport type {\n Permission,\n AccessLevel as RBACAccessLevel,\n UUID,\n PermissionMap,\n} from \"../../rbac/types\";\nimport { logger } from \"../../utils/core/logger\";\nimport type { NavigationItem } from \"./types\";\n\n/**\n * Options for the useNavigationFiltering hook.\n */\ninterface UseNavigationFilteringOptions {\n items: NavigationItem[];\n itemsPreFiltered?: boolean;\n auditLog?: boolean;\n}\n\n/**\n * Return value of the useNavigationFiltering hook.\n */\ninterface UseNavigationFilteringResult {\n authContext: ReturnType<typeof useUnifiedAuth> | null;\n rbacContext: ReturnType<typeof useRBAC> | null;\n filteredItems: NavigationItem[];\n permissionMap: PermissionMap;\n hasAnyPermission: ((permissions: Permission[]) => boolean) | null;\n}\n\n/**\n * Hook for filtering navigation items based on RBAC permissions.\n * Filters navigation items to show only those the user has access to.\n * \n * @param options - Navigation filtering configuration\n * @returns Filtered navigation items and permission context\n */\nexport function useNavigationFiltering({\n items,\n itemsPreFiltered = false,\n auditLog = true,\n}: UseNavigationFilteringOptions): UseNavigationFilteringResult {\n const [resolvedAppId, setResolvedAppId] = React.useState<string | undefined>(undefined);\n const previousFilteredItemsRef = React.useRef<NavigationItem[]>([]);\n\n let authContext = null;\n try {\n authContext = useUnifiedAuth();\n } catch (error) {\n logger.warn(\n \"NavigationMenu\",\n \"useUnifiedAuth not available, running in unauthenticated mode\",\n );\n }\n\n let rbacContext = null;\n try {\n rbacContext = useRBAC();\n } catch (error) {\n logger.warn(\n \"NavigationMenu\",\n \"useRBAC not available, permission filtering disabled\",\n );\n }\n\n const eventLoadingRaw = authContext?.eventLoading;\n const eventLoading = eventLoadingRaw ?? false;\n const selectedEvent = authContext?.selectedEvent || null;\n const orgContextReady =\n authContext?.isContextReady ?? (authContext?.selectedOrganisation?.id ? true : false);\n\n const { supabase } = authContext || {};\n const { selectedOrganisation } = authContext || {};\n const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({\n supabase: itemsPreFiltered ? null : supabase || null,\n selectedOrganisationId: itemsPreFiltered ? null : selectedOrganisation?.id || null,\n selectedEventId: itemsPreFiltered ? null : selectedEvent?.event_id || null,\n });\n\n React.useEffect(() => {\n if (\n !scopeLoading &&\n !resolvedScope?.appId &&\n selectedOrganisation?.id &&\n authContext?.appName &&\n authContext?.user?.id &&\n !resolvedAppId\n ) {\n if (!authContext.user || !authContext.appName) {\n return;\n }\n const userId = authContext.user.id;\n const appName = authContext.appName;\n import(\"../../rbac/api\")\n .then(({ resolveAppContext }) => {\n resolveAppContext({\n userId,\n appName,\n })\n .then((result) => {\n if (result?.appId) {\n setResolvedAppId(result.appId);\n }\n })\n .catch(() => {});\n })\n .catch(() => {});\n }\n }, [\n scopeLoading,\n resolvedScope?.appId,\n selectedOrganisation?.id,\n authContext?.appName,\n authContext?.user?.id,\n resolvedAppId,\n ]);\n\n const effectiveScope = React.useMemo(() => {\n if (resolvedScope?.organisationId) {\n return resolvedScope;\n }\n\n if (selectedOrganisation?.id) {\n const fallbackScope = {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: resolvedAppId,\n };\n return fallbackScope;\n }\n\n return null;\n }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id, resolvedAppId]);\n\n const scopeKey = effectiveScope\n ? `${effectiveScope.organisationId || \"\"}-${effectiveScope.eventId || \"\"}-${\n effectiveScope.appId || \"\"\n }`\n : \"empty\";\n\n const stableScope = React.useMemo(() => {\n if (effectiveScope?.organisationId) {\n return {\n organisationId: effectiveScope.organisationId,\n eventId: effectiveScope.eventId,\n appId: effectiveScope.appId,\n };\n }\n return {\n organisationId: \"\",\n eventId: undefined,\n appId: undefined,\n };\n }, [scopeKey, effectiveScope]);\n\n const userId = (authContext?.user?.id || \"\") as UUID;\n const {\n permissions: permissionMap,\n hasAnyPermission,\n isLoading: permissionsLoading,\n error: permissionsError,\n } = usePermissions(\n itemsPreFiltered ? (null as any) : userId,\n itemsPreFiltered ? undefined : stableScope.organisationId,\n itemsPreFiltered ? undefined : stableScope.eventId,\n itemsPreFiltered ? undefined : stableScope.appId,\n );\n\n const filteredItems = React.useMemo(() => {\n if (itemsPreFiltered && items && items.length > 0) {\n const visibleItems = (items || []).filter((item) => !item.meta?.hidden);\n previousFilteredItemsRef.current = visibleItems;\n return visibleItems;\n }\n\n const isOrgContextReady = orgContextReady && selectedOrganisation?.id;\n const isEventContextReady = eventLoadingRaw === undefined ? true : !eventLoading;\n const hasValidContext = isOrgContextReady && isEventContextReady;\n const shouldWaitForScope = scopeLoading || !hasValidContext;\n const shouldRetryAfterError = scopeError && hasValidContext && !scopeLoading;\n\n if (items && items.length > 0 && selectedOrganisation?.id) {\n const visibleItems = (items || []).filter((item) => !item.meta?.hidden);\n previousFilteredItemsRef.current = visibleItems;\n return visibleItems;\n }\n\n if (!authContext || !rbacContext || (shouldWaitForScope && !shouldRetryAfterError)) {\n return [];\n }\n\n if (permissionsLoading) {\n if (previousFilteredItemsRef.current.length > 0) {\n return previousFilteredItemsRef.current;\n }\n if (items && items.length > 0 && stableScope.organisationId) {\n return (items || []).filter((item) => !item.meta?.hidden);\n }\n return [];\n }\n\n if (permissionsError) {\n logger.warn(\n \"NavigationMenu\",\n \"Permission check error - showing no items for security\",\n {\n permissionsError: permissionsError?.message,\n },\n );\n return [];\n }\n\n if (!permissionMap || Object.keys(permissionMap).length === 0) {\n if (stableScope.organisationId && items && items.length > 0) {\n return (items || []).filter((item) => !item.meta?.hidden);\n }\n\n if (stableScope.organisationId) {\n logger.warn(\"NavigationMenu\", \"Permission map is empty and no items provided - showing nothing\", {\n permissionMapSize: 0,\n organisationId: stableScope.organisationId,\n eventId: stableScope.eventId,\n appId: stableScope.appId,\n });\n }\n return [];\n }\n\n const getPageIdFromHref = (href?: string): string | null => {\n if (!href) return null;\n const path = href.split(\"?\")[0].split(\"#\")[0].replace(/^\\//, \"\");\n return path || \"home\";\n };\n\n const hasItemPermission = (item: NavigationItem): boolean => {\n if (item.permissions && item.permissions.length > 0 && !item.href) {\n const permissions = item.permissions\n .filter((p): p is string => typeof p === \"string\")\n .map((p) => p as Permission);\n\n if (permissions.length > 0) {\n const hasPermission = hasAnyPermission?.(permissions);\n if (!hasPermission) {\n return false;\n }\n }\n }\n\n if (item.roles && item.roles.length > 0) {\n const hasRole = item.roles.some((role) => {\n if (typeof role !== \"string\") return true;\n\n switch (role.toLowerCase()) {\n case \"super_admin\":\n case \"super admin\":\n return rbacContext.isSuperAdmin;\n case \"org_admin\":\n case \"org admin\":\n case \"admin\":\n return rbacContext.isOrgAdmin || rbacContext.isSuperAdmin;\n case \"event_admin\":\n case \"event admin\":\n return rbacContext.isEventAdmin || rbacContext.isSuperAdmin;\n default:\n return (\n rbacContext.organisationRole === role ||\n rbacContext.eventAppRole === role ||\n rbacContext.isSuperAdmin\n );\n }\n });\n if (!hasRole) {\n return false;\n }\n }\n\n if (item.accessLevel) {\n if (typeof item.accessLevel === \"string\") {\n const accessLevel = item.accessLevel.toLowerCase() as RBACAccessLevel;\n const userEventRole = rbacContext.eventAppRole;\n\n if (!rbacContext.isSuperAdmin) {\n const roleToAccessLevel: Record<string, RBACAccessLevel> = {\n viewer: \"viewer\",\n participant: \"participant\",\n planner: \"planner\",\n event_admin: \"admin\",\n };\n const userAccessLevel = userEventRole ? roleToAccessLevel[userEventRole] || \"viewer\" : null;\n\n const levelHierarchy: Record<RBACAccessLevel, number> = {\n viewer: 1,\n participant: 2,\n planner: 3,\n admin: 4,\n super: 5,\n };\n const requiredLevel = levelHierarchy[accessLevel] || 0;\n const userLevel = userAccessLevel ? levelHierarchy[userAccessLevel] || 0 : 0;\n\n if (userLevel < requiredLevel) {\n return false;\n }\n }\n }\n }\n\n if (item.href) {\n const pageId = item.pageId || getPageIdFromHref(item.href);\n if (pageId) {\n const pagePermission: Permission = `read:page.${pageId}` as Permission;\n\n const isSuperAdmin = permissionMap[\"*\"] === true;\n const hasPagePermission = permissionMap[pagePermission] === true;\n const finalHasPermission = isSuperAdmin || hasPagePermission;\n\n if (!finalHasPermission) {\n return false;\n }\n }\n }\n\n return true;\n };\n\n const filterItem = (item: NavigationItem): NavigationItem | null => {\n if (item.meta?.hidden) return null;\n\n if (!hasItemPermission(item)) return null;\n\n let filteredChildren: NavigationItem[] | undefined;\n if (item.children && item.children.length > 0) {\n filteredChildren = item.children\n .map((child) => filterItem(child))\n .filter((child): child is NavigationItem => child !== null);\n\n if (filteredChildren.length === 0 && !item.href) {\n return null;\n }\n }\n\n return {\n ...item,\n children: filteredChildren,\n };\n };\n\n const filtered = (items || [])\n .map((item) => filterItem(item))\n .filter((item): item is NavigationItem => item !== null);\n\n previousFilteredItemsRef.current = filtered;\n\n return filtered;\n }, [\n items,\n itemsPreFiltered,\n authContext,\n rbacContext,\n permissionMap,\n hasAnyPermission,\n scopeLoading,\n scopeError,\n permissionsLoading,\n resolvedScope,\n effectiveScope,\n auditLog,\n eventLoadingRaw,\n eventLoading,\n selectedEvent,\n orgContextReady,\n selectedOrganisation?.id,\n permissionsError,\n stableScope.organisationId,\n stableScope.eventId,\n stableScope.appId,\n ]);\n\n return {\n authContext,\n rbacContext,\n filteredItems,\n permissionMap,\n hasAnyPermission: hasAnyPermission || null,\n };\n}\n","/**\n * @file Header Component\n * @package @jmruthers/pace-core\n * @module Components/Header\n * @since 0.1.0\n *\n * A comprehensive header component for application layouts with navigation,\n * user menu, organisation selector, event selector, and customizable branding.\n *\n * Features:\n * - Customizable logo (URL or component)\n * - Clickable logo that routes to dashboard (configurable)\n * - Navigation menu integration\n * - User menu with authentication\n * - Organisation selector for multi-organisation applications\n * - Event selector for multi-tenant applications\n * - Custom actions support\n * - Responsive design\n * - Accessibility compliant\n * - Backdrop blur effects\n * - Flexible layout options\n *\n * @example\n * ```tsx\n * // Basic header with logo and user menu (logo routes to /dashboard by default)\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoAlt=\"My App\"\n * logoHref=\"/dashboard\"\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header with navigation and custom actions\n * <Header\n * logo={<CustomLogo />}\n * logoHref=\"/home\"\n * navItems={[\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard' },\n * { id: 'users', label: 'Users', href: '/users' },\n * { id: 'settings', label: 'Settings', href: '/settings' }\n * ]}\n * currentPath=\"/dashboard\"\n * actions={\n * <>\n * <Button variant=\"outline\">Export</Button>\n * <Button>New Item</Button>\n * </>\n * }\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header without context selector\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoHref=\"/dashboard\"\n * showContextSelector={false}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header with custom user menu\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoHref=\"/home\"\n * userMenu={<CustomUserMenu user={currentUser} />}\n * showUserMenu={true}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML with role=\"banner\"\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - High contrast support\n * - Focus management\n *\n * @dependencies\n * - @supabase/supabase-js - User authentication\n * - React 19+ - Component framework\n * - Tailwind CSS - Styling\n * - NavigationMenu component\n * - UserMenu component\n * - ContextSelector component (unified org/event selector)\n */\n\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { User } from '@supabase/supabase-js';\nimport { cn } from '../../utils/core/cn';\nimport { ContextSelector } from '../ContextSelector';\nimport { UserMenu } from '../UserMenu';\nimport { NavigationMenu } from '../NavigationMenu';\nimport type { NavigationItem } from '../NavigationMenu';\nimport type { PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport type { Event } from '../../types/event';\n\n/**\n * Props for the Header component\n */\nexport interface HeaderProps {\n /** URL to the app logo image */\n logoUrl?: string;\n /** Alt text for the logo */\n logoAlt?: string;\n /** Custom logo component (overrides logoUrl) */\n logo?: React.ReactNode;\n /** Navigation items for the menu - uses NavigationItem interface */\n navItems?: NavigationItem[];\n /** Current user for the user menu */\n user?: User | null;\n /** Sign out handler for user menu */\n onSignOut?: () => Promise<void>;\n /** Password change handler for user menu */\n onChangePassword?: (newPassword: string, confirmPassword: string) => Promise<{ error?: PasswordChangeFormError }>;\n /** Additional actions to display (will be placed between event selector and user menu) */\n actions?: React.ReactNode;\n /** Custom user menu component (overrides default UserMenu) */\n userMenu?: React.ReactNode;\n /** Custom className */\n className?: string;\n /** Show/hide context selector (unified org/event selector) - default: true */\n showContextSelector?: boolean;\n /** Show organisations in context selector - default: true */\n showOrganisations?: boolean;\n /** Show events in context selector - default: true */\n showEvents?: boolean;\n /** Show/hide user menu */\n showUserMenu?: boolean;\n /** Current path for navigation highlighting */\n currentPath?: string;\n /** Custom navigation handler */\n onNavigate?: (item: NavigationItem) => void;\n /** URL to navigate to when logo is clicked (e.g., '/dashboard') */\n logoHref?: string;\n}\n\n/**\n * Header component for application layouts with comprehensive navigation, user management, \n * and customizable branding support.\n * \n * A flexible header component that supports various configurations including custom logos,\n * navigation menus, user authentication, event selection, and custom actions.\n * \n * **Logo Display:** When used via PaceAppLayout, the logo URL is automatically constructed\n * from the appName prop as `/${appName.toLowerCase()}_logo_wide.svg`. The appName should\n * come from an APP_NAME constant declared in your App.tsx file to ensure consistency across\n * authenticated and public pages.\n * \n * Features:\n * - Customizable logo (URL or custom component)\n * - Clickable logo that automatically routes to dashboard (configurable via logoHref)\n * - Navigation menu integration with highlighting\n * - User menu with authentication and password management\n * - Event selector for multi-tenant applications\n * - Custom actions support\n * - Responsive design with mobile considerations\n * - Accessibility compliant with proper ARIA attributes\n * - Backdrop blur effects for modern UI\n * - Flexible layout with configurable sections\n *\n * @example\n * Basic header with logo and navigation (logo routes to /dashboard when clicked):\n * ```tsx\n * import { Header } from '@jmruthers/pace-core';\n * import { useNavigate, useLocation } from 'react-router-dom';\n * \n * function AppHeader() {\n * const navigate = useNavigate();\n * const location = useLocation();\n * \n * const navItems = [\n * { id: 'dashboard', label: 'Dashboard', href: '/dashboard' },\n * { id: 'meals', label: 'Meals', href: '/meals' },\n * { id: 'settings', label: 'Settings', href: '/settings' }\n * ];\n * \n * return (\n * <Header\n * logoUrl=\"/company-logo.svg\"\n * logoAlt=\"My Company\"\n * logoHref=\"/dashboard\"\n * navItems={navItems}\n * currentPath={location.pathname}\n * onNavigate={(item) => navigate(item.href)}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Header with custom actions:\n * ```tsx\n * import { Header, Button } from '@jmruthers/pace-core';\n * \n * function HeaderWithActions() {\n * const customActions = (\n * <>\n * <Button variant=\"outline\" size=\"sm\">Export</Button>\n * <Button size=\"sm\">New Item</Button>\n * </>\n * );\n * \n * return (\n * <Header\n * logoUrl=\"/logo.svg\"\n * navItems={navigationItems}\n * actions={customActions}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @example\n * Minimal header configuration:\n * ```tsx\n * function MinimalHeader() {\n * return (\n * <Header\n * logoUrl=\"/simple-logo.svg\"\n * logoAlt=\"Simple App\"\n * showContextSelector={false}\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * );\n * }\n * ```\n * \n * @param props - Header configuration including logo, navigation, user settings, and custom content\n * @returns React element with complete header functionality\n * \n * @since 0.1.0\n */\n/**\n * Header component for application layouts.\n * Provides navigation, user menu, organisation/event selectors, and customizable branding.\n * \n * @param props - Header configuration\n * @returns The rendered header\n */\nexport function Header({\n logoUrl,\n logoAlt = 'Logo',\n logo,\n navItems = [],\n user,\n onSignOut,\n onChangePassword,\n actions,\n userMenu,\n className,\n showContextSelector = true,\n showOrganisations = true,\n showEvents = true,\n showUserMenu = true,\n currentPath,\n onNavigate,\n logoHref\n}: HeaderProps) {\n // Determine if context selector should be shown\n const shouldShowContextSelector = showContextSelector !== false;\n \n // Get hooks for context selector\n const { switchOrganisation } = useOrganisations();\n const { events, setSelectedEvent } = useEvents();\n\n return (\n <header className={cn(\n \"w-full border-b border-main-200 h-16 shadow-sm bg-main-100 \",\n className\n )} role=\"banner\">\n <nav className=\"px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_1fr_auto_auto_auto_auto] items-center gap-4 h-full\">\n {/* Logo */}\n {logo ? (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n {logo}\n </Link>\n ) : (\n logo\n )\n ) : logoUrl ? (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n <img\n src={logoUrl}\n alt={logoAlt || 'Logo'}\n className=\"h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent\"\n />\n </Link>\n ) : (\n <img\n src={logoUrl}\n alt={logoAlt || 'Logo'}\n className=\"h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent\"\n />\n )\n ) : (\n logoHref ? (\n <Link to={logoHref} className=\"cursor-pointer hover:opacity-80 transition-opacity\">\n <img\n src=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E\"\n alt={logoAlt || 'Logo'}\n className=\"size-8 shadow-md\"\n />\n </Link>\n ) : (\n <img\n src=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E\"\n alt={logoAlt || 'Logo'}\n className=\"size-8 shadow-md\"\n />\n )\n )}\n\n {/* Navigation Menu */}\n {navItems && navItems.length > 0 && (\n <NavigationMenu\n items={navItems}\n currentPath={currentPath}\n onNavigate={onNavigate}\n buttonText=\"Menu\"\n className=\"w-48\"\n itemsPreFiltered={true}\n />\n )}\n\n {/* Unified Context Selector - Shows all accessible orgs and events */}\n {shouldShowContextSelector ? (\n <ContextSelector\n placeholder=\"Select organisation or event\"\n className={cn(\n \"w-96\",\n // Adjust width based on whether actions exist\n actions ? \"col-span-1\" : \"col-span-2\"\n )}\n showOrganisations={showOrganisations}\n showEvents={showEvents}\n onOrganisationSelect={async (org) => {\n // When switching to an organisation, clear event selection FIRST\n // This ensures the userClearedEventRef flag is set before any event refresh\n // This prevents auto-selection from re-selecting the event\n setSelectedEvent(null);\n // Then switch organisation (this may trigger event refresh, but flag is already set)\n await switchOrganisation(org.id);\n }}\n onEventSelect={(event) => {\n // Find the full event object from the events list\n const fullEvent = events.find((e: Event) => (e.event_id || e.id) === (event.event_id || event.id));\n setSelectedEvent(fullEvent || event);\n }}\n compact={true}\n />\n ) : null}\n \n {/* Custom Actions */}\n {actions}\n \n {/* User Menu */}\n {showUserMenu && (\n userMenu ? (\n userMenu\n ) : (\n <UserMenu\n user={user || null}\n onSignOut={onSignOut}\n onChangePassword={onChangePassword}\n className=\"w-70\"\n />\n )\n )}\n\n </nav>\n </header>\n );\n}\n","/**\n * @file Footer Component\n * @package @jmruthers/pace-core\n * @module Components/Footer\n * @since 0.1.0\n *\n * A flexible footer component for application layouts with copyright information,\n * navigation links, and customizable content.\n *\n * Features:\n * - Copyright information with automatic year generation\n * - Customizable company name and branding\n * - Optional navigation links\n * - Logo display support\n * - Custom footer content via children\n * - Responsive design\n * - Accessibility compliant\n * - Flexible layout options\n * - Consistent styling with design system\n *\n * @example\n * ```tsx\n * // Basic footer with default copyright\n * <Footer />\n * \n * // Footer with custom company name and year\n * <Footer \n * companyName=\"My Company Inc.\"\n * year={2024}\n * />\n * \n * // Footer with navigation links\n * <Footer\n * companyName=\"My Company\"\n * links={[\n * { label: 'Privacy Policy', href: '/privacy' },\n * { label: 'Terms of Service', href: '/terms' },\n * { label: 'Contact', href: '/contact' }\n * ]}\n * />\n * \n * // Footer with logo and custom copyright\n * <Footer\n * logo=\"/logo.svg\"\n * copyright=\"© 2024 My Company. All rights reserved.\"\n * />\n * \n * // Footer with custom content\n * <Footer companyName=\"My Company\">\n * <section className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-8\">\n * <section>\n * <h3 className=\"font-semibold mb-2\">About Us</h3>\n * <p className=\"text-sm text-muted-foreground\">\n * We provide innovative solutions for modern businesses.\n * </p>\n * </section>\n * <section>\n * <h3 className=\"font-semibold mb-2\">Contact</h3>\n * <p className=\"text-sm text-muted-foreground\">\n * Email: info@mycompany.com<br />\n * Phone: (555) 123-4567\n * </p>\n * </section>\n * <section>\n * <h3 className=\"font-semibold mb-2\">Follow Us</h3>\n * <nav className=\"flex gap-2\">\n * <a href=\"#\" className=\"text-muted-foreground hover:text-foreground\">Twitter</a>\n * <a href=\"#\" className=\"text-muted-foreground hover:text-foreground\">LinkedIn</a>\n * </nav>\n * </section>\n * </section>\n * </Footer>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML with role=\"contentinfo\"\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - High contrast support\n * - Clear link identification\n *\n * @dependencies\n * - React 19+ - Component framework\n * - Tailwind CSS - Styling\n */\nimport React from 'react';\nimport { cn } from '../../utils/core/cn';\n\n/**\n * Props for the Footer component.\n */\nexport interface FooterProps {\n /**\n * Company or organization name\n */\n companyName?: string;\n\n /**\n * Current year or custom year for copyright\n * @default current year\n */\n year?: number;\n\n /**\n * Optional array of navigation links to display\n */\n links?: Array<{\n label: string;\n href: string;\n }>;\n\n /**\n * Optional CSS class name\n */\n className?: string;\n\n /**\n * Logo image URL (from UI version)\n */\n logo?: string;\n\n /**\n * Copyright text (from UI version)\n */\n copyright?: string;\n\n /**\n * Footer content - children to render inside footer\n */\n children?: React.ReactNode;\n}\n\n/**\n * Footer component that displays copyright information and navigation\n * \n * @example\n * ```tsx\n * // Basic usage\n * <Footer />\n * \n * // With children\n * <Footer>\n * <section>Custom footer content</section>\n * </Footer>\n * \n * // With logo and copyright\n * <Footer logo=\"/logo.png\" copyright=\"© 2024 Company. All rights reserved.\" />\n * ```\n */\nconst FooterComponent: React.FC<FooterProps> = ({\n companyName = 'Solvera Solutions Pty Ltd',\n year = new Date().getFullYear(),\n links,\n className = '',\n logo,\n copyright,\n children\n}) => {\n // Use custom copyright if provided, otherwise generate default\n const copyrightText = copyright || `© Copyright 2022–${year} all rights reserved, ${companyName}.`;\n\n return (\n <footer className={cn('mt-8 py-6 flex justify-center border-t border-border bg-main-100', className)}>\n\n <section className='px-4 w-[min(var(--app-width),100%)] mx-auto text-center'>\n {logo && (\n <img src={logo} alt=\"Logo\" className=\"h-8 w-auto\" />\n )}\n\n {children && (\n <>\n {children}\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {copyrightText}\n </span>\n\n {links && links.length > 0 && (\n <ul className=\"flex gap-4 mt-2 md:mt-0\">\n {links.map((link, index) => (\n <li key={index}>\n <a href={link.href} className=\"text-muted-foreground hover:text-foreground\">\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n )}\n </section>\n </footer>\n );\n};\n\nFooterComponent.displayName = 'Footer';\n\nexport const Footer = React.memo(FooterComponent);\nFooter.displayName = 'Footer';\n","/**\n * @file PACE App Layout Component\n * @package @jmruthers/pace-core\n * @module Components/PaceAppLayout\n * @since 0.1.0\n *\n * A comprehensive application layout component that provides a consistent\n * structure for all PACE suite applications with header, navigation, and footer.\n * \n * NEW: Layout-level permission enforcement to ensure consuming apps can't\n * forget to implement permission checks on individual pages.\n *\n * Features:\n * - Consistent application layout structure\n * - Header with logo, navigation, and user menu\n * - Footer with copyright and links\n * - React Router integration with Outlet\n * - Unified authentication integration\n * - Navigation menu with configurable items\n * - User sign-out functionality\n * - Password change capability\n * - Responsive design\n * - Accessibility compliant\n * - Flexible content area\n * - Branding support\n * - Layout-level permission enforcement\n * - Automatic page permission validation\n * - Permission-based navigation filtering\n *\n * @example\n * ```tsx\n * // Basic app layout with React Router (RECOMMENDED)\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={<PaceAppLayout appName=\"My Application\" />}>\n * <Route index element={<HomePage />} />\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"settings\" element={<SettingsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * \n * // App layout with custom permission configuration\n * function MyApp() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"My App\">\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"My Application\"\n * enforcePermissions={true}\n * defaultPermission=\"read\"\n * permissionFallback={<AccessDeniedPage />}\n * />\n * }>\n * <Route index element={<HomePage />} />\n * <Route path=\"events\" element={<EventsPage />} />\n * <Route path=\"reports\" element={<ReportsPage />} />\n * <Route path=\"admin\" element={<AdminPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * \n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly navigation\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear content hierarchy\n * - Consistent navigation patterns\n *\n * @routing\n * - React Router v6 integration\n * - Nested route support\n * - Dynamic navigation handling\n * - Path-based navigation\n * - Route outlet rendering\n * - Permission-based route protection\n *\n * @dependencies\n * - React 19+ - Component framework\n * - React Router v6 - Routing\n * - UnifiedAuthProvider - Authentication\n * - usePermissionCache - Permission management\n * - Header component\n * - Footer component\n * - Button component\n * - NavigationMenu types\n * - Tailwind CSS - Styling\n */\n\nimport React, { useState, useEffect, useMemo, useCallback } from 'react';\nimport { Outlet, useNavigate, useLocation } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport { useCan, useResolvedScope, useRBAC } from '../../rbac/hooks';\nimport { createScopeFromEvent } from '../../rbac/utils/eventContext';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { isSuperAdmin as checkSuperAdminApi } from '../../rbac/api';\nimport { logger } from '../../utils/core/logger';\nimport type { Permission, Scope } from '../../rbac/types';\nimport { EventContextRequiredError, OrganisationContextRequiredError } from '../../rbac/types';\n\n// Stable empty objects to prevent infinite loops\nconst EMPTY_PAGE_ID_MAPPING = {};\nconst EMPTY_ROUTE_PERMISSIONS = {};\nimport { Button } from '../Button';\nimport { Footer } from '../Footer';\nimport { Header } from '../Header';\nimport type { NavigationItem } from '../NavigationMenu/NavigationMenu';\nimport type { PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';\n// Define Operation type locally since old RBAC types are removed\ntype Operation = 'read' | 'create' | 'update' | 'delete' | 'manage';\n\n/**\n * Props for the PaceAppLayout component.\n * Configures the application layout including navigation, header, and footer.\n */\nexport interface PaceAppLayoutProps {\n /** The name of the application to be displayed in the header. */\n appName: string;\n /** Optional navigation items for the header menu. If not provided, uses default navigation. */\n navItems?: NavigationItem[];\n /** Show/hide unified context selector (shows all accessible orgs and events) - default: true */\n showContextSelector?: boolean;\n /** Show organisations in context selector - default: true */\n showOrganisations?: boolean;\n /** Show events in context selector - default: true */\n showEvents?: boolean;\n /** Custom actions to display in the header (between event selector and user menu) */\n headerActions?: React.ReactNode;\n /** Custom logo component (overrides default logo) */\n customLogo?: React.ReactNode;\n /** URL to navigate to when logo is clicked (defaults to '/dashboard') */\n logoHref?: string;\n /** Custom user menu component (overrides default user menu) */\n customUserMenu?: React.ReactNode;\n /** Custom className for the header */\n headerClassName?: string;\n /** Show/hide user menu */\n showUserMenu?: boolean;\n /** Enable layout-level permission enforcement */\n enforcePermissions?: boolean;\n /** Default permission to check for all routes (when enforcePermissions is true) */\n defaultPermission?: Operation;\n /** Route-specific permissions mapping */\n routePermissions?: Record<string, Operation>;\n /** Fallback component to show when user lacks permission */\n permissionFallback?: React.ReactNode;\n /** Custom permission page ID mapping */\n pageIdMapping?: Record<string, string>;\n \n // NEW: Phase 1 - Enhanced Security Features\n /** Enable strict mode to prevent bypassing permission checks (default: true) */\n strictMode?: boolean;\n /** Enable page-level permission enforcement (default: false) */\n enforcePagePermissions?: boolean;\n /** Default page permission fallback component */\n pagePermissionFallback?: React.ReactNode;\n /** Enable audit logging for all permission checks (default: true) */\n auditLog?: boolean;\n /** Callback when page access is denied */\n onPageAccessDenied?: (pageName: string, operation: string) => void;\n /** Callback when strict mode violation occurs */\n onStrictModeViolation?: (pageName: string, operation: string) => void;\n \n // NEW: Phase 2 - Enhanced Routing Features\n /** Enable role-based routing (default: false) */\n roleBasedRouting?: boolean;\n /** Route configuration for role-based routing */\n routeConfig?: Array<{\n path: string;\n component: React.ComponentType;\n permissions: string[];\n roles?: string[];\n accessLevel?: string;\n pageId?: string;\n strictMode?: boolean;\n meta?: {\n title?: string;\n description?: string;\n requiresAuth?: boolean;\n hidden?: boolean;\n };\n }>;\n /** Fallback route for unauthorized access */\n fallbackRoute?: string;\n /** Callback when route access is denied */\n onRouteAccessDenied?: (route: string, reason: string) => void;\n /** Callback when route strict mode violation occurs */\n onRouteStrictModeViolation?: (route: string, reason: string) => void;\n}\n\n/**\n * A consistent layout component for all PACE suite applications that provides a standard\n * structure with header, main content area, and footer.\n * \n * NEW: This component now includes layout-level permission enforcement to ensure\n * consuming apps can't forget to implement permission checks on individual pages.\n * \n * This component is designed to work with React Router's nested routing pattern using\n * Outlet to render child routes. It provides integrated authentication, navigation,\n * and user management functionality.\n * \n * **Super Admin Access:** When `enforcePermissions={true}`, PaceAppLayout automatically\n * checks if the user is a super admin before enforcing permissions. Super admins bypass\n * all permission checks and can access any route without violations. The component extracts\n * base page names from route paths (e.g., `/organisation/scouts-victoria` → `\"organisation\"`)\n * for permission checking, which can be overridden using `pageIdMapping`.\n * \n * **Important:** The appName prop should use an APP_NAME constant declared in your App.tsx\n * file. This ensures consistency with public pages (via PublicPageProvider) which should\n * also receive the same APP_NAME constant. The logo URL is automatically constructed as\n * `/${appName.toLowerCase()}_logo_wide.svg` from the public folder.\n * \n * Features:\n * - React Router v6 integration with nested routing\n * - Unified authentication integration\n * - Consistent header with navigation and user menu\n * - Flexible main content area with Outlet\n * - Footer with application branding\n * - User sign-out and password change functionality\n * - Responsive design and accessibility compliant\n * - Layout-level permission enforcement\n * - Permission-based navigation filtering\n * - Automatic page permission validation\n * - Super admin bypass (super admins automatically bypass all permission checks)\n * \n * @example\n * Basic React Router setup with permission enforcement (RECOMMENDED):\n * ```tsx\n * import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';\n * import { UnifiedAuthProvider } from '@jmruthers/pace-core/providers';\n * import { PaceAppLayout, PaceLoginPage, PublicPageApp } from '@jmruthers/pace-core';\n * \n * const APP_NAME = 'CORE';\n * \n * function App() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName={APP_NAME}>\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={<PaceLoginPage appName={APP_NAME} />} />\n * <Route path=\"/events/*\" element={<PublicPageApp appName={APP_NAME} />} />\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName={APP_NAME}\n * enforcePermissions={true}\n * defaultPermission=\"read\"\n * />\n * }>\n * <Route index element={<HomePage />} />\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"meals\" element={<MealsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * ```\n * \n * \n * @example\n * Custom navigation items with permission filtering (works independently of route enforcement):\n * ```tsx\n * import { NavigationItem } from '@jmruthers/pace-core';\n * \n * function App() {\n * const customNavItems: NavigationItem[] = [\n * { id: 'components', label: 'Components', href: '/components', icon: 'Component' },\n * { id: 'styles', label: 'Styles', href: '/styles', icon: 'Palette' },\n * { id: 'meals', label: 'Meals', href: '/meals', icon: 'UtensilsCrossed' }\n * ];\n * \n * return (\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"My Custom App\" \n * navItems={customNavItems}\n * // Permission filtering is always enabled - no prop needed\n * routePermissions={{\n * '/components': 'read',\n * '/styles': 'read',\n * '/meals': 'read'\n * }}\n * // Optionally enable route-level enforcement (separate from navigation filtering)\n * // enforcePermissions={true}\n * />\n * }>\n * <Route path=\"components\" element={<ComponentsPage />} />\n * <Route path=\"styles\" element={<StylesPage />} />\n * <Route path=\"meals\" element={<MealsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * );\n * }\n * ```\n * \n * @example\n * Route-specific permissions with custom page IDs:\n * ```tsx\n * function AdminApp() {\n * return (\n * <Router>\n * <Routes>\n * <Route path=\"/\" element={\n * <PaceAppLayout \n * appName=\"Admin Panel\"\n * enforcePermissions={true}\n * routePermissions={{\n * '/dashboard': 'read',\n * '/user-management': 'read',\n * '/system-settings': 'update'\n * }}\n * pageIdMapping={{\n * '/dashboard': 'dashboard',\n * '/user-management': 'user-management',\n * '/system-settings': 'system-admin'\n * }}\n * permissionFallback={<AccessDeniedPage />}\n * />\n * }>\n * <Route path=\"dashboard\" element={<DashboardPage />} />\n * <Route path=\"user-management\" element={<UserManagementPage />} />\n * <Route path=\"system-settings\" element={<SystemSettingsPage />} />\n * </Route>\n * </Routes>\n * </Router>\n * );\n * }\n * ```\n * \n * @param props - Layout configuration including app name for branding and permission settings\n * @returns React element with complete application layout structure and permission enforcement\n * \n * @since 0.1.0\n */\nexport function PaceAppLayout({ \n appName, \n navItems, \n showContextSelector = true,\n showOrganisations = true,\n showEvents = true,\n headerActions,\n customLogo,\n logoHref = '/dashboard',\n customUserMenu,\n headerClassName,\n showUserMenu = true,\n enforcePermissions = false,\n defaultPermission = 'read',\n routePermissions = EMPTY_ROUTE_PERMISSIONS,\n permissionFallback,\n pageIdMapping = EMPTY_PAGE_ID_MAPPING,\n // NEW: Phase 1 - Enhanced Security Features\n strictMode = true,\n enforcePagePermissions = false,\n pagePermissionFallback,\n auditLog = true,\n onPageAccessDenied,\n onStrictModeViolation,\n // NEW: Phase 2 - Enhanced Routing Features\n roleBasedRouting = false,\n routeConfig = [],\n fallbackRoute = '/unauthorized',\n onRouteAccessDenied,\n onRouteStrictModeViolation\n}: PaceAppLayoutProps) {\n const { user, signOut, updatePassword, supabase, appId: contextAppId, selectedOrganisationId } = useUnifiedAuth(); // Get appId from context (resolved on login)\n const { \n selectedOrganisation, \n isContextReady, \n hasValidOrganisationContext,\n ensureOrganisationContext,\n isLoading: organisationLoading \n } = useOrganisations();\n // Use useRBAC to get super admin status - it's more reliable than async check\n // Note: isSuperAdmin might be false initially while loading, but that's OK - we'll allow rendering\n // if organisation loading completes or if we're a super admin\n const { isSuperAdmin: isSuperAdminFromRBAC, isLoading: rbacLoading } = useRBAC();\n\n // Also check super admin status directly as a fallback (for ADMIN/PORTAL apps)\n // This allows super admins to proceed even if RBAC hasn't loaded yet\n const [isSuperAdminDirect, setIsSuperAdminDirect] = useState<boolean>(false);\n const [isCheckingSuperAdminDirect, setIsCheckingSuperAdminDirect] = useState<boolean>(false);\n\n useEffect(() => {\n const checkSuperAdminDirect = async () => {\n if (!user?.id) {\n setIsSuperAdminDirect(false);\n setIsCheckingSuperAdminDirect(false);\n return;\n }\n\n // Only skip if RBAC already confirmed super admin\n if (isSuperAdminFromRBAC) {\n setIsCheckingSuperAdminDirect(false);\n return;\n }\n\n setIsCheckingSuperAdminDirect(true);\n try {\n const superAdminStatus = await checkSuperAdminApi(user.id);\n setIsSuperAdminDirect(superAdminStatus);\n } catch (error) {\n logger.error('PaceAppLayout', 'Error checking super admin status directly', { userId: user?.id, error });\n setIsSuperAdminDirect(false);\n } finally {\n setIsCheckingSuperAdminDirect(false);\n }\n };\n\n checkSuperAdminDirect();\n }, [user?.id, isSuperAdminFromRBAC]);\n\n // Use direct check if RBAC hasn't loaded yet, otherwise use RBAC result\n const isSuperAdmin = isSuperAdminFromRBAC || isSuperAdminDirect;\n const navigate = useNavigate();\n const location = useLocation();\n \n // Apply event theme colors automatically\n useEventTheme();\n \n // Get selected event (optional)\n let selectedEvent: { event_id: string } | null = null;\n try {\n const eventsContext = useEvents();\n selectedEvent = eventsContext.selectedEvent;\n } catch (error) {\n // Event provider not available - continue without event context\n }\n \n // Resolve scope for permission checking\n const { resolvedScope, isLoading: scopeLoading } = useResolvedScope({\n supabase: supabase || null,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n\n // Use appId from context (resolved immediately on login) or fallback to resolvedScope\n // This ensures appId is available immediately without waiting for additional resolution\n const resolvedAppId = contextAppId || resolvedScope?.appId;\n \n // Build scope from resolved values\n // Preserve appId from resolvedScope or fallback to resolvedAppId\n // CRITICAL: Always create a new scope object from primitive values to ensure stable reference\n // This prevents useCan from re-checking permissions when resolvedScope changes reference but values are the same\n const scopeOrgId = resolvedScope?.organisationId || selectedOrganisation?.id || '';\n const scopeEventId = resolvedScope?.eventId || selectedEvent?.event_id || undefined;\n const scopeAppId = resolvedScope?.appId || resolvedAppId || undefined;\n \n const scope = useMemo<Scope>(() => {\n const newScope: Scope = {};\n if (scopeOrgId) {\n newScope.organisationId = scopeOrgId;\n }\n if (scopeEventId) {\n newScope.eventId = scopeEventId;\n }\n if (scopeAppId) {\n newScope.appId = scopeAppId;\n }\n return newScope;\n }, [scopeOrgId, scopeEventId, scopeAppId]);\n\n // Default navigation items if none provided\n const defaultNavItems: NavigationItem[] = useMemo(() => [\n { id: 'home', label: 'Home', href: '/', icon: 'Home' },\n { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },\n { id: 'settings', label: 'Settings', href: '/settings', icon: 'Settings' },\n { id: 'ui-showcase', label: 'UI Showcase', href: '/ui-showcase', icon: 'Component' },\n { id: 'data-table-showcase', label: 'DataTable Showcase', href: '/data-table-showcase', icon: 'Table' },\n ], []);\n\n // Use provided navItems or fall back to default\n const baseMenuItems = useMemo(() => navItems || defaultNavItems, [navItems]);\n\n // Get current route permission requirements\n const currentRoutePermission = useMemo(() => {\n const currentPath = location.pathname;\n return routePermissions[currentPath] || defaultPermission;\n }, [location.pathname, routePermissions, defaultPermission]);\n\n // Get current page ID for permission checking\n // Extract base page name (first path segment) instead of full route path\n // Example: /organisation/scouts-victoria -> \"organisation\"\n const currentPageId = useMemo(() => {\n const currentPath = location.pathname;\n // Use pageIdMapping if provided (takes precedence)\n if (pageIdMapping[currentPath]) {\n return pageIdMapping[currentPath];\n }\n // Extract first path segment (base page name)\n const pathSegments = currentPath.slice(1).split('/').filter(Boolean);\n // Only return 'home' if there's actually a path segment, otherwise return empty string\n // This prevents checking permissions for a non-existent \"home\" page when the index route is used\n return pathSegments[0] || '';\n }, [location.pathname, pageIdMapping]);\n\n // Build permission string in format: operation:page.pageId\n const currentPermission = useMemo<Permission>(() => {\n // If enforcePermissions is false, don't check any permission (return empty string)\n // If currentPageId is empty (index route with no path segments), don't check permissions\n if (!enforcePermissions || !currentPageId) {\n return '' as Permission;\n }\n const permissionString = `${currentRoutePermission}:page.${currentPageId}`;\n return permissionString as Permission;\n }, [enforcePermissions, currentRoutePermission, currentPageId]);\n\n // Check super admin status before permission enforcement\n // Removed duplicate super admin check - using useRBAC hook instead\n // The useRBAC hook provides isSuperAdmin which is more reliable\n\n // Use useCan hook for permission checking (standardized approach)\n // Note: The database function already handles super admin bypass, but we check here\n // as an additional safety layer to prevent unnecessary permission checks\n // Pass appName to useCan so it can be passed to isPermitted for PORTAL/ADMIN special case\n // Only check permissions if enforcePermissions is true and we have a valid permission string\n const shouldCheckPermission = enforcePermissions && !!currentPermission && !!currentPageId;\n // Pass super admin status to avoid duplicate check - use null if still checking, false/true if known\n const superAdminStatus = isSuperAdminFromRBAC ? true : (isCheckingSuperAdminDirect ? null : isSuperAdminDirect);\n const { can: canFromHook, isLoading: isCheckingPermission, error: permissionError } = useCan(\n user?.id || '',\n scope,\n shouldCheckPermission ? currentPermission : ('' as Permission),\n shouldCheckPermission ? currentPageId : '',\n true, // useCache\n superAdminStatus, // Pass super admin status to avoid duplicate check\n appName // Pass appName for PORTAL/ADMIN special case\n );\n\n // Permission enforcement state - super admin bypasses all checks\n // This ensures super admins never see permission errors even if useCan hasn't completed\n // Use combined super admin check (RBAC + direct check)\n const can = isSuperAdmin ? true : canFromHook;\n const hasPermission = enforcePermissions ? can : true;\n \n // Check if the permission error is a context error (missing event/org context)\n // Context errors should allow the page to render so it can show helpful messaging\n // Real permission denials should still show \"Access Denied\"\n const isContextError = useMemo(() => {\n if (!permissionError) {\n return false;\n }\n return (\n permissionError instanceof EventContextRequiredError ||\n permissionError instanceof OrganisationContextRequiredError ||\n permissionError.name === 'EventContextRequiredError' ||\n permissionError.name === 'OrganisationContextRequiredError'\n );\n }, [permissionError]);\n\n // Handle permission check results with audit logging and callbacks\n useEffect(() => {\n if (!enforcePermissions) {\n return;\n }\n\n // Only proceed when permission check is complete (not loading)\n // Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)\n // If RBAC is still loading, allow rendering to proceed (optimistic for super admins)\n if (isCheckingPermission) {\n return;\n }\n\n // NEW: Phase 1 - Enhanced Security Features\n // Handle strict mode violations - skip for super admins\n if (strictMode && !isSuperAdmin && !can) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected page without permission', {\n pageName: currentPageId,\n operation: currentRoutePermission,\n userId: user?.id,\n isSuperAdmin: isSuperAdmin,\n timestamp: new Date().toISOString()\n });\n \n if (onStrictModeViolation) {\n onStrictModeViolation(currentPageId, currentRoutePermission);\n }\n }\n \n // Handle page access denied callback - skip for super admins\n if (!isSuperAdmin && !can && onPageAccessDenied) {\n onPageAccessDenied(currentPageId, currentRoutePermission);\n }\n }, [enforcePermissions, can, isCheckingPermission, isSuperAdmin, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);\n\n // Filter navigation items based on permissions\n // Permission filtering is always enabled - users only see navigation items they have permission to access\n const [filteredMenuItems, setFilteredMenuItems] = useState<NavigationItem[]>(baseMenuItems);\n\n useEffect(() => {\n let isMounted = true;\n\n const filterItems = async () => {\n // Wait for organisation context to be ready before filtering\n // This prevents blocking navigation while context is loading\n if (!user?.id) {\n // User not loaded yet - show all items until context is ready\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // Use the scope from context (includes selectedOrganisation and selectedEvent)\n // This is critical for event-based apps where event context comes from EventService, not user metadata\n const currentScope = scope;\n \n // Wait for scope to be fully resolved (including appId) before filtering\n // This is important because getPermissionMap requires appId to fetch pages\n // Check both resolvedScope.appId and resolvedAppId (fallback)\n // appId is now resolved immediately on login in UnifiedAuthProvider, so it should be available\n const hasAppId = currentScope.appId || resolvedAppId;\n \n // OPTIMIZATION: Show items optimistically while permissions load\n // This makes the menu appear immediately, then we filter when permissions are ready\n const hasOrganisationContext = currentScope.organisationId;\n const hasUser = !!user?.id;\n \n // Show navigation optimistically while waiting for context selection.\n // Only hide navigation if user is not loaded.\n // This prevents navigation from disappearing after initial render while waiting for context.\n if (!hasUser) {\n // User not loaded yet - show all items until user is ready\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // If no organisation context yet, show items optimistically\n // This allows users to see navigation while they select a context\n // Only proceed with permission filtering once context is selected\n if (!hasOrganisationContext) {\n if (isMounted) {\n // Show items optimistically when org selector is enabled, otherwise show all items\n // This prevents navigation from disappearing while waiting for organisation selection\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n\n // For super admins, show all items (they bypass permission checks)\n // Gracefully handle RBAC not being initialized (e.g., in tests)\n try {\n const { isSuperAdmin: checkSuperAdminDynamic } = await import('../../rbac/api');\n const isSuper = await checkSuperAdminDynamic(user.id);\n \n if (isSuper) {\n // Super admins see all navigation items\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\n }\n } catch (error) {\n // If RBAC is not initialized (e.g., in tests), continue with normal filtering\n // This prevents errors from breaking navigation when RBAC isn't available\n if (error && typeof error === 'object' && 'code' in error && error.code === 'RBAC_NOT_INITIALIZED') {\n // RBAC not available - proceed with normal filtering without super admin check\n // In this case, we'll filter items normally based on permissions\n } else {\n // Re-throw unexpected errors\n throw error;\n }\n }\n\n // Organisation context is ready - now filter items based on permissions\n // OPTIMIZATION: Use batch permission map instead of individual checks to avoid rate limits\n // This makes 1 call instead of N calls (where N = number of navigation items)\n // OPTIMIZATION: Proceed even if appId is still resolving - permission checks work with organisationId\n try {\n const { getPermissionMap } = await import('../../rbac/api');\n \n // Build scope for permission check - use appId if available, but don't wait for it\n // Permission checks will work with resource permissions even without appId\n const permissionScope: Scope = {\n organisationId: currentScope.organisationId,\n eventId: currentScope.eventId,\n appId: currentScope.appId || resolvedAppId || undefined // Use appId if available, but proceed without it\n };\n \n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope: permissionScope,\n });\n\n // Filter items using the permission map and scope type\n // First, get scope types for all pages (batch if possible, or individual)\n const { getPageScopeType } = await import('../../rbac/api');\n const effectiveAppId = currentScope.appId || resolvedAppId;\n const effectiveAppName = appName;\n \n // Determine current context type for scope filtering\n const hasEventContext = !!currentScope.eventId;\n const hasOrgContext = !!currentScope.organisationId;\n \n // Filter items using both permission map and scope type\n const filtered = await Promise.all(\n baseMenuItems.map(async (item) => {\n if (!item.href) return { item, hasAccess: true, matchesScope: true, scopeCheckError: false };\n \n // Extract page ID from href: remove leading slash, fallback to 'dashboard' for root\n // This matches database page names in rbac_app_pages\n const pageId = pageIdMapping[item.href] || (item.href === '/' ? 'dashboard' : item.href.slice(1)) || 'dashboard';\n const permission = routePermissions[item.href] || defaultPermission;\n const fullPermission: Permission = permission.includes(':')\n ? (permission as Permission)\n : (pageId ? `${permission}:page.${pageId}` : permission) as Permission;\n \n // Check permission map (super admin check already handled in getPermissionMap)\n const hasAccess = permissionMap['*'] === true || permissionMap[fullPermission] === true;\n \n // Check scope type compatibility\n let matchesScope = true;\n let scopeCheckError = false;\n if (effectiveAppId || effectiveAppName) {\n try {\n const pageScopeType = await getPageScopeType(\n pageId,\n effectiveAppId,\n effectiveAppName\n );\n \n // Filter based on current context:\n // - If event is selected: show only 'event' or 'both' pages\n // - If only org is selected: show only 'organisation' or 'both' pages\n if (hasEventContext) {\n // Event context: show 'event' or 'both' pages only\n matchesScope = pageScopeType === 'event' || pageScopeType === 'both';\n } else if (hasOrgContext) {\n // Organisation context only: show 'organisation' or 'both' pages only\n matchesScope = pageScopeType === 'organisation' || pageScopeType === 'both';\n } else {\n // No context: show all pages (shouldn't happen, but safe fallback)\n matchesScope = true;\n }\n } catch (error) {\n // If we can't get scope type, allow the page (graceful degradation)\n // This prevents navigation from disappearing if there's a database issue\n scopeCheckError = true;\n logger.warn('PaceAppLayout', 'Failed to get page scope type for navigation filtering', {\n pageId,\n href: item.href,\n contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),\n error: error instanceof Error ? error.message : String(error),\n note: 'Allowing page to prevent navigation from disappearing - this may indicate missing scope_type in database'\n });\n matchesScope = true; // Default to allowing if we can't check\n }\n } else {\n // No appId/appName available - can't check scope, allow the page\n // This happens during initial load before app context is resolved\n matchesScope = true;\n }\n \n return { item, hasAccess, matchesScope, scopeCheckError };\n })\n );\n\n if (!isMounted) return;\n\n const accessibleItems = filtered\n .filter(({ hasAccess, matchesScope }) => hasAccess && matchesScope)\n .map(({ item }) => item);\n\n // If all items were filtered out, check if it's due to scope filtering\n // This can happen if:\n // 1. All pages are scoped for the other context type (expected behavior)\n // 2. Scope type lookup failed for all pages (should fallback to showing items with permissions)\n if (accessibleItems.length === 0 && filtered.length > 0) {\n const itemsWithPermissions = filtered.filter(({ hasAccess }) => hasAccess);\n const itemsFilteredByScope = filtered.filter(({ hasAccess, matchesScope }) => hasAccess && !matchesScope);\n const itemsWithScopeErrors = filtered.filter(({ hasAccess, scopeCheckError }) => hasAccess && scopeCheckError);\n \n // If scope checking failed for ALL items with permissions, fall back to showing them\n // This prevents navigation from disappearing due to database/API issues\n if (itemsWithPermissions.length > 0 && \n itemsWithScopeErrors.length === itemsWithPermissions.length) {\n logger.warn('PaceAppLayout', 'Scope checking failed for all items - falling back to permission-only filtering', {\n contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),\n totalItems: baseMenuItems.length,\n itemsWithPermissions: itemsWithPermissions.length,\n scopeCheckErrorCount: itemsWithScopeErrors.length,\n note: 'Showing items based on permissions only - scope filtering disabled due to errors. This may indicate database issues or missing scope_type values.'\n });\n \n // Fall back to showing items that have permissions (ignore scope check)\n const fallbackItems = filtered\n .filter(({ hasAccess }) => hasAccess)\n .map(({ item }) => item);\n \n if (isMounted && fallbackItems.length > 0) {\n setFilteredMenuItems(fallbackItems);\n return;\n }\n } else if (itemsWithPermissions.length > 0 && itemsFilteredByScope.length === itemsWithPermissions.length) {\n // All items were filtered by scope (not errors) - this is expected if all pages are scoped for other context\n logger.info('PaceAppLayout', 'All navigation items filtered out by scope type', {\n contextType: hasEventContext ? 'event' : (hasOrgContext ? 'organisation' : 'none'),\n totalItems: baseMenuItems.length,\n itemsWithPermissions: itemsWithPermissions.length,\n itemsFilteredByScope: itemsFilteredByScope.length,\n note: 'All pages appear to be scoped for a different context type - this is expected behavior. Navigation will be empty until user selects the appropriate context.'\n });\n }\n }\n\n // SECURITY: Never show all items if permission check fails - this would be a security risk\n // If all items are filtered out, it means the user doesn't have permission to see any navigation\n // OR all pages are scoped for a different context type\n // This is the correct behavior - better to show nothing than show unauthorized items\n setFilteredMenuItems(accessibleItems);\n } catch (error) {\n // On error, fall back to showing all items (graceful degradation)\n // This prevents navigation from being empty if permission checks fail\n logger.error('PaceAppLayout', 'Failed to load permission map for navigation filtering', { userId: user?.id, error });\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n }\n };\n\n filterItems();\n\n return () => {\n isMounted = false;\n };\n }, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, selectedOrganisation?.id, selectedEvent?.event_id, appName]);\n\n // NEW: Phase 2 - Enhanced Routing Features\n // Check route access for role-based routing\n useEffect(() => {\n if (!roleBasedRouting || routeConfig.length === 0) return;\n \n let isMounted = true;\n \n const checkRouteAccess = async () => {\n const currentPath = location.pathname;\n const currentRoute = routeConfig.find(route => route.path === currentPath);\n \n if (!currentRoute) {\n // Route not found in configuration\n if (strictMode) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: Route not found in configuration', {\n route: currentPath,\n userId: user?.id,\n timestamp: new Date().toISOString()\n });\n \n if (onRouteStrictModeViolation) {\n onRouteStrictModeViolation(currentPath, 'Route not found in configuration');\n }\n }\n return;\n }\n \n // Check permissions using useCan hook result\n let hasAccess = true; // Default to true if no permission requirements\n \n // Check page permissions\n if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {\n // Use the permission check result from useCan hook\n // For now, we'll use a simple check - in future we might need useMultiplePermissions here\n try {\n const { isPermittedCached } = await import('../../rbac/api');\n const hasPagePermission = await isPermittedCached({\n userId: user?.id || '',\n scope,\n permission: currentRoute.permissions[0] as Permission,\n pageId: currentRoute.pageId,\n });\n if (!isMounted) return;\n hasAccess = hasPagePermission;\n } catch (error) {\n logger.error('PaceAppLayout', 'Failed to check page permission', { route: currentPath, pageId: currentRoute.pageId, error });\n if (!isMounted) return;\n hasAccess = false;\n }\n }\n \n // If permission check passed or not required, check roles\n if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {\n const { useUnifiedAuth } = await import('../../providers/services/UnifiedAuthProvider');\n // Note: We're already in the component with authContext via useUnifiedAuth at top\n // For this feature to work properly, we need the auth context\n // This is a limitation of the current implementation\n hasAccess = true; // Will be properly implemented when auth context is available in this effect\n }\n \n if (!isMounted) return;\n \n if (!hasAccess) {\n // Handle route access denied\n if (onRouteAccessDenied) {\n onRouteAccessDenied(currentPath, 'Insufficient permissions');\n }\n \n if (strictMode) {\n logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected route without permission', {\n route: currentPath,\n userId: user?.id,\n permissions: currentRoute.permissions,\n roles: currentRoute.roles,\n accessLevel: currentRoute.accessLevel,\n timestamp: new Date().toISOString()\n });\n \n if (onRouteStrictModeViolation) {\n onRouteStrictModeViolation(currentPath, 'Insufficient permissions');\n }\n }\n \n // Redirect to fallback route\n navigate(fallbackRoute, { replace: true });\n return;\n }\n };\n \n checkRouteAccess();\n \n return () => {\n isMounted = false;\n };\n }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);\n\n const handleSignOut = async () => {\n try {\n await signOut();\n } catch (error) {\n logger.error('PaceAppLayout', 'Failed to sign out', { error: error instanceof Error ? error.message : String(error) });\n }\n };\n\n const handleChangePassword = async (newPassword: string, confirmPassword: string) => {\n try {\n // The form component in UserMenu already checks for matching passwords\n const result = await updatePassword(newPassword);\n if (result?.error) {\n // The form will display the error message\n logger.error('PaceAppLayout', 'Failed to change password', { error: result.error.message });\n // Convert AuthError to PasswordChangeFormError\n return {\n error: {\n message: result.error.message,\n code: result.error.name || 'PASSWORD_UPDATE_ERROR'\n }\n };\n }\n // The form will handle closing the modal on success\n return {};\n } catch (error) {\n logger.error('PaceAppLayout', 'Failed to change password', { error: error instanceof Error ? error.message : String(error) });\n return {\n error: {\n message: error instanceof Error ? error.message : 'An unexpected error occurred',\n code: 'PASSWORD_UPDATE_ERROR'\n }\n };\n }\n };\n\n // CRITICAL: Wait for organisation context to be ready before proceeding\n // The OrganisationService automatically selects an organisation when loading\n // We just need to wait for isContextReady to be true\n // No need to call ensureOrganisationContext() here - it will throw if no org is selected\n // and the service handles selection automatically during loadUserOrganisations()\n\n // Show loading state while organisation context is being set\n // This is critical - we must wait for organisation context before allowing any data access\n // BUT: Allow rendering to proceed if loading is complete, even if user has no organisations (valid state for profile pages)\n // Only block if we're actively loading - once loading completes (success or error), allow rendering\n // EXCEPTION: Super admins can proceed even during organisation loading (they can access all orgs)\n // Use combined super admin check (RBAC + direct check) to allow super admins to proceed immediately\n // IMPORTANT: If we're still checking super admin status, allow rendering to proceed (optimistic approach)\n // This prevents blocking super admins while their status is being determined\n // Also allow rendering if we already have a selectedOrganisationId (even if organisationLoading is still true)\n // This prevents blank pages when organisation context is available but loading state hasn't cleared yet\n if (user?.id && organisationLoading && !isSuperAdmin && !isCheckingSuperAdminDirect && !rbacLoading && !selectedOrganisationId) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4\"></div>\n <p className=\"text-sec-600\">Loading organisation context...</p>\n </div>\n </div>\n );\n }\n \n // Once loading is complete (whether success or error), allow rendering to proceed\n // For users without organisations, allow access to profile pages (dashboard, member-profile, medical-profile, additional-contacts)\n // These pages work with user context only and don't require organisation context\n // The app can check hasValidOrganisationContext() to determine if org context is available for org-specific features\n\n // Show loading state while checking permissions\n // Keep loading active until permission check completes to prevent exposing protected content\n // Super admin status is checked via useRBAC hook (isSuperAdminFromRBAC)\n if (enforcePermissions && isCheckingPermission) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4\"></div>\n <p className=\"text-sec-600\">Checking permissions...</p>\n </div>\n </div>\n );\n }\n\n // Show permission error (only after check is complete)\n // Super admins bypass all permission checks, so don't show errors for them\n // Context errors (missing event/org) should allow the page to render so it can show helpful messaging\n // Real permission errors should still show \"Access Denied\"\n if (enforcePermissions && permissionError && !isSuperAdmin && !isContextError) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <h2 className=\"text-xl font-semibold text-acc-600 mb-2\">Permission Error</h2>\n <p className=\"text-sec-600 mb-4\">{permissionError.message}</p>\n <Button onClick={() => navigate('/')}>Go Home</Button>\n </div>\n </div>\n );\n }\n\n // Show permission fallback if user lacks permission\n // Only show this if super admin check is complete and user is not a super admin\n // Skip if it's a context error (missing event/org) - allow page to render and show helpful messaging\n if (enforcePermissions && hasPermission === false && !isCheckingSuperAdminDirect && !isSuperAdmin && !isContextError) {\n // NEW: Phase 1 - Use page permission fallback if available\n if (enforcePagePermissions && pagePermissionFallback) {\n return <>{pagePermissionFallback}</>;\n }\n \n if (permissionFallback) {\n return <>{permissionFallback}</>;\n }\n \n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <h2 className=\"text-xl font-semibold text-acc-600 mb-2\">Access Denied</h2>\n <p className=\"text-sec-600 mb-4\">\n You don't have permission to access this page.\n </p>\n <div className=\"flex gap-2 justify-center\">\n <Button onClick={() => navigate('/')}>Go Home</Button>\n <Button \n variant=\"outline\" \n onClick={async () => {\n await handleSignOut();\n navigate('/login');\n }}\n >\n Sign out\n </Button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <>\n <Header\n logo={customLogo || undefined}\n logoUrl={!customLogo ? `/${appName.toLowerCase()}_logo_wide.svg` : undefined}\n logoAlt={`${appName} Logo`}\n logoHref={logoHref}\n navItems={filteredMenuItems}\n actions={headerActions}\n userMenu={customUserMenu}\n user={user}\n onSignOut={handleSignOut}\n onChangePassword={handleChangePassword}\n currentPath={window.location.pathname}\n onNavigate={(item) => {\n if (item.href) {\n navigate(item.href);\n }\n }}\n showContextSelector={showContextSelector}\n showOrganisations={showOrganisations}\n showEvents={showEvents}\n showUserMenu={showUserMenu}\n className={headerClassName || \"sticky top-0 z-[40] w-full\"}\n />\n <main className=\"px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n <Outlet />\n </main>\n <Footer />\n </>\n );\n} ","/**\n * @file PACE Login Page Component\n * @package @jmruthers/pace-core\n * @module Components/PaceLoginPage\n * @since 0.1.0\n *\n * A comprehensive login page component that provides a consistent authentication\n * experience for all PACE suite applications with role-based redirection and\n * enhanced error handling.\n *\n * Features:\n * - Consistent login page layout\n * - Unified authentication integration\n * - Role-based automatic redirection (admin users)\n * - Manual redirection for all successful logins\n * - Customizable app branding\n * - Configurable redirect paths\n * - Enhanced error handling and display\n * - Dual loading state management (auth + form)\n * - Navigation error recovery\n * - Responsive design\n * - Accessibility compliant\n * - Integration with LoginForm\n * - React Router navigation\n * - Centered layout design\n * - Error persistence and display\n *\n * @example\n * ```tsx\n * // Basic login page\n * <PaceLoginPage appName=\"My Application\" />\n * \n * // Login page with custom redirect\n * <PaceLoginPage\n * appName=\"Dashboard App\"\n * onSuccessRedirectPath=\"/dashboard\"\n * />\n * \n * // Login page in router setup\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage \n * appName=\"My App\"\n * onSuccessRedirectPath=\"/home\"\n * />\n * } />\n * <Route path=\"/home\" element={<HomePage />} />\n * </Routes>\n * </Router>\n * \n * // Login page with authentication provider\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"My App\">\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage appName=\"My Application\" />\n * } />\n * <Route path=\"/\" element={<PaceAppLayout appName=\"My Application\" />}>\n * <Route index element={<HomePage />} />\n * </Route>\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * \n * // Login page with role-based access control\n * function App() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"Admin Portal\">\n * <Router>\n * <Routes>\n * <Route path=\"/login\" element={\n * <PaceLoginPage \n * appName=\"Admin Portal\"\n * onSuccessRedirectPath=\"/admin/dashboard\"\n * />\n * } />\n * <Route path=\"/admin/*\" element={<AdminRoutes />} />\n * </Routes>\n * </Router>\n * </UnifiedAuthProvider>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - Keyboard navigation support\n * - Focus management\n * - High contrast support\n * - Clear page hierarchy\n * - Accessible form elements\n * - Error announcements\n *\n * @routing\n * - React Router v6 integration\n * - Automatic navigation on success\n * - Role-based redirect logic (admin users)\n * - Configurable redirect paths\n * - Replace navigation for login flow\n * - Navigation error handling\n *\n * @authentication\n * - Integration with UnifiedAuthProvider\n * - Role detection via hasRole('admin')\n * - Loading state management\n * - Error state handling\n * - Session validation\n * - Automatic redirect prevention loops\n *\n * @dependencies\n * - React 19+ - Hooks and effects\n * - React Router v6 - Navigation\n * - UnifiedAuthProvider - Authentication\n * - LoginForm component\n * - Button component\n * - Input component\n * - Label component\n * - Tailwind CSS - Styling\n */\n\nimport React, { useEffect, useState, useContext } from 'react';\nimport { useNavigate, useLocation } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers';\nimport { isSuperAdmin } from '../../rbac/api';\nimport { LoginForm } from '../LoginForm';\nimport { Button, Input, Label } from '..';\nimport { clearPalette } from '../../theming/runtime';\nimport { EventServiceContext } from '../../providers/services/EventServiceProvider';\nimport { logger } from '../../utils/core/logger';\n\n/**\n * Props for the PaceLoginPage component.\n */\nexport interface PaceLoginPageProps {\n /** The name of the application to be displayed on the login form. */\n appName: string;\n /** The path to redirect to upon successful login. Defaults to `/`. */\n onSuccessRedirectPath?: string;\n /** Whether to check app access using RBAC. Defaults to false. */\n requireAppAccess?: boolean;\n}\n\n/**\n * A consistent, reusable login page for all PACE suite applications.\n * It handles the sign-in logic with role-based automatic redirection for admin users,\n * enhanced error handling, and dual loading state management.\n * \n * Recent enhancements:\n * - Role-based redirection: Admin users are automatically redirected\n * - RBAC-based app access control: Checks if user has permission to access the app\n * - Enhanced error handling with navigation error recovery\n * - Dual loading states: auth loading + form submission loading\n * - Error persistence: Auth errors are displayed below the form\n * - Navigation safety: Try-catch blocks prevent navigation errors\n * \n * @param props - Login page configuration including app name and redirect path\n * @returns JSX.Element - The rendered login page with enhanced functionality\n * \n * @example\n * ```tsx\n * <PaceLoginPage \n * appName=\"My Application\" \n * onSuccessRedirectPath=\"/dashboard\" \n * />\n * ```\n */\nexport const PaceLoginPage: React.FC<PaceLoginPageProps> = ({\n appName = 'Pace',\n onSuccessRedirectPath = '/',\n requireAppAccess = false\n}) => {\n const { signIn, isAuthenticated, isLoading, authError, user, supabase } = useUnifiedAuth();\n \n const navigate = useNavigate();\n const location = useLocation();\n const [isSigningIn, setIsSigningIn] = useState(false);\n const [accessError, setAccessError] = useState<string | null>(null);\n const [isCheckingAccess, setIsCheckingAccess] = useState(false);\n\n // Get event service context (may not be available if outside EventServiceProvider)\n // Using useContext directly allows graceful handling when provider is not available\n const eventServiceContext = useContext(EventServiceContext);\n const eventService = eventServiceContext?.eventService || null;\n\n // Clear any active event theme when login page mounts\n // This ensures the login screen always uses default colors\n useEffect(() => {\n clearPalette();\n }, []);\n\n // Clear theme whenever on login route (including after navigation back to login)\n // This ensures event theme doesn't apply if events are restored while still on login\n useEffect(() => {\n const isOnLoginPage = location.pathname === '/login' || location.pathname.startsWith('/login');\n if (isOnLoginPage) {\n clearPalette();\n }\n }, [location.pathname]);\n\n // Restore persisted event after login screen has rendered\n // This happens after the login page is fully rendered, allowing events to be loaded first\n useEffect(() => {\n const restoreEvent = async () => {\n try {\n const isOnLoginPage = window.location.pathname === '/login' || window.location.pathname.startsWith('/login');\n if (isOnLoginPage && eventService) {\n await eventService.restorePersistedEvent();\n }\n } catch (error) {\n // Service may not be available yet or events not loaded - that's okay\n }\n };\n \n // Small delay to ensure login page is fully rendered before restoring\n const timeoutId = setTimeout(() => {\n restoreEvent();\n }, 100);\n \n return () => clearTimeout(timeoutId);\n }, [eventService]);\n\n // Check app access after authentication using RBAC\n useEffect(() => {\n if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {\n return;\n }\n\n const checkAccess = async () => {\n setIsCheckingAccess(true);\n setAccessError(null);\n\n try {\n const userId = user.id;\n logger.debug('PaceLoginPage', 'Checking app access using RBAC:', { appName, userId });\n\n // Step 1: Check if user is super admin (they have unrestricted access)\n const superAdminCheck = await isSuperAdmin(userId);\n \n if (superAdminCheck) {\n logger.debug('PaceLoginPage', 'User is super admin, granting access');\n setIsCheckingAccess(false);\n navigate(onSuccessRedirectPath, { replace: true });\n return;\n }\n\n // Step 2: Get the app ID\n const { data: appData, error: appError } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single();\n\n if (appError || !appData) {\n logger.error('PaceLoginPage', 'App not found:', { appName, error: appError });\n setAccessError(`Application \"${appName}\" is not configured. Please contact your administrator.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 3: Get all pages for this app\n const { data: pagesData, error: pagesError } = await supabase\n .from('rbac_app_pages')\n .select('id, page_name')\n .eq('app_id', appData.id);\n\n if (pagesError || !pagesData || pagesData.length === 0) {\n setAccessError(`You do not have permission to access ${appName}. This application is currently unavailable. Please contact your administrator if you believe you should have access.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 4: Get user's first organisation\n const { data: orgRow } = await supabase\n .from('rbac_organisation_roles')\n .select('organisation_id')\n .eq('user_id', userId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .limit(1)\n .maybeSingle();\n\n const organisationId = orgRow?.organisation_id;\n\n if (!organisationId) {\n setAccessError(`You do not have permission to access ${appName}. You are not assigned to any organisation. Please contact your administrator.`);\n setIsCheckingAccess(false);\n return;\n }\n\n // Step 5: Check if user has ANY read permission on ANY page in this app\n // We check each page and see if user has the 'read' operation allowed\n let hasAnyAccess = false;\n for (const page of pagesData) {\n const { data: hasPermission, error: permError } = await supabase\n .rpc('rbac_check_permission_simplified', {\n p_user_id: userId,\n p_permission: `read:page.${page.page_name}`, // Permission format: operation:resource\n p_organisation_id: organisationId,\n p_event_id: null,\n p_app_id: appData.id,\n p_page_id: page.page_name // Page name to resolve to UUID\n });\n\n if (!permError && hasPermission === true) {\n hasAnyAccess = true;\n break;\n }\n }\n\n if (hasAnyAccess) {\n setIsCheckingAccess(false);\n navigate(onSuccessRedirectPath, { replace: true });\n return;\n }\n\n // No access - deny\n setAccessError(`You do not have permission to access ${appName}. This application is restricted to authorized users only. Please contact your administrator if you believe you should have access.`);\n setIsCheckingAccess(false);\n } catch (error) {\n logger.error('PaceLoginPage', 'Error checking app access:', error);\n setAccessError('An error occurred while checking your permissions. Please try again or contact support.');\n setIsCheckingAccess(false);\n }\n };\n\n checkAccess();\n }, [isAuthenticated, isLoading, user, supabase, appName, requireAppAccess, navigate, onSuccessRedirectPath]);\n\n const handleSubmit = async (data: { email: string; password: string }) => {\n setIsSigningIn(true);\n setAccessError(null); // Clear previous access errors\n \n try {\n const { error } = await signIn(data.email, data.password);\n\n if (error) {\n // Throw error so LoginForm can catch and display it\n throw error;\n }\n\n // Navigation will be handled by the useEffect that checks app access\n // Don't navigate here if requireAppAccess is true\n if (!requireAppAccess) {\n try {\n navigate(onSuccessRedirectPath, { replace: true });\n } catch (navError) {\n logger.error('PaceLoginPage', 'Navigation error after sign-in:', navError);\n }\n }\n } finally {\n setIsSigningIn(false);\n }\n };\n\n return (\n <main className=\"min-h-screen grid mx-auto w-fit content-center justify-items-center gap-y-8\" aria-label={`${appName} Login Page`}>\n <img\n src={`/${appName.toLowerCase()}_logo_square.svg`}\n alt={`${appName} logo`}\n className=\"h-48\"\n />\n\n <LoginForm className=\"w-md\"\n onSignIn={handleSubmit}\n appName={appName}\n isLoading={isSigningIn}\n onError={(error) => {\n // LoginForm will handle display of the error\n logger.error('PaceLoginPage', 'Login error:', error);\n }}\n />\n {(() => {\n const benign = !!(authError && (\n authError.name === 'AuthSessionMissingError' || /Auth session missing/i.test(authError.message)\n ));\n return authError && !benign ? (\n <em className=\"mt-4 text-destructive text-center\">{authError.message}</em>\n ) : null;\n })()}\n {accessError && (\n <em className=\"mt-4 text-destructive text-center\">\n {accessError}\n </em>\n )}\n {isCheckingAccess && (\n <em className=\"mt-4 text-muted-foreground text-center\">\n Checking permissions...\n </em>\n )}\n </main>\n );\n} ","/**\n * @file SessionRestorationLoader Component\n * @package @jmruthers/pace-core\n * @module Components/SessionRestorationLoader\n * @since 0.1.0\n *\n * Displays a consistent loading state while the authentication service\n * restores the Supabase session from persistent storage.\n *\n * Features:\n * - Full-screen loading state\n * - Accessible with proper ARIA attributes\n * - Screen reader friendly\n * - Customizable message\n * - Uses LoadingSpinner component\n *\n * @example\n * ```tsx\n * // Basic usage\n * <SessionRestorationLoader />\n *\n * // With custom message\n * <SessionRestorationLoader message=\"Restoring your session...\" />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA role=\"status\"\n * - Screen reader announcement\n * - High contrast support\n *\n * @dependencies\n * - React 19+ - Component framework\n * - LoadingSpinner - Spinner component\n * - Tailwind CSS - Styling\n */\n\nimport React from 'react';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { Alert } from '../Alert';\nimport { cn } from '../../utils/core/cn';\n\nexport interface SessionRestorationLoaderProps {\n /** Customise the status message displayed under the spinner */\n message?: string;\n /** Additional CSS classes for styling */\n className?: string;\n}\n\nexport const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> = ({\n message = 'Restoring session...',\n className\n}) => {\n return (\n <Alert\n className={cn(\n 'flex flex-col items-center justify-center h-screen w-full gap-4 text-center p-4 bg-background',\n className\n )}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={message}\n >\n <LoadingSpinner size=\"lg\" />\n <span className=\"text-sm text-sec-600\">{message}</span>\n </Alert>\n );\n};\n\n","/**\n * @file Protected Route Component\n * @package @jmruthers/pace-core\n * @module Components/ProtectedRoute\n * @since 0.6.0\n *\n * A route protection component that handles authentication and optional event selection\n * without creating a chicken-and-egg problem where users cannot see the event selector.\n *\n * Features:\n * - Authentication checking with redirect to login\n * - Session restoration handling\n * - Event loading state management\n * - Smart event selection logic (allows rendering when events exist but none selected)\n * - Optional event requirement (can be disabled for apps that don't need events)\n * - Super admin bypass support\n * - Clear error states for no events available\n *\n * @example\n * Basic protected route:\n * ```tsx\n * import { ProtectedRoute } from '@jmruthers/pace-core';\n * import { Routes, Route } from 'react-router-dom';\n *\n * function App() {\n * return (\n * <Routes>\n * <Route path=\"/login\" element={<LoginPage />} />\n * <Route element={<ProtectedRoute />}>\n * <Route path=\"/dashboard\" element={<DashboardPage />} />\n * </Route>\n * </Routes>\n * );\n * }\n * ```\n *\n * @example\n * Protected route without event requirement:\n * ```tsx\n * <Route element={<ProtectedRoute requireEvent={false} />}>\n * <Route path=\"/settings\" element={<SettingsPage />} />\n * </Route>\n * ```\n *\n * @example\n * Protected route with custom no events message:\n * ```tsx\n * <Route element={\n * <ProtectedRoute\n * requireEvent={true}\n * noEventsFallback={<CustomNoEventsMessage />}\n * />\n * }>\n * <Route path=\"/dashboard\" element={<DashboardPage />} />\n * </Route>\n * ```\n *\n * @accessibility\n * - Proper loading states with screen reader support\n * - Clear error messages\n * - Keyboard navigation support\n *\n * @dependencies\n * - React Router v6 - Routing functionality\n * - useUnifiedAuth - Authentication context\n * - useEvents - Event context\n * - SessionRestorationLoader - Session restoration UI\n * - LoadingSpinner - Loading state UI\n */\n\nimport React, { useMemo, useEffect, useRef, useState } from 'react';\nimport { Navigate, Outlet } from 'react-router-dom';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useSessionRestoration } from '../../hooks/useSessionRestoration';\nimport { useEvents } from '../../hooks/useEvents';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { SessionRestorationLoader } from '../SessionRestorationLoader';\nimport { Alert, AlertDescription, AlertTitle } from '../Alert/Alert';\nimport { logger } from '../../utils/core/logger';\nimport { usePreventTabReload } from '../../hooks/usePreventTabReload';\n\n/**\n * Props for the ProtectedRoute component.\n */\nexport interface ProtectedRouteProps {\n /**\n * Whether an event is required for routes inside this component.\n * When true, routes will only render if an event is selected or can be selected.\n * When false, routes render regardless of event state.\n * @default true\n */\n requireEvent?: boolean;\n\n /**\n * Custom component to render when no events are available.\n * If not provided, a default message is shown.\n */\n noEventsFallback?: React.ReactNode;\n\n /**\n * Custom component to render while events are loading.\n * If not provided, a default loading spinner is shown.\n */\n loadingFallback?: React.ReactNode;\n\n /**\n * Login redirect path when user is not authenticated.\n * @default '/login'\n */\n loginPath?: string;\n}\n\n/**\n * ProtectedRoute component that handles authentication and optional event selection.\n *\n * This component solves the chicken-and-egg problem where apps check for `selectedEvent`\n * before rendering, which blocks the event selector (typically in the header) from being visible.\n *\n * Strategy:\n * 1. Check authentication first - redirect to login if not authenticated\n * 2. Allow rendering during event loading - prevents blocking UI\n * 3. If events exist but none selected - allow rendering so selector is visible\n * 4. If no events available - show error message\n * 5. Individual pages should handle \"no selected event\" state gracefully\n *\n * @param props - Configuration for route protection\n * @returns React element with route protection logic\n */\nexport function ProtectedRoute({\n requireEvent = false,\n noEventsFallback,\n loadingFallback,\n loginPath = '/login'\n}: ProtectedRouteProps) {\n const { isAuthenticated, isLoading } = useUnifiedAuth();\n \n // Always call useEvents() - UnifiedAuthProvider always includes EventServiceProvider\n // Only use the values when requireEvent is true\n const eventsContext = useEvents();\n const selectedEvent = requireEvent ? eventsContext.selectedEvent : null;\n const events = requireEvent ? (eventsContext.events || []) : [];\n const eventLoading = requireEvent ? (eventsContext.isLoading || false) : false;\n \n const sessionRestoration = useSessionRestoration();\n\n // Prevent full page reloads when switching tabs (handles bfcache and visibility changes)\n usePreventTabReload({ enabled: true, gracePeriodMs: 2000 });\n\n // Track if user was previously authenticated to prevent redirects during session refresh\n const wasAuthenticatedRef = useRef(false);\n const [shouldRedirect, setShouldRedirect] = useState(false);\n const tabJustBecameVisibleRef = useRef(false);\n \n // Track authentication state to detect when user was previously logged in\n useEffect(() => {\n if (isAuthenticated) {\n wasAuthenticatedRef.current = true;\n setShouldRedirect(false);\n tabJustBecameVisibleRef.current = false; // Clear visibility flag when authenticated\n }\n }, [isAuthenticated]);\n\n // Handle tab visibility changes - prevent immediate redirects when tab becomes visible\n // This prevents the page from refreshing when switching back to the tab\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let wasHidden = document.hidden;\n\n const handleVisibilityChange = () => {\n const isNowVisible = !document.hidden;\n \n // When tab becomes visible, immediately prevent redirects and give session refresh time\n if (isNowVisible && wasHidden) {\n // Tab just became visible - immediately prevent redirects\n if (!isAuthenticated && wasAuthenticatedRef.current) {\n tabJustBecameVisibleRef.current = true;\n setShouldRedirect(false); // Immediately clear redirect flag\n \n // Clear any existing timeout\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n \n // Wait a bit to see if session refresh completes\n timeoutId = setTimeout(() => {\n // Only allow redirect if still not authenticated after delay\n tabJustBecameVisibleRef.current = false;\n // Use a function to get the latest state\n setShouldRedirect((prev) => {\n // Only set to true if we're still not authenticated\n // This will be checked again in the render logic\n return prev;\n });\n }, 2000); // 2 second grace period for session refresh\n }\n } else if (!isNowVisible) {\n // Tab became hidden - clear the visibility flag\n tabJustBecameVisibleRef.current = false;\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n }\n \n wasHidden = !isNowVisible;\n };\n\n // Check initial state - if tab is visible and user appears logged out, give grace period\n if (!document.hidden && !isAuthenticated && wasAuthenticatedRef.current) {\n tabJustBecameVisibleRef.current = true;\n setShouldRedirect(false);\n timeoutId = setTimeout(() => {\n tabJustBecameVisibleRef.current = false;\n }, 2000);\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange);\n return () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n };\n }, [isAuthenticated]);\n\n // Reset redirect flag when authenticated\n useEffect(() => {\n if (isAuthenticated) {\n setShouldRedirect(false);\n tabJustBecameVisibleRef.current = false;\n }\n }, [isAuthenticated]);\n\n const isRestoringSession = useMemo(() => {\n return sessionRestoration.isRestoring &&\n !sessionRestoration.restorationComplete &&\n !sessionRestoration.restorationError &&\n !sessionRestoration.hasTimedOut;\n }, [\n sessionRestoration.isRestoring,\n sessionRestoration.restorationComplete,\n sessionRestoration.restorationError,\n sessionRestoration.hasTimedOut\n ]);\n\n // Show session restoration loader during restoration\n if (isRestoringSession) {\n return <SessionRestorationLoader />;\n }\n\n // Allow rendering during event loading - prevents blocking UI while events load\n // This must come before auth loading check to avoid blocking when only events are loading\n if (requireEvent && eventLoading) {\n return <Outlet />;\n }\n\n // Show loading state while auth is being determined (but not organisation/event loading)\n // Use isLoading (combined loading state) for consistency with simpler implementations\n if (isLoading && !sessionRestoration.hasTimedOut) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // Redirect to login if not authenticated\n // Priority order:\n // 1. If session restoration has timed out or errored → redirect immediately (even if loading)\n // 2. If user was never authenticated → redirect immediately (even if loading)\n // 3. If tab just became visible → show loading (prevent redirect during grace period)\n // 4. If we've confirmed they should redirect (after visibility change grace period) → redirect\n // 5. Otherwise, if loading → show loading spinner (session might be refreshing)\n // 6. Otherwise → redirect (user is not authenticated and not loading)\n if (!isAuthenticated) {\n // Session restoration timeout/error always redirects immediately\n if (sessionRestoration.hasTimedOut || sessionRestoration.restorationError) {\n logger.warn('ProtectedRoute', 'Session restoration failed, redirecting to login', {\n timedOut: sessionRestoration.hasTimedOut,\n error: sessionRestoration.restorationError?.message\n });\n return <Navigate to={loginPath} replace />;\n }\n\n // User was never authenticated → redirect immediately\n if (!wasAuthenticatedRef.current) {\n return <Navigate to={loginPath} replace />;\n }\n\n // Tab just became visible - show loading to prevent redirect during grace period\n // Also check document visibility state directly as a fallback\n const isTabVisible = typeof document !== 'undefined' && !document.hidden;\n if (tabJustBecameVisibleRef.current || (isTabVisible && wasAuthenticatedRef.current && isLoading)) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // We've confirmed redirect after grace period → redirect\n if (shouldRedirect) {\n return <Navigate to={loginPath} replace />;\n }\n\n // User was authenticated before but now appears logged out\n // Show loading state while we wait for session refresh (unless we're not loading)\n if (isLoading) {\n return loadingFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n // Not loading and not authenticated → redirect\n return <Navigate to={loginPath} replace />;\n }\n\n // If event is not required, allow rendering\n if (!requireEvent) {\n return <Outlet />;\n }\n\n // Note: Super admin bypass would require useRBAC hook which adds complexity\n // Apps that need super admin access without events should set requireEvent={false}\n // For now, we keep it simple and always require events when requireEvent=true\n\n // Event loading check already handled above before auth loading check\n\n // If no events are available, show error message\n if (!events || events.length === 0) {\n return noEventsFallback || (\n <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh', padding: '2rem' }}>\n <Alert variant=\"destructive\" className=\"max-w-md\">\n <AlertTitle>No Events Available</AlertTitle>\n <AlertDescription>\n You don't have access to any events. Please contact your administrator if you believe this is an error.\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n\n // KEY FIX: Allow rendering when events exist but none selected\n // This allows the event selector (typically in PaceAppLayout header) to be visible\n // Individual pages should handle \"no selected event\" state gracefully\n // Auto-selection will handle selecting the next event, or user can manually select\n \n // If no event selected but events exist, allow rendering\n // The event selector will be visible and user can select, or auto-selection will kick in\n if (!selectedEvent) {\n // Log for debugging - this is expected behavior, not an error\n return <Outlet />;\n }\n\n // Event is selected - allow rendering\n return <Outlet />;\n}\n\n","/**\n * @file File Upload Component\n * @package @jmruthers/pace-core\n * @module Components/FileUpload\n * \n * Provides a file upload interface using the file reference system.\n * Supports drag-and-drop, file validation, progress tracking, and accessibility.\n */\n\nimport React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { FileCategory, FileUploadResult, UploadProgress } from '../../types/file-reference';\nimport { useFileReference } from '../../hooks/useFileReference';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { getAppId } from '../../utils/app/appIdResolver';\nimport { assertAppId } from '../../types/core';\n\n/**\n * Props for the FileUpload component.\n * Configures file upload behavior including storage location, validation, and callbacks.\n */\nexport interface FileUploadProps {\n supabase: SupabaseClient;\n table_name: string;\n record_id: string;\n organisation_id?: string | null; // Optional for user-scoped files (e.g., profile photos)\n userId?: string; // Optional userId for user-scoped files (required if organisation_id is not provided)\n app_id?: string; // Optional - will be resolved from app name if not provided\n category: FileCategory;\n folder: string; // Folder name in storage bucket (e.g., 'profile_photos', 'documents')\n pageContext: string; // The page context where the file upload occurs (e.g., 'configuration', 'forms', 'applications')\n event_id?: string; // Optional event ID for event-scoped permission checks (required for event-based apps)\n accept?: string;\n maxSize?: number;\n multiple?: boolean;\n disabled?: boolean;\n isPublic?: boolean; // Whether files should be uploaded to public-files bucket\n className?: string;\n showPreview?: boolean; // Show image preview for accepted files\n showProgress?: boolean; // Show upload progress bar\n onUploadSuccess?: (result: FileUploadResult) => void;\n onUploadError?: (error: string, file?: File) => void;\n onProgress?: (progress: UploadProgress) => void;\n children?: React.ReactNode;\n}\n\ninterface FileUploadState {\n file: File;\n progress: UploadProgress;\n preview?: string;\n result?: FileUploadResult;\n}\n\nexport function FileUpload({\n supabase,\n table_name,\n record_id,\n organisation_id,\n userId,\n app_id,\n category,\n folder,\n pageContext,\n event_id,\n accept = '*/*',\n maxSize = 10 * 1024 * 1024, // 10MB default\n multiple = false,\n disabled = false,\n isPublic = false,\n className = '',\n showPreview = true,\n showProgress = true,\n onUploadSuccess,\n onUploadError,\n onProgress,\n children\n}: FileUploadProps) {\n // Validate pageContext early - required prop\n if (!pageContext) {\n const errorMsg = 'pageContext is required for FileUpload component. This is used for permission checks.';\n if (import.meta.env.MODE === 'development') {\n console.error('[FileUpload]', errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const [isDragging, setIsDragging] = useState(false);\n const [uploadStates, setUploadStates] = useState<Map<string, FileUploadState>>(new Map());\n const [resolvedAppId, setResolvedAppId] = useState<string | null>(app_id || null);\n const [isResolvingAppId, setIsResolvingAppId] = useState(!app_id);\n const [appIdError, setAppIdError] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const { uploadFile, isLoading, error } = useFileReference(supabase);\n\n // Resolve app_id from app name if not provided\n useEffect(() => {\n if (app_id) {\n // If app_id is provided, use it directly\n setResolvedAppId(app_id);\n setIsResolvingAppId(false);\n setAppIdError(null);\n return;\n }\n\n // Otherwise, resolve from app name\n const resolveAppId = async () => {\n setIsResolvingAppId(true);\n setAppIdError(null);\n\n try {\n const appName = getCurrentAppName();\n if (!appName) {\n const errorMsg = 'App ID is required. Either provide app_id prop or set app name via setRBACAppName()';\n setAppIdError(errorMsg);\n setIsResolvingAppId(false);\n return;\n }\n\n const resolvedId = await getAppId(supabase, appName);\n if (!resolvedId) {\n const errorMsg = `Failed to resolve app ID for app name \"${appName}\". Make sure the app is registered in rbac_apps table.`;\n setAppIdError(errorMsg);\n setIsResolvingAppId(false);\n return;\n }\n\n setResolvedAppId(resolvedId);\n setIsResolvingAppId(false);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to resolve app ID';\n setAppIdError(errorMessage);\n setIsResolvingAppId(false);\n }\n };\n\n resolveAppId();\n }, [app_id, supabase]);\n\n // Calculate isUploading and isDisabled early so they can be used in callbacks\n const isUploading = useMemo(() => {\n return uploadStates.size > 0 && Array.from(uploadStates.values()).some(state => \n state.progress.status === 'uploading' || state.progress.status === 'processing'\n );\n }, [uploadStates]);\n\n const isDisabled = useMemo(() => {\n return disabled || isUploading || isResolvingAppId || !resolvedAppId;\n }, [disabled, isUploading, isResolvingAppId, resolvedAppId]);\n\n // Generate preview URL for images\n const generatePreview = useCallback((file: File): Promise<string | null> => {\n return new Promise((resolve) => {\n if (!file.type.startsWith('image/')) {\n resolve(null);\n return;\n }\n \n const reader = new FileReader();\n reader.onload = (e) => {\n resolve(e.target?.result as string || null);\n };\n reader.onerror = () => resolve(null);\n reader.readAsDataURL(file);\n });\n }, []);\n\n // Validate file\n const validateFile = useCallback((file: File): string | null => {\n // Check file size\n if (file.size > maxSize) {\n return `File \"${file.name}\" exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`;\n }\n\n // Check file type if accept is specified\n if (accept !== '*/*') {\n const acceptedTypes = accept.split(',').map(type => type.trim());\n const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();\n const fileMimeType = file.type;\n\n const isAccepted = acceptedTypes.some(accepted => {\n if (accepted.startsWith('.')) {\n // Extension match\n return accepted === fileExtension;\n } else if (accepted.includes('/*')) {\n // MIME type wildcard (e.g., \"image/*\")\n const baseType = accepted.split('/')[0];\n return fileMimeType.startsWith(baseType + '/');\n } else {\n // Exact MIME type match\n return accepted === fileMimeType;\n }\n });\n\n if (!isAccepted) {\n return `File \"${file.name}\" is not an accepted format. Accepted: ${accept}`;\n }\n }\n\n return null;\n }, [accept, maxSize]);\n\n const handleFileSelect = useCallback(async (files: FileList | null) => {\n if (!files || files.length === 0) return;\n\n const fileArray = Array.from(files);\n \n // Validate all files first\n const validationErrors: string[] = [];\n const validFiles: File[] = [];\n\n for (const file of fileArray) {\n const error = validateFile(file);\n if (error) {\n validationErrors.push(error);\n onUploadError?.(error, file);\n } else {\n validFiles.push(file);\n }\n }\n\n if (validFiles.length === 0) {\n return;\n }\n\n // Initialize upload states\n const newUploadStates = new Map<string, FileUploadState>();\n \n for (const file of validFiles) {\n const fileId = `${file.name}-${file.size}-${Date.now()}`;\n const preview = showPreview ? (await generatePreview(file)) || undefined : undefined;\n \n const progress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'idle'\n };\n\n newUploadStates.set(fileId, {\n file,\n progress,\n preview\n });\n }\n\n setUploadStates(newUploadStates);\n\n // Upload files sequentially\n for (const [fileId, uploadState] of newUploadStates.entries()) {\n const { file } = uploadState;\n\n // Update status to uploading\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'uploading'\n }\n });\n }\n return updated;\n });\n\n try {\n // Simulate progress updates (Supabase doesn't provide real progress, so we estimate)\n const progressInterval = setInterval(() => {\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state && state.progress.status === 'uploading') {\n const estimatedProgress = Math.min(\n state.progress.percentage + 10,\n 90\n );\n const newProgress: UploadProgress = {\n ...state.progress,\n percentage: estimatedProgress,\n loaded: Math.floor((estimatedProgress / 100) * file.size)\n };\n onProgress?.(newProgress);\n updated.set(fileId, {\n ...state,\n progress: newProgress\n });\n }\n return updated;\n });\n }, 200);\n\n\n // Use resolved app_id\n if (!resolvedAppId) {\n const errorMsg = appIdError || 'App ID not available. Please provide app_id prop or set app name.';\n throw new Error(errorMsg);\n }\n\n // Validate pageContext before upload\n if (!pageContext) {\n const errorMsg = 'pageContext is required for file upload. This is used for permission checks.';\n throw new Error(errorMsg);\n }\n\n const result = await uploadFile({\n table_name,\n record_id,\n organisation_id: organisation_id || null,\n userId: userId, // Pass userId prop directly - it's required for user-scoped files when organisation_id is null\n app_id: resolvedAppId ? assertAppId(resolvedAppId) : assertAppId(''),\n category,\n folder,\n pageContext: pageContext,\n event_id,\n is_public: isPublic\n }, file);\n\n clearInterval(progressInterval);\n\n if (result) {\n // Update status to completed\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'completed',\n percentage: 100,\n loaded: file.size\n },\n result\n });\n }\n return updated;\n });\n\n const finalProgress: UploadProgress = {\n loaded: file.size,\n total: file.size,\n percentage: 100,\n fileName: file.name,\n status: 'completed'\n };\n onProgress?.(finalProgress);\n onUploadSuccess?.(result);\n\n // Upload preview and file information will persist until component unmounts\n // or new files are uploaded (replacing the uploadStates Map)\n } else {\n // Update status to error\n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'error',\n error: 'Upload failed'\n }\n });\n }\n return updated;\n });\n\n const errorProgress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'error',\n error: 'Upload failed'\n };\n onProgress?.(errorProgress);\n onUploadError?.('Upload failed', file);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Upload failed';\n \n setUploadStates(prev => {\n const updated = new Map(prev);\n const state = updated.get(fileId);\n if (state) {\n updated.set(fileId, {\n ...state,\n progress: {\n ...state.progress,\n status: 'error',\n error: errorMessage\n }\n });\n }\n return updated;\n });\n\n const errorProgress: UploadProgress = {\n loaded: 0,\n total: file.size,\n percentage: 0,\n fileName: file.name,\n status: 'error',\n error: errorMessage\n };\n onProgress?.(errorProgress);\n onUploadError?.(errorMessage, file);\n }\n }\n }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError, pageContext]);\n\n const handleDragOver = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!isDisabled) {\n setIsDragging(true);\n }\n }, [isDisabled]);\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n }, []);\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n \n if (isDisabled) return;\n \n const files = e.dataTransfer.files;\n handleFileSelect(files);\n }, [isDisabled, handleFileSelect]);\n\n const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n handleFileSelect(e.target.files);\n // Reset input value to allow re-uploading the same file\n if (e.target) {\n e.target.value = '';\n }\n }, [handleFileSelect]);\n\n const handleClick = useCallback(() => {\n if (!isDisabled && fileInputRef.current) {\n fileInputRef.current.click();\n }\n }, [isDisabled]);\n\n const formatFileSize = (bytes: number): string => {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n };\n\n const dragClasses = isDragging ? 'border-main-500 bg-main-50' : 'border-sec-300 hover:border-sec-400';\n const disabledClasses = isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-sec-50';\n\n return (\n <div className={`space-y-4 ${className}`}>\n <div\n role=\"button\"\n tabIndex={isDisabled ? -1 : 0}\n aria-label=\"File upload area\"\n aria-disabled={isDisabled}\n className={`relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${dragClasses} ${disabledClasses}`}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n onClick={!isDisabled ? handleClick : undefined}\n onKeyDown={!isDisabled ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick();\n }\n } : undefined}\n >\n {children || (\n <div className=\"space-y-2\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n onChange={handleFileInputChange}\n className=\"hidden\"\n disabled={isDisabled}\n data-testid=\"file-input\"\n aria-label={accept ? `Upload file${multiple ? 's' : ''} (${accept})` : `Upload file${multiple ? 's' : ''}`}\n />\n <div className=\"text-sec-600\">\n {isResolvingAppId ? (\n 'Resolving app configuration...'\n ) : isDragging ? (\n 'Drop files here...'\n ) : (\n <>\n <span className=\"font-medium\">Click to upload</span>\n {' '}or drag and drop\n </>\n )}\n </div>\n <div className=\"text-sm text-sec-500\">\n {!isResolvingAppId && accept !== '*/*' && `Accepted formats: ${accept}`}\n {!isResolvingAppId && maxSize && ` • Max size: ${Math.round(maxSize / 1024 / 1024)}MB`}\n {!isResolvingAppId && multiple && ' • Multiple files allowed'}\n </div>\n </div>\n )}\n \n {isUploading && !showProgress && (\n <div \n className=\"absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Uploading file\"\n >\n <div className=\"animate-spin rounded-full size-8 border-b-2 border-main-500\" aria-hidden=\"true\"></div>\n </div>\n )}\n </div>\n\n {/* Upload Progress List */}\n {showProgress && uploadStates.size > 0 && (\n <div className=\"space-y-2\">\n {Array.from(uploadStates.entries()).map(([fileId, uploadState]) => {\n const { file, progress, preview, result } = uploadState;\n const isError = progress.status === 'error';\n const isCompleted = progress.status === 'completed';\n const isUploading = progress.status === 'uploading' || progress.status === 'processing';\n\n return (\n <div\n key={fileId}\n className={`flex items-center space-x-3 p-3 rounded-lg border ${\n isError \n ? 'bg-acc-50 border-acc-200' \n : isCompleted \n ? 'bg-success-50 border-success-200'\n : 'bg-sec-50 border-sec-200'\n }`}\n >\n {/* Preview/Icon */}\n <div className=\"flex-shrink-0\">\n {preview ? (\n <img\n src={preview}\n alt={file.name}\n className=\"w-12 h-12 object-cover rounded\"\n />\n ) : (\n <div className=\"w-12 h-12 flex items-center justify-center bg-sec-200 rounded\">\n <span className=\"text-2xl\">📄</span>\n </div>\n )}\n </div>\n\n {/* File Info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sec-900 truncate\">\n {file.name}\n </div>\n <div className=\"text-sm text-sec-500\">\n {formatFileSize(file.size)}\n {isCompleted && result && ' • Uploaded'}\n {isError && progress.error && ` • ${progress.error}`}\n </div>\n \n {/* Progress Bar */}\n {showProgress && (isUploading || isError) && (\n <div className=\"mt-2\">\n <div className=\"w-full bg-sec-200 rounded-full h-2\">\n <div\n className={`h-2 rounded-full transition-all duration-300 ${\n isError ? 'bg-acc-500' : 'bg-main-500'\n }`}\n style={{ width: `${progress.percentage}%` }}\n />\n </div>\n {isUploading && (\n <div className=\"text-xs text-sec-500 mt-1\">\n {progress.percentage}% • {formatFileSize(progress.loaded)} / {formatFileSize(progress.total)}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Status Icon */}\n <div className=\"flex-shrink-0\">\n {isCompleted && (\n <span className=\"text-success-500 text-xl\">✓</span>\n )}\n {isError && (\n <span className=\"text-acc-500 text-xl\">✕</span>\n )}\n {isUploading && (\n <div \n className=\"animate-spin rounded-full size-5 border-b-2 border-main-500\"\n role=\"status\"\n aria-label=\"Uploading\"\n aria-hidden=\"true\"\n ></div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n \n {appIdError && (\n <div \n className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {appIdError}\n </div>\n )}\n {error && (\n <div \n className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {error}\n </div>\n )}\n </div>\n );\n}\n\n\n","/**\n * @file Table Component System\n * @package @jmruthers/pace-core\n * @module Components/Table\n * @since 0.1.0\n *\n * A comprehensive table component system for displaying tabular data.\n * Provides accessible table components with consistent styling and behavior.\n *\n * Features:\n * - Semantic HTML table structure\n * - Consistent styling and spacing\n * - Hover states and transitions\n * - Responsive design\n * - Accessibility compliant\n * - Customizable styling\n * - Checkbox support\n * - Caption support\n *\n * @example\n * ```tsx\n * // Basic table\n * <Table>\n * <TableCaption>A list of your recent invoices.</TableCaption>\n * <TableHeader>\n * <TableRow>\n * <TableHead>Invoice</TableHead>\n * <TableHead>Status</TableHead>\n * <TableHead>Method</TableHead>\n * <TableHead>Amount</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>INV001</TableCell>\n * <TableCell>Paid</TableCell>\n * <TableCell>Credit Card</TableCell>\n * <TableCell>$250.00</TableCell>\n * </TableRow>\n * <TableRow>\n * <TableCell>INV002</TableCell>\n * <TableCell>Pending</TableCell>\n * <TableCell>PayPal</TableCell>\n * <TableCell>$150.00</TableCell>\n * </TableRow>\n * </TableBody>\n * <TableFooter>\n * <TableRow>\n * <TableCell colSpan={3}>Total</TableCell>\n * <TableCell>$400.00</TableCell>\n * </TableRow>\n * </TableFooter>\n * </Table>\n * \n * // Table with checkboxes\n * <Table>\n * <TableHeader>\n * <TableRow>\n * <TableHead className=\"w-12\">\n * <Checkbox />\n * </TableHead>\n * <TableHead>Name</TableHead>\n * <TableHead>Email</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>\n * <Checkbox />\n * </TableCell>\n * <TableCell>John Doe</TableCell>\n * <TableCell>john@example.com</TableCell>\n * </TableRow>\n * </TableBody>\n * </Table>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper table semantics\n * - Screen reader support\n * - Keyboard navigation\n * - Focus management\n * - High contrast support\n * - Caption for table description\n *\n * @dependencies\n * - React 19+ - Hooks and refs\n * - Tailwind CSS - Styling\n */\n\nimport * as React from \"react\"\n\nimport { cn } from \"../../utils/core/cn\"\n\n/**\n * Table component\n * The main table container with semantic HTML structure\n * \n * @param props - Table configuration and styling\n * @param ref - Forwarded ref to the table element\n * @returns JSX.Element - The rendered table element\n * \n * @example\n * ```tsx\n * <Table>\n * <TableHeader>...</TableHeader>\n * <TableBody>...</TableBody>\n * </Table>\n * ```\n */\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n))\nTable.displayName = \"Table\"\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n))\nTableHeader.displayName = \"TableHeader\"\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n))\nTableBody.displayName = \"TableBody\"\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n))\nTableFooter.displayName = \"TableFooter\"\n\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted\",\n className\n )}\n {...props}\n />\n))\nTableRow.displayName = \"TableRow\"\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n))\nTableHead.displayName = \"TableHead\"\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-4 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n))\nTableCell.displayName = \"TableCell\"\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"mt-4 text-sm text-muted-foreground\", className)}\n {...props}\n />\n))\nTableCaption.displayName = \"TableCaption\"\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableCaption,\n TableCell,\n TableFooter,\n TableHead,\n TableRow,\n}\n","/**\n * @file Public Page Layout Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A layout component specifically designed for public pages that don't require authentication.\n * Provides a consistent structure for public event pages with event-specific branding.\n *\n * Features:\n * - No authentication required\n * - Event-specific header and branding\n * - Automatic event color theming (applies event_colours when available)\n * - Responsive design\n * - Print-friendly styling\n * - Error boundary integration\n * - Loading state management\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { PublicPageLayout, usePublicRouteParams, usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams({ fetchEventData: false });\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode || '');\n * \n * // PublicPageLayout handles all loading, error, and missing event states\n * return (\n * <PublicPageLayout \n * eventCode={eventCode || ''}\n * event={event}\n * isLoading={isLoading}\n * error={error}\n * refetch={refetch}\n * >\n * <h1>Event Details</h1>\n * <main className=\"content\">\n * Your public page content\n * </main>\n * </PublicPageLayout>\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - Keyboard navigation support\n * - High contrast support\n * - Clear content hierarchy\n *\n * @routing\n * - Works with React Router\n * - Supports public route patterns\n * - Event code validation\n * - Error handling for invalid routes\n *\n * @dependencies\n * - React 19+ - Component framework\n * - React Router - Routing integration\n * - Public hooks - Data access\n * - Tailwind CSS - Styling\n */\n\nimport React, { ReactNode } from 'react';\nimport { ErrorBoundary } from '../ErrorBoundary';\nimport { LoadingSpinner } from '../LoadingSpinner';\nimport { Button } from '../Button';\nimport { FileDisplay } from '../FileDisplay/FileDisplay';\nimport { FileCategory } from '../../types/file-reference';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport { useAppConfig } from '../../hooks/useAppConfig';\nimport { cn } from '../../utils/core/cn';\nimport type { Event } from '../../types/event';\n\nexport interface PublicPageLayoutProps {\n /** The event code for this public page */\n eventCode: string;\n /** Child components to render */\n children: ReactNode;\n /** Optional event data - if not provided, will be fetched by parent component */\n event?: Event | null;\n /** Loading state - if true, shows loading spinner */\n isLoading?: boolean;\n /** Error state - if provided, shows error message */\n error?: Error | null;\n /** Function to retry loading event data */\n refetch?: () => Promise<void> | void;\n /** Whether to show the footer (default: true) */\n showFooter?: boolean;\n /** Custom error fallback component */\n errorFallback?: React.ComponentType<{ error: Error; retry: () => void }>;\n /** Custom loading fallback component */\n loadingFallback?: React.ComponentType;\n /** Custom header component */\n customHeader?: ReactNode;\n /** Custom footer component */\n customFooter?: ReactNode;\n /** Whether to show event validation errors (default: true) */\n showValidationErrors?: boolean;\n /** Custom loading message */\n loadingMessage?: string;\n}\n\n// === HEADER COMPONENT ===\n\nexport interface PublicPageHeaderProps {\n /** The event data for this public page */\n event?: Event;\n /** The event code for this public page */\n eventCode: string;\n /** Optional page title */\n title?: string;\n /** Optional page description */\n description?: string;\n /** Whether to show the event logo (default: true) */\n showEventLogo?: boolean;\n /** Whether to show the app logo (default: true) */\n showAppLogo?: boolean;\n /** Custom CSS classes for the header */\n className?: string;\n /** Custom content to display in the header */\n children?: ReactNode;\n /** Custom event logo component */\n customEventLogo?: ReactNode;\n}\n\nexport function PublicPageHeader({\n event,\n eventCode,\n title,\n description,\n showEventLogo = true,\n showAppLogo = true,\n className = '',\n children,\n customEventLogo\n}: PublicPageHeaderProps) {\n const { appName } = useAppConfig();\n\n return (\n <header className={cn(\n \"w-full px-[max(0rem,calc((100vw-var(--app-width))/2-0.5rem))] grid grid-cols-[auto_1fr_auto] place-items-center gap-2\",\n className\n )}>\n {/* App Logo */}\n {showAppLogo && appName && (\n <img\n className=\"ml-4 max-w-36 object-contain row-span-2\"\n src={`/${appName.toLowerCase()}_logo_wide.svg`}\n alt={appName}\n />\n )}\n\n {/* Event Information */}\n {event && (\n <>\n <h1>{event.event_name}</h1>\n {/* Event Logo */}\n {showEventLogo && event && (\n <>\n {customEventLogo || (\n <FileDisplay\n table_name=\"event\"\n record_id={event.event_id}\n organisation_id={event.organisation_id}\n category={FileCategory.EVENT_LOGOS}\n displayOnly={true}\n showFallback={true}\n fallbackSize=\"md\"\n className=\"mr-4 max-w-36 row-span-2\"\n generateFallbackText={(fileName) => {\n if (!event.event_name) return 'EV';\n return event.event_name\n .split(/[\\s\\-_]+/)\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3);\n }}\n />\n )}\n </>\n )}\n {event.event_venue && (\n <h4>{event.event_venue}</h4>\n )}\n </>\n )}\n\n {/* Page Title and Description */}\n {title && (\n <>\n <h1>{title}</h1>\n {description && (\n <p className=\"text-lg text-sec-600 max-w-3xl mx-auto\">\n {description}\n </p>\n )}\n </>\n )}\n\n {/* Custom Content */}\n {children && <>{children}</>}\n </header>\n );\n}\n\n// === FOOTER COMPONENT ===\n\nexport interface PublicPageFooterProps {\n /** The event data for this public page */\n event: Event;\n /** Company or organization name */\n companyName?: string;\n /** Current year or custom year for copyright */\n year?: number;\n /** Optional array of navigation links to display */\n links?: Array<{\n label: string;\n href: string;\n }>;\n /** Optional CSS class name */\n className?: string;\n /** Logo image URL */\n logo?: string;\n /** Copyright text */\n copyright?: string;\n /** Footer content - children to render inside footer */\n children?: React.ReactNode;\n}\n\nexport function PublicPageFooter({\n event,\n companyName = 'Solvera Solutions Pty Ltd',\n year = new Date().getFullYear(),\n links,\n className = '',\n logo,\n copyright,\n children\n}: PublicPageFooterProps) {\n const copyrightText = copyright || `© Copyright 2022–${year} all rights reserved, ${companyName}.`;\n\n return (\n <footer className={cn('mt-8 py-6 flex justify-center', className)}>\n <section className='px-4 w-[min(var(--app-width),100%)] mx-auto text-center'>\n {logo && (\n <img src={logo} alt=\"Logo\" className=\"h-8 w-auto\" />\n )}\n\n {children && <>{children}</>}\n\n <span className=\"text-muted-foreground\">\n {copyrightText}\n </span>\n\n {links && links.length > 0 && (\n <ul className=\"flex gap-4 mt-2 md:mt-0\">\n {links.map((link, index) => (\n <li key={index}>\n <a href={link.href} className=\"text-muted-foreground hover:text-foreground\">\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n )}\n </section>\n </footer>\n );\n}\n\n/**\n * Layout component for public pages that don't require authentication\n * \n * This component provides a consistent structure for public event pages\n * with event-specific branding, error handling, and loading states.\n * \n * Automatically applies event colors from the event's event_colours field\n * when an event is provided, ensuring consistent theming across public pages.\n * \n * @param props - Layout configuration and content\n * @returns React element with complete public page layout\n */\nexport function PublicPageLayout({\n eventCode,\n children,\n event = null,\n isLoading = false,\n error = null,\n refetch,\n showFooter = true,\n errorFallback: ErrorFallback,\n loadingFallback: LoadingFallback,\n customHeader,\n customFooter,\n showValidationErrors = true,\n loadingMessage\n}: PublicPageLayoutProps) {\n // Apply event theme colors automatically when event is available\n // This works in public page context without requiring EventProvider\n useEventTheme(event);\n\n // Default refetch function\n const handleRefetch = refetch || (async () => {});\n\n // Handle loading state\n if (isLoading) {\n if (LoadingFallback) {\n return <LoadingFallback />;\n }\n return (\n <div className=\"min-h-screen bg-background flex items-center justify-center\">\n <div className=\"max-w-md mx-auto text-center px-4\">\n <LoadingSpinner size=\"lg\" className=\"mx-auto mb-4\" />\n {loadingMessage && (\n <p className=\"text-sec-600\">{loadingMessage}</p>\n )}\n </div>\n </div>\n );\n }\n\n // Handle error state\n if (error && showValidationErrors) {\n if (ErrorFallback) {\n return <ErrorFallback error={error} retry={handleRefetch} />;\n }\n return (\n <main className=\"flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n\n <h1>Event Not Found</h1>\n <p>\n The event code \"{eventCode}\" is invalid or the event is not available for public viewing.\n </p>\n <Button onClick={handleRefetch}>Try Again</Button>\n\n </main>\n );\n }\n\n // Handle missing event\n if (!event && showValidationErrors) {\n return (\n <main className=\"flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n\n <h1>Event Not Available</h1>\n <p>\n This event is not available for public viewing.\n </p>\n {handleRefetch && <Button onClick={handleRefetch}>Try Again</Button>}\n\n </main>\n );\n }\n\n // At this point, if showValidationErrors is true, event must exist\n // If showValidationErrors is false, we allow rendering without event\n // But footer requires event, so only show it if event exists\n return (\n <ErrorBoundary componentName=\"PublicPageLayout\">\n <>\n {/* Header */}\n {customHeader || (\n <PublicPageHeader \n event={event || undefined}\n eventCode={eventCode}\n />\n )}\n\n {/* Main Content */}\n <main className=\"px-4 w-[min(var(--app-width),100%)] mx-auto py-8\">\n {children}\n </main>\n\n {/* Footer - only show if event exists */}\n {showFooter && event && (\n customFooter || <PublicPageFooter event={event} />\n )}\n </>\n </ErrorBoundary>\n );\n}\n\n"],"mappings":"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","names":["React","Fragment","jsx","jsxs","jsx","React","useState","useEffect","useCallback","useRef","useState","useEffect","useCallback","useRef","useState","useRef","useCallback","error","useEffect","Fragment","jsx","jsxs","React","FileDisplayContent","useState","useRef","useCallback","useEffect","error","fileUrl","useState","useCallback","useEffect","useRef","useMemo","log","useState","useMemo","useCallback","getSignedUrl","useRef","useEffect","error","React","jsx","jsx","jsx","React","jsx","React","jsx","React","Fragment","jsx","jsxs","props","className","components","classNames","React","jsx","jsxs","Fragment","jsx","jsxs","React","useState","useCallback","useMemo","jsx","jsxs","React","useState","useMemo","useCallback","useMemo","Calendar","Fragment","jsx","jsxs","isSuperAdmin","useMemo","Calendar","useState","jsx","jsxs","useState","React","useCallback","useMemo","useState","jsx","jsxs","React","UserMenu","useState","useMemo","useCallback","UserMenuLoading","React","ChevronDown","React","userId","isSuperAdmin","jsx","jsxs","ChevronDown","jsx","jsxs","React","Fragment","jsx","jsxs","React","useState","useEffect","useMemo","Fragment","jsx","jsxs","useState","useEffect","superAdminStatus","isSuperAdmin","useMemo","useUnifiedAuth","useEffect","useState","useContext","useNavigate","useLocation","jsx","jsxs","useNavigate","useLocation","useState","useContext","useEffect","jsx","jsxs","useMemo","useEffect","useRef","useState","Outlet","jsx","jsxs","useRef","useState","useEffect","useMemo","Outlet","useState","useCallback","useRef","useEffect","useMemo","Fragment","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","error","isUploading","React","jsx","Fragment","jsx","jsxs"]}
|