@jmruthers/pace-core 0.5.152 → 0.5.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/{chunk-UHNMAVK4.js → chunk-4MBPFXR4.js} +56 -4
  2. package/dist/chunk-4MBPFXR4.js.map +1 -0
  3. package/dist/components.js +1 -1
  4. package/dist/index.js +1 -1
  5. package/docs/api/classes/ColumnFactory.md +1 -1
  6. package/docs/api/classes/ErrorBoundary.md +1 -1
  7. package/docs/api/classes/InvalidScopeError.md +1 -1
  8. package/docs/api/classes/MissingUserContextError.md +1 -1
  9. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  10. package/docs/api/classes/PermissionDeniedError.md +1 -1
  11. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  12. package/docs/api/classes/RBACAuditManager.md +1 -1
  13. package/docs/api/classes/RBACCache.md +1 -1
  14. package/docs/api/classes/RBACEngine.md +1 -1
  15. package/docs/api/classes/RBACError.md +1 -1
  16. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  17. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  18. package/docs/api/classes/StorageUtils.md +1 -1
  19. package/docs/api/enums/FileCategory.md +1 -1
  20. package/docs/api/interfaces/AggregateConfig.md +1 -1
  21. package/docs/api/interfaces/BadgeProps.md +1 -1
  22. package/docs/api/interfaces/ButtonProps.md +1 -1
  23. package/docs/api/interfaces/CalendarProps.md +1 -1
  24. package/docs/api/interfaces/CardProps.md +1 -1
  25. package/docs/api/interfaces/ColorPalette.md +1 -1
  26. package/docs/api/interfaces/ColorShade.md +1 -1
  27. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  28. package/docs/api/interfaces/DataRecord.md +1 -1
  29. package/docs/api/interfaces/DataTableAction.md +1 -1
  30. package/docs/api/interfaces/DataTableColumn.md +1 -1
  31. package/docs/api/interfaces/DataTableProps.md +1 -1
  32. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  33. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  34. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  35. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  36. package/docs/api/interfaces/EventLogoProps.md +1 -1
  37. package/docs/api/interfaces/ExportColumn.md +1 -1
  38. package/docs/api/interfaces/ExportOptions.md +1 -1
  39. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  40. package/docs/api/interfaces/FileMetadata.md +1 -1
  41. package/docs/api/interfaces/FileReference.md +1 -1
  42. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  43. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  44. package/docs/api/interfaces/FileUploadProps.md +1 -1
  45. package/docs/api/interfaces/FooterProps.md +1 -1
  46. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  47. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  48. package/docs/api/interfaces/InputProps.md +1 -1
  49. package/docs/api/interfaces/LabelProps.md +1 -1
  50. package/docs/api/interfaces/LoginFormProps.md +1 -1
  51. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  52. package/docs/api/interfaces/NavigationContextType.md +1 -1
  53. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  54. package/docs/api/interfaces/NavigationItem.md +1 -1
  55. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  56. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  57. package/docs/api/interfaces/Organisation.md +1 -1
  58. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  59. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  60. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  61. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  62. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  63. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  64. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  65. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  66. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  67. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  68. package/docs/api/interfaces/PaletteData.md +1 -1
  69. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  70. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  71. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  72. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  73. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  74. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  75. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  76. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  77. package/docs/api/interfaces/RBACConfig.md +1 -1
  78. package/docs/api/interfaces/RBACLogger.md +1 -1
  79. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  80. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  81. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  82. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  83. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  84. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  85. package/docs/api/interfaces/RouteConfig.md +1 -1
  86. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  87. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  88. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  89. package/docs/api/interfaces/StorageConfig.md +1 -1
  90. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  91. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  92. package/docs/api/interfaces/StorageListOptions.md +1 -1
  93. package/docs/api/interfaces/StorageListResult.md +1 -1
  94. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  95. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  96. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  97. package/docs/api/interfaces/StyleImport.md +1 -1
  98. package/docs/api/interfaces/SwitchProps.md +1 -1
  99. package/docs/api/interfaces/TabsContentProps.md +1 -1
  100. package/docs/api/interfaces/TabsListProps.md +1 -1
  101. package/docs/api/interfaces/TabsProps.md +1 -1
  102. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  103. package/docs/api/interfaces/TextareaProps.md +1 -1
  104. package/docs/api/interfaces/ToastActionElement.md +1 -1
  105. package/docs/api/interfaces/ToastProps.md +1 -1
  106. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  107. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  108. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  109. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  110. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  111. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  112. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  113. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  114. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  115. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  116. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  117. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  118. package/docs/api/interfaces/UserEventAccess.md +1 -1
  119. package/docs/api/interfaces/UserMenuProps.md +1 -1
  120. package/docs/api/interfaces/UserProfile.md +1 -1
  121. package/docs/api/modules.md +2 -2
  122. package/package.json +1 -1
  123. package/src/components/NavigationMenu/NavigationMenu.tsx +62 -3
  124. package/dist/chunk-UHNMAVK4.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/EventProvider.tsx","../src/components/Label/Label.tsx","../src/components/Textarea/Textarea.tsx","../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/EventSelector/EventSelector.tsx","../src/components/PasswordReset/PasswordChangeForm.tsx","../src/components/UserMenu/UserMenu.tsx","../src/components/NavigationMenu/NavigationMenu.tsx","../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/ErrorBoundary/ErrorBoundary.tsx","../src/components/OrganisationSelector/OrganisationSelector.tsx","../src/hooks/useFileReference.ts","../src/components/FileUpload/FileUpload.tsx","../src/components/FileDisplay/FileDisplay.tsx","../src/hooks/useFileUrl.ts","../src/components/Table/Table.tsx","../src/components/PublicLayout/PublicPageHeader.tsx","../src/components/PublicLayout/PublicPageFooter.tsx","../src/components/PublicLayout/PublicLoadingSpinner.tsx","../src/components/PublicLayout/PublicPageLayout.tsx","../src/components/PublicLayout/PublicPageContextChecker.tsx","../src/components/PublicLayout/EventLogo.tsx"],"sourcesContent":["/**\n * @file Re-export for EventProvider\n * @package @jmruthers/pace-core\n * @module Providers\n * @since 0.1.0\n * \n * Re-exports the service-based EventProvider for backward compatibility.\n */\n\nexport { EventServiceProvider as EventProvider } from './services/EventServiceProvider';\nexport type { EventServiceProviderProps as EventProviderProps } from './services/EventServiceProvider';\n\n// Re-export context and hook \nexport { EventServiceContext, useEventService } from './services/EventServiceProvider';\nexport type { EventServiceContextType, EventContextType } from './services/EventServiceProvider';\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 * - class-variance-authority - Variant styling\n * - React 18+ - 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 <label\n aria-label=\"required\"\n className={cn(\n 'text-destructive ml-1',\n hideRequiredIndicator && 'sr-only'\n )}\n >\n {requiredIndicator || '*'}\n </label>\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 */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant = 'default', size = 'md', error, ...props }, ref) => {\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);\n\nTextarea.displayName = 'Textarea';\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { Textarea };\n\n","/**\n * @file Avatar Component Suite\n * @package @jmruthers/pace-core\n * @module Components\n * @since 0.1.0\n *\n * A flexible and accessible avatar component for displaying user profile images or initials.\n * Includes Avatar, AvatarImage, and AvatarFallback subcomponents.\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 * // Basic avatar with image\n * <Avatar>\n * <AvatarImage src=\"/user.jpg\" alt=\"User\" />\n * <AvatarFallback>AB</AvatarFallback>\n * </Avatar>\n *\n * // Avatar with fallback only\n * <Avatar>\n * <AvatarFallback>JD</AvatarFallback>\n * </Avatar>\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 * as AvatarPrimitive from \"@radix-ui/react-avatar\"\n\nimport { cn } from \"../../utils/core/cn\"\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(\n \"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full\",\n className\n )}\n {...props}\n />\n))\nAvatar.displayName = AvatarPrimitive.Root.displayName\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => (\n <AvatarPrimitive.Image\n ref={ref}\n className={cn(\"object-cover\", className)}\n {...props}\n />\n))\nAvatarImage.displayName = AvatarPrimitive.Image.displayName\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>\n>(({ className, ...props }, ref) => (\n <AvatarPrimitive.Fallback\n ref={ref}\n className={cn(\n \"flex h-full w-full items-center justify-center rounded-full text-sec-50 bg-sec-500\",\n className\n )}\n {...props}\n />\n))\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName\n\nexport { Avatar, AvatarImage, AvatarFallback }\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\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\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', 'mx-1', '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 = 'inline-flex text-balance items-center rounded-2xl px-3 py-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 */\nconst Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant = 'solid-main-normal', ...props }, ref) => {\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);\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 * <div className=\"flex items-center gap-2\">\n * <Switch \n * checked={checked} \n * onCheckedChange={setChecked}\n * id=\"notifications\"\n * />\n * <label htmlFor=\"notifications\">\n * Enable notifications\n * </label>\n * </div>\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 * <div className=\"flex items-center gap-2\">\n * <Switch id=\"terms\" />\n * <Label htmlFor=\"terms\">\n * I agree to the terms and conditions\n * </Label>\n * </div>\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 h-5 w-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';\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, ...props }, ref) => (\n <TabsPrimitive.Root ref={ref} {...props} />\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, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n 'inline-flex h-10 items-center justify-center rounded-md bg-sec-100 p-1 text-sec-600',\n className\n )}\n {...props}\n />\n));\n\nTabsList.displayName = TabsPrimitive.List.displayName || 'TabsList';\n\n// ============================================================================\n// TABS TRIGGER COMPONENT\n// ============================================================================\n\nexport interface TabsTriggerProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> {}\n\n/**\n * TabsTrigger component\n * Individual tab button that activates a tab panel\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 */\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n 'data-[state=active]:bg-background data-[state=active]:text-main-600 data-[state=active]:shadow-sm',\n 'data-[state=inactive]:text-sec-600 data-[state=inactive]:hover:text-main-600',\n className\n )}\n {...props}\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 * <div>Content for tab 1</div>\n * </TabsContent>\n * ```\n */\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n TabsContentProps\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',\n className\n )}\n {...props}\n />\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\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 { DayPicker, type DayPickerProps } from 'react-day-picker';\nimport { cn } from '../../utils/core/cn';\n\n// ============================================================================\n// CALENDAR COMPONENT\n// ============================================================================\n\nexport interface CalendarProps extends Omit<DayPickerProps, 'className' | 'classNames' | 'styles'> {\n /**\n * Additional CSS classes to apply to the calendar wrapper\n */\n className?: string;\n /**\n * Custom classNames for DayPicker sub-components\n */\n classNames?: DayPickerProps['classNames'];\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 * @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\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 */\nconst Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(\n ({ className, classNames, mode, ...props }, ref) => {\n return (\n <div ref={ref} className={cn('p-3', className)}>\n <DayPicker\n mode={mode}\n className=\"rounded-md border border-sec-200 bg-background\"\n classNames={{\n months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',\n month: 'space-y-4',\n caption: 'flex justify-center pt-1 relative items-center',\n caption_label: 'text-sm font-medium',\n nav: 'space-x-1 flex items-center',\n nav_button: cn(\n '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 nav_button_previous: 'absolute left-1',\n nav_button_next: 'absolute right-1',\n table: 'w-full border-collapse space-y-1',\n head_row: 'flex',\n head_cell: 'text-sec-600 rounded-md w-9 font-normal text-[0.8rem]',\n row: 'flex w-full mt-2',\n cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-acc-50/50 [&:has([aria-selected])]:bg-acc-100 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',\n day: 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 day_range_end: 'day-range-end',\n day_selected: 'bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50 focus:bg-main-600 focus:text-main-50',\n day_today: 'bg-sec-100 text-main-600 font-semibold',\n day_outside: 'day-outside text-sec-400 opacity-50 aria-selected:bg-acc-50/50 aria-selected:text-sec-400 aria-selected:opacity-30',\n day_disabled: 'text-sec-400 opacity-50 cursor-not-allowed',\n day_range_middle: 'aria-selected:bg-acc-100 aria-selected:text-main-600',\n day_hidden: 'invisible',\n ...classNames,\n }}\n components={{\n IconLeft: ({ ...props }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n {...props}\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n ),\n IconRight: ({ ...props }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"h-4 w-4\"\n {...props}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n ),\n ...props.components,\n }}\n {...(props as any)}\n />\n </div>\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 18+ - 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 } 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=\"h-4 w-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\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: any) => {\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 18+ - Hooks and context\n */\n\nimport React from 'react';\nimport { useForm, FormProvider, UseFormReturn, FieldValues, DefaultValues, SubmitHandler, SubmitErrorHandler } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { cn } from '../../utils/core/cn';\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 });\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 * @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 18+ - 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\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 // Memoized handlers\n const handleEmailChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n setFormData(prev => ({ ...prev, email: e.target.value }));\n }, []);\n\n const handlePasswordChange = useCallback((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 = useCallback(() => {\n onSignUp?.();\n }, [onSignUp]);\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\">\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 EventSelector Component\n * @package @jmruthers/pace-core\n * @module Components/EventSelector\n * @since 0.1.0\n *\n * A secure event selector component that allows users to choose from events they have\n * access to based on their role-based permissions. Integrates with the RBAC system\n * to ensure users only see events they're authorized to access.\n *\n * Features:\n * - Role-based event access control\n * - Automatic next event detection and selection\n * - Cross-device synchronization via Supabase\n * - Offline support with localStorage fallback\n * - Comprehensive error handling and retry functionality\n * - Event details display in dropdown\n * - Next/upcoming event indicators\n * - Loading states and user feedback\n * - Accessible interface design\n * - Integration with EventProvider\n *\n * @example\n * ```tsx\n * // Basic event selector\n * <EventSelector \n * onEventChange={(event) => console.log('Selected event:', event)}\n * />\n * \n * // With custom configuration\n * <EventSelector\n * placeholder=\"Choose an event...\"\n * showEventDetails={true}\n * showNextEventIndicator={true}\n * showRetryButton={true}\n * onEventChange={handleEventChange}\n * />\n * \n * // In a header component\n * <Header>\n * <EventSelector \n * className=\"w-64\"\n * showEventDetails={false}\n * onEventChange={setCurrentEvent}\n * />\n * </Header>\n * \n * // With error handling\n * <EventSelector\n * showNoEventsMessage={true}\n * showRetryButton={true}\n * onEventChange={(event) => {\n * if (event) {\n * setCurrentEvent(event);\n * navigate(`/events/${event.id}`);\n * }\n * }}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA labels and descriptions\n * - Keyboard navigation support\n * - Screen reader friendly\n * - Focus management\n * - High contrast support\n * - Clear error identification\n *\n * @security\n * - Role-based access control integration\n * - Secure event data handling\n * - User permission validation\n * - No unauthorized event exposure\n * - Secure session management\n *\n * @dependencies\n * - EventProvider - Event context and state\n * - Select components - Dropdown interface\n * - Button component - Retry functionality\n * - Alert component - Error display\n * - LoadingSpinner - Loading states\n * - React 18+ - Hooks and effects\n * - Tailwind CSS - Styling\n */\n\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { RefreshCw, AlertCircle, Lock, Calendar, Star } from 'lucide-react';\nimport { useEvents } from '../../hooks/useEvents';\nimport { Event } from '../../types';\nimport { useEffect, useMemo } from 'react';\nimport { cn } from '../../utils/core/cn';\nimport { logger } from '../../utils/core/logger';\n\nexport interface EventSelectorProps {\n /** Placeholder text for the dropdown */\n placeholder?: string;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when an event changes, providing full event object */\n onEventChange?: (event: Event | null) => void;\n /** Show friendly message when no events available */\n showNoEventsMessage?: boolean;\n /** Show retry button on errors */\n showRetryButton?: boolean;\n /** Show event details in dropdown */\n showEventDetails?: boolean;\n /** Show indicator for next/upcoming events */\n showNextEventIndicator?: boolean;\n}\n\n/**\n * EventSelector component for selecting events with built-in access control\n * \n * This component provides secure event selection with:\n * - Database integration via rbac_event_app_roles table\n * - Auto-selection of next upcoming event by date\n * - Cross-device sync via Supabase user session metadata\n * - localStorage fallback for offline scenarios\n * - Comprehensive error handling and user feedback\n * \n * @component\n * @example\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"PACE\">\n * <EventSelector onEventChange={(event) => console.log(event)} />\n * </UnifiedAuthProvider>\n */\nexport function EventSelector({\n placeholder = \"Select an event\",\n className,\n onEventChange,\n showNoEventsMessage = true,\n showRetryButton = true,\n showEventDetails = true,\n showNextEventIndicator = true\n}: EventSelectorProps) {\n const { \n events, \n selectedEvent, \n isLoading, \n error, \n setSelectedEvent, \n refreshEvents,\n } = useEvents();\n\n logger.debug('EventSelector', 'Component render:', {\n eventsCount: events.length,\n events: events.map(e => ({ id: e.event_id, name: e.event_name })),\n selectedEvent: selectedEvent ? { id: selectedEvent.event_id, name: selectedEvent.event_name } : null,\n isLoading,\n error: error?.message\n });\n\n\n const handleValueChange = (eventId: string) => {\n const event = events.find((e) => (e.event_id || e.id) === eventId);\n \n if (event) {\n setSelectedEvent(event);\n if (onEventChange) {\n onEventChange(event);\n }\n }\n };\n\n const handleRetry = () => {\n refreshEvents();\n };\n\n // Helper function to check if an event is the next upcoming event\n const isNextEvent = (event: Event): boolean => {\n if (!event.event_date) return false;\n \n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const eventDate = new Date(event.event_date);\n \n return eventDate >= today;\n };\n\n // Helper function to format event date\n const formatEventDate = (dateString: string): string => {\n const date = new Date(dateString);\n const today = new Date();\n const tomorrow = new Date(today);\n tomorrow.setDate(tomorrow.getDate() + 1);\n \n // Normalize dates to compare only the date part (ignore time)\n const normalizeDate = (d: Date) => {\n const normalized = new Date(d);\n normalized.setHours(0, 0, 0, 0);\n return normalized;\n };\n \n const normalizedDate = normalizeDate(date);\n const normalizedToday = normalizeDate(today);\n const normalizedTomorrow = normalizeDate(tomorrow);\n \n \n if (normalizedDate.getTime() === normalizedToday.getTime()) {\n return 'Today';\n } else if (normalizedDate.getTime() === normalizedTomorrow.getTime()) {\n return 'Tomorrow';\n } else {\n return date.toLocaleDateString();\n }\n };\n\n // Compute sorted list: descending by event_date (newest first); events without date go last\n const sortedEvents = useMemo(() => {\n const getTime = (e: Event) => (e.event_date ? new Date(e.event_date).getTime() : Number.NEGATIVE_INFINITY);\n return [...events].sort((a, b) => getTime(b) - getTime(a));\n }, [events]);\n\n // Default to the next upcoming event if none selected, fallback to most recent past event\n // IMPORTANT: Only auto-select if there's no persisted event being restored\n // EventService handles all persistence internally - we don't check storage directly\n useEffect(() => {\n // Only auto-select if events are loaded, no event is selected, and not currently loading\n // EventService will have already loaded persisted event if one exists\n if (!selectedEvent && events.length > 0 && !isLoading) {\n // No event selected - safe to auto-select\n // EventService has already checked for persisted events during initialization\n autoSelectEvent();\n }\n \n function autoSelectEvent() {\n const today = new Date();\n const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();\n \n // Try to find next future event\n const next = [...events]\n .filter(e => e.event_date && new Date(e.event_date).getTime() >= startOfToday)\n .sort((a, b) => new Date(a.event_date as string).getTime() - new Date(b.event_date as string).getTime())[0];\n \n if (next) {\n setSelectedEvent(next);\n if (onEventChange) onEventChange(next);\n } else {\n // Fallback to most recent past event if no future events found\n const mostRecentPast = [...events]\n .filter(e => {\n if (!e.event_date) return false;\n const eventDate = new Date(e.event_date);\n const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();\n return startOfEventDate < startOfToday;\n })\n .sort((a, b) => new Date(b.event_date as string).getTime() - new Date(a.event_date as string).getTime())[0];\n \n if (mostRecentPast) {\n setSelectedEvent(mostRecentPast);\n if (onEventChange) onEventChange(mostRecentPast);\n }\n }\n }\n }, [events, selectedEvent, setSelectedEvent, onEventChange, isLoading]);\n\n // Loading state\n if (isLoading) {\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n <LoadingSpinner size=\"sm\" />\n <span className=\"text-sm text-muted-foreground\">Loading events...</span>\n </div>\n );\n }\n\n // Access error state\n if (error) {\n return (\n <div className={className}>\n <Alert variant=\"destructive\">\n <Lock className=\"h-4 w-4\" />\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{error.message}</span>\n {showRetryButton && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRetry}\n className=\"ml-2\"\n >\n <RefreshCw className=\"h-3 w-3 mr-1\" />\n Retry\n </Button>\n )}\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n\n // No events available state\n if (events.length === 0) {\n if (showNoEventsMessage) {\n return (\n <div className={className}>\n <Alert variant=\"inline\">\n <AlertCircle className=\"h-4 w-4 text-acc-700\" />\n <AlertDescription className=\"flex items-center justify-between\">\n <span>No events available.</span>\n {showRetryButton && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRetry}\n className=\"ml-2\"\n >\n <RefreshCw className=\"h-3 w-3 mr-1\" />\n Refresh\n </Button>\n )}\n </AlertDescription>\n </Alert>\n </div>\n );\n }\n return null;\n }\n\n // Normal selector state\n return (\n <Select \n value={selectedEvent ? (selectedEvent.event_id || selectedEvent.id) : ''}\n onValueChange={handleValueChange}\n className={className}\n >\n <SelectTrigger className=\"text-left\" variant=\"outline\">\n <SelectValue placeholder={placeholder}>\n {selectedEvent && (\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 flex-shrink-0\" />\n <span className=\"truncate\">{selectedEvent.event_name || selectedEvent.name}</span>\n {selectedEvent.event_date && (\n <span className=\"text-xs text-muted-foreground flex-shrink-0\">\n ({formatEventDate(selectedEvent.event_date)})\n </span>\n )}\n </div>\n )}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {sortedEvents\n .map((event) => {\n const isNext = isNextEvent(event);\n const isSelected = selectedEvent && (selectedEvent.event_id === event.event_id || selectedEvent.id === event.id);\n \n return (\n <SelectItem \n key={event.event_id || event.id}\n value={event.event_id || event.id}\n className=\"flex items-center justify-between\"\n >\n <div className=\"flex items-center gap-2 w-full\">\n {showNextEventIndicator && isNext && (\n <Star className=\"h-3 w-3 text-acc-500\" />\n )}\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className={isSelected ? \"font-semibold\" : \"\"}>\n {event.event_name || event.name}\n </span>\n {isSelected && (\n <span className=\"text-xs bg-primary text-primary-foreground px-1 rounded\">\n Current\n </span>\n )}\n </div>\n {showEventDetails && event.event_date && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Calendar className=\"h-3 w-3\" />\n <span>{formatEventDate(event.event_date)}</span>\n {showNextEventIndicator && isNext && (\n <span className=\"text-acc-600 font-medium\">\n (Next)\n </span>\n )}\n </div>\n )}\n {showEventDetails && event.event_venue && (\n <div className=\"text-xs text-muted-foreground\">\n 📍 {event.event_venue}\n </div>\n )}\n </div>\n </div>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n );\n}\n","/**\n * @file Password Change Form Component\n * @package @jmruthers/pace-core\n * @module Components/PasswordReset\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 18+ - 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\nexport interface PasswordChangeFormValues {\n newPassword: string;\n confirmPassword: string;\n}\n\nexport interface PasswordChangeFormProps {\n onSubmit: (values: PasswordChangeFormValues) => Promise<{ error?: any }>;\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: any) {\n setError(err?.message || 'An unexpected error occurred.');\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 * <div 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 * </div>\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 18+ - 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 } from '../PasswordReset/PasswordChangeForm';\nimport { Avatar, AvatarFallback, AvatarImage } from '../Avatar';\nimport { Button } from '../Button';\n\nexport interface UserMenuProps {\n user: User | null;\n onSignOut?: () => Promise<void>;\n onChangePassword?: (newPassword: string, confirmPassword: string) => Promise<{ error: any }>;\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 className=\"size-7\">\n <AvatarImage src={userInfo.avatarUrl} alt={userInfo.displayName} />\n <AvatarFallback>{userInfo.initial}</AvatarFallback>\n </Avatar>\n )}\n <span>{userInfo.displayName}</span>\n <ChevronDown className=\"h-4 w-4\" />\n </Button>\n </SelectTrigger>\n <SelectContent>\n <SelectLabel className=\"font-normal\">\n <div className=\"flex flex-col space-y-1\">\n <p className=\"font-medium\">{userInfo.displayName}</p>\n <p className=\"text-muted-foreground\">{userInfo.email}</p>\n </div>\n </SelectLabel>\n <SelectSeparator />\n <DialogTrigger asChild>\n <SelectItem value=\"change-password\">\n <KeyRound className=\"mr-2 h-4 w-4\" />\n <span>Change Password</span>\n </SelectItem>\n </DialogTrigger>\n <SelectItem value=\"sign-out\" onClick={handleSignOut}>\n <LogOut className=\"mr-2 h-4 w-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 <div className=\"relative inline-block text-left\">\n <button\n type=\"button\"\n disabled\n className=\"flex items-center space-x-2 px-3 py-2 text-sm font-medium text-muted-foreground bg-muted border border-input rounded-md\"\n >\n <div className=\"w-6 h-6 rounded-full bg-muted animate-pulse\" />\n <span className=\"truncate max-w-[150px]\">Loading...</span>\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n </button>\n <div role=\"status\" aria-label=\"Loading user menu\" aria-live=\"polite\" className=\"w-6 h-6 rounded-full bg-muted animate-pulse\" />\n </div>\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 18+ - 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 { Menu, ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/core/cn\";\nimport { NavigationMenuProps, NavigationItem } from \"./types\";\nimport { Button } from \"../Button\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../Select\";\nimport { useUnifiedAuth } from \"../../providers/UnifiedAuthProvider\";\nimport { useRBAC } from \"../../rbac/hooks/useRBAC\";\nimport { useResolvedScope } from \"../../rbac/hooks\";\nimport { usePermissions } from \"../../rbac/hooks/usePermissions\";\nimport type { Permission, AccessLevel as RBACAccessLevel } from \"../../rbac/types\";\nimport { logger } from \"../../utils/core/logger\";\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 * filterByPermissions={true}\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 filterByPermissions = true,\n ...props \n}, ref) => {\n const [expandedItems, setExpandedItems] = React.useState<Set<string>>(new Set());\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n\n // Get authentication context\n let authContext = null;\n try {\n authContext = useUnifiedAuth();\n } catch (error) {\n // NavigationMenu is being used outside of UnifiedAuthProvider\n logger.warn('NavigationMenu', 'useUnifiedAuth not available, running in unauthenticated mode');\n }\n\n // Get RBAC context for permission and role checks\n let rbacContext = null;\n try {\n rbacContext = useRBAC();\n } catch (error) {\n // RBAC not available - permission filtering will be disabled\n logger.warn('NavigationMenu', 'useRBAC not available, permission filtering disabled');\n }\n\n // Get event context state for checking readiness\n // Store the raw value to check if it's undefined (tests without event provider)\n const eventLoadingRaw = authContext?.eventLoading;\n const eventLoading = eventLoadingRaw ?? false;\n const selectedEvent = authContext?.selectedEvent || null;\n // Check org context readiness: use isContextReady if available, otherwise fall back to checking selectedOrganisation\n // This handles both production (with isContextReady) and test scenarios (without it)\n const orgContextReady = authContext?.isContextReady ?? (authContext?.selectedOrganisation?.id ? true : false);\n\n // Get resolved scope for permission checks\n // Note: Always call useResolvedScope (hooks must be called unconditionally)\n // When filterByPermissions is false, we'll simply ignore the resolved scope\n const { supabase } = authContext || {};\n const { selectedOrganisation } = authContext || {};\n const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({\n supabase: filterByPermissions ? (supabase || null) : null,\n selectedOrganisationId: filterByPermissions ? (selectedOrganisation?.id || null) : null,\n selectedEventId: filterByPermissions ? (selectedEvent?.event_id || null) : null\n });\n\n // Resolve appId when useResolvedScope fails but context is ready\n // This is needed because usePermissions requires appId to fetch permissions correctly\n const [resolvedAppId, setResolvedAppId] = React.useState<string | undefined>(undefined);\n React.useEffect(() => {\n // Only resolve appId if:\n // 1. useResolvedScope errored or returned null\n // 2. But we have organisation context ready\n // 3. And we have appName from authContext\n // 4. And we haven't resolved it yet\n if (\n !scopeLoading && \n !resolvedScope?.appId && \n selectedOrganisation?.id && \n authContext?.appName && \n authContext?.user?.id &&\n !resolvedAppId\n ) {\n // Resolve appId using the same method as useRBAC\n // Double-check user exists (TypeScript narrowing) and capture values\n if (!authContext.user || !authContext.appName) {\n return;\n }\n const userId = authContext.user.id;\n const appName = authContext.appName;\n import('../../rbac/api').then(({ resolveAppContext }) => {\n resolveAppContext({\n userId,\n appName\n }).then((result) => {\n if (result?.appId) {\n setResolvedAppId(result.appId);\n }\n }).catch((error) => {\n // Silently fail - usePermissions will handle it\n logger.debug('NavigationMenu', 'Failed to resolve appId', error);\n });\n });\n }\n }, [scopeLoading, resolvedScope?.appId, selectedOrganisation?.id, authContext?.appName, authContext?.user?.id, resolvedAppId]);\n\n // Build scope from resolvedScope if available, otherwise fall back to context values\n // This handles the case where useResolvedScope errored initially but context is now ready\n // IMPORTANT: We need appId for usePermissions to work correctly\n const effectiveScope = React.useMemo(() => {\n if (!scopeLoading && resolvedScope?.organisationId) {\n // Use resolved scope if available (includes appId)\n logger.warn('NavigationMenu', 'Using resolvedScope', {\n organisationId: resolvedScope.organisationId,\n eventId: resolvedScope.eventId,\n appId: resolvedScope.appId\n });\n return resolvedScope;\n } else if (!scopeLoading && selectedOrganisation?.id) {\n // Fall back to building scope from context if resolvedScope is null but context is ready\n // Use resolvedAppId if we've resolved it, otherwise undefined (usePermissions will try to resolve)\n const fallbackScope = {\n organisationId: selectedOrganisation.id,\n eventId: selectedEvent?.event_id || undefined,\n appId: resolvedAppId\n };\n logger.warn('NavigationMenu', 'Using fallback scope', {\n organisationId: fallbackScope.organisationId,\n eventId: fallbackScope.eventId,\n appId: fallbackScope.appId,\n resolvedAppId,\n hasResolvedScope: !!resolvedScope,\n scopeLoading\n });\n return fallbackScope;\n }\n logger.warn('NavigationMenu', 'effectiveScope is null', {\n scopeLoading,\n hasResolvedScope: !!resolvedScope,\n hasSelectedOrganisation: !!selectedOrganisation?.id\n });\n return null;\n }, [scopeLoading, resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id, resolvedAppId]);\n\n // Create a stable scope object that changes when effectiveScope changes\n // This ensures usePermissions detects scope changes and re-runs\n // We memoize it to prevent unnecessary re-renders while still triggering usePermissions when scope changes\n // IMPORTANT: Depend on effectiveScope itself (not just properties) to catch when appId changes\n const stableScope = React.useMemo(() => {\n if (effectiveScope?.organisationId) {\n const scope = {\n organisationId: effectiveScope.organisationId,\n eventId: effectiveScope.eventId,\n appId: effectiveScope.appId\n };\n // Debug logging to verify appId is preserved\n logger.warn('NavigationMenu', 'stableScope created from effectiveScope', {\n effectiveScopeAppId: effectiveScope.appId,\n stableScopeAppId: scope.appId,\n hasAppId: !!scope.appId,\n organisationId: scope.organisationId,\n eventId: scope.eventId\n });\n return scope;\n }\n // Return empty scope object (not null) so usePermissions can handle it\n return {\n organisationId: '',\n eventId: undefined,\n appId: undefined\n };\n }, [effectiveScope]);\n\n // Get permissions map for synchronous permission checks\n const userId = authContext?.user?.id || '';\n \n // Debug logging to understand why usePermissions returns empty map\n React.useEffect(() => {\n if (filterByPermissions && stableScope.organisationId) {\n logger.warn('NavigationMenu', 'usePermissions scope', {\n userId,\n scope: stableScope,\n hasOrganisationId: !!stableScope.organisationId,\n hasEventId: !!stableScope.eventId,\n hasAppId: !!stableScope.appId,\n organisationId: stableScope.organisationId,\n eventId: stableScope.eventId,\n appId: stableScope.appId\n });\n }\n }, [filterByPermissions, stableScope.organisationId, stableScope.eventId, stableScope.appId, userId]);\n \n const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading, error: permissionsError } = usePermissions(\n userId as any,\n stableScope as any\n );\n \n // Debug logging for permission map state\n React.useEffect(() => {\n if (filterByPermissions) {\n logger.warn('NavigationMenu', 'usePermissions result', {\n permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0,\n isLoading: permissionsLoading,\n error: permissionsError?.message,\n hasError: !!permissionsError,\n scope: stableScope\n });\n }\n }, [filterByPermissions, permissionMap, permissionsLoading, permissionsError, stableScope]);\n\n // NEW: Phase 2 - Enhanced Security Features\n // Filter navigation items based on permissions using RBAC hooks\n // Use ref to preserve previous filtered items during permission refetches (e.g., when event changes)\n const previousFilteredItemsRef = React.useRef<NavigationItem[]>([]);\n \n const filteredItems = React.useMemo(() => {\n // Security: If filtering is enabled but we're missing required context or still loading, show NO items\n // This prevents security risk of showing items before permissions are verified\n if (filterByPermissions) {\n // CRITICAL: Wait for BOTH organisation AND event context to be ready before checking permissions\n // This prevents the error \"No organisation or event context available\" when event context is still loading\n const isOrgContextReady = orgContextReady && selectedOrganisation?.id;\n // Event context is ready when not loading\n // If eventLoadingRaw is undefined (tests without event provider), consider it ready\n // Only wait for event context if we're actually loading events\n const isEventContextReady = eventLoadingRaw === undefined ? true : !eventLoading;\n \n // Check if we have valid context for permission checking\n // Use actual context values, not just resolvedScope, because resolvedScope might be null\n // if useResolvedScope errored initially but context is now ready\n const hasValidContext = isOrgContextReady && isEventContextReady;\n \n // If scope is still loading or we don't have valid context yet, show nothing\n // BUT: If scope errored but context is now ready, retry (don't block forever)\n const shouldWaitForScope = scopeLoading || (!hasValidContext);\n const shouldRetryAfterError = scopeError && hasValidContext && !scopeLoading;\n \n // During initial load or when scope/context is loading, show nothing\n if (!authContext || !rbacContext || (shouldWaitForScope && !shouldRetryAfterError)) {\n // Still loading - show nothing to prevent security risk\n // Note: We check both org and event context readiness to prevent premature permission checks\n // Exception: If scope errored but context is now ready, we'll retry below\n return [];\n }\n \n // If scope errored but context is now ready, we can proceed with permission checks\n // The resolvedScope might be null, but we'll use the actual context values\n // usePermissions will handle the scope resolution internally\n \n // During permission refetch (after initial load), preserve previous items if we have them\n // This prevents navigation from disappearing when switching events\n if (permissionsLoading) {\n // If we have previous items, keep showing them during refetch\n // This prevents the navigation from disappearing when event changes\n if (previousFilteredItemsRef.current.length > 0) {\n return previousFilteredItemsRef.current;\n }\n // Otherwise, show nothing during initial load\n return [];\n }\n \n // If there's an error or empty permission map after loading, show nothing\n // Security: Better to show nothing than risk showing unauthorized items\n if (permissionsError || !permissionMap || Object.keys(permissionMap).length === 0) {\n logger.warn('NavigationMenu', 'Permission map is empty or has error - showing no items for security', {\n permissionsError: permissionsError?.message,\n permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0\n });\n return [];\n }\n } else {\n // Filtering disabled - only filter out hidden items\n return (items || []).filter(item => !item.meta?.hidden);\n }\n \n // Helper function to derive page ID from href\n const getPageIdFromHref = (href?: string): string | null => {\n if (!href) return null;\n // Remove leading slash and any query params/hash\n const path = href.split('?')[0].split('#')[0].replace(/^\\//, '');\n return path || 'home';\n };\n \n // Helper function to check if item has permission to be shown\n const hasItemPermission = (item: NavigationItem): boolean => {\n // Check permissions if available\n if (item.permissions && item.permissions.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 const hasPermission = hasAnyPermission(permissions);\n if (!hasPermission) return false;\n }\n }\n \n // Check roles if available\n if (item.roles && item.roles.length > 0) {\n const hasRole = item.roles.some(role => {\n if (typeof role !== 'string') return true;\n \n // Map role strings to RBAC role checks\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 if (!hasRole) return false;\n }\n \n // Check access level if available\n if (item.accessLevel) {\n if (typeof item.accessLevel === 'string') {\n // Map access level string to RBAC access level\n const accessLevel = item.accessLevel.toLowerCase() as RBACAccessLevel;\n const userEventRole = rbacContext.eventAppRole;\n \n // If user is super admin, they have all access levels\n if (rbacContext.isSuperAdmin) {\n // Super admin has access\n } else {\n // Map eventAppRole to access level for comparison\n // eventAppRole: 'viewer' | 'participant' | 'planner' | 'event_admin'\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 // Check if user's access level meets the required access level\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 // NEW: Auto-check page permissions for items with href\n // Always check page permissions for items with href, even if they have explicit permissions/roles/accessLevel\n // This ensures that items are filtered out if the user doesn't have access to the page itself\n if (item.href) {\n const pageId = item.pageId || getPageIdFromHref(item.href);\n if (pageId) {\n // Check for read permission on the page\n const pagePermission: Permission = `read:page.${pageId}` as Permission;\n \n // Check permission map (super admin has access to everything via '*' key)\n // Only allow if permission is explicitly true (undefined/false means no access)\n const isSuperAdmin = permissionMap['*'] === true;\n const hasPagePermission = permissionMap[pagePermission] === true;\n const finalHasPermission = isSuperAdmin || hasPagePermission;\n \n if (!finalHasPermission) {\n if (auditLog) {\n logger.debug('NavigationMenu', `Filtering out navigation item \"${item.label}\" - no page permission:`, {\n itemId: item.id,\n href: item.href,\n pageId,\n permission: pagePermission,\n hasPermission: finalHasPermission,\n isSuperAdmin,\n permissionMapValue: permissionMap[pagePermission],\n permissionMapKeys: Object.keys(permissionMap).slice(0, 10) // Show first 10 keys for debugging\n });\n }\n return false;\n }\n }\n }\n \n return true;\n };\n \n // Helper function to filter items recursively (creates new objects to avoid mutations)\n const filterItem = (item: NavigationItem): NavigationItem | null => {\n // Check if item should be hidden\n if (item.meta?.hidden) return null;\n \n // Check if item has permission\n if (!hasItemPermission(item)) return null;\n \n // Recursively filter children if present\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 parent has no accessible children, hide the parent too (unless it has its own href)\n if (filteredChildren.length === 0 && !item.href) {\n return null;\n }\n }\n \n // Return filtered item (with filtered children if applicable)\n return {\n ...item,\n children: filteredChildren\n };\n };\n \n // Filter items based on permissions - only show items with explicit permission\n // Security: No fallback - if items don't have permission, they are hidden\n const filtered = (items || [])\n .map(item => filterItem(item))\n .filter((item): item is NavigationItem => item !== null);\n \n // Update the ref with the new filtered items so we can preserve them during refetches\n previousFilteredItemsRef.current = filtered;\n \n return filtered;\n }, [\n items, \n filterByPermissions, \n authContext, \n rbacContext, \n permissionMap, \n hasAnyPermission, \n scopeLoading, \n scopeError,\n permissionsLoading,\n resolvedScope,\n effectiveScope,\n auditLog,\n // Add event context state to dependencies so we re-check permissions when event context becomes available\n eventLoadingRaw,\n eventLoading,\n selectedEvent,\n orgContextReady,\n selectedOrganisation?.id\n ]);\n\n // Log navigation access attempts for debugging\n React.useEffect(() => {\n if (auditLog && authContext) {\n // Find the current navigation item to log its actual permissions\n const currentItem = items?.find(item => item.href === currentPath || item.id === 'navigation-menu');\n logger.debug('NavigationMenu', 'Navigation access attempt:', {\n itemId: currentItem?.id || 'navigation-menu',\n label: currentItem?.label || 'Navigation Menu',\n href: currentPath,\n permissions: currentItem?.permissions || null,\n roles: currentItem?.roles || null,\n accessLevel: currentItem?.accessLevel || null,\n timestamp: new Date().toISOString()\n });\n }\n }, [auditLog, authContext, currentPath, items]);\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\n if (auditLog) {\n logger.debug('NavigationMenu', 'Navigation access attempt:', {\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 \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 const isItemVisible = filteredItems.some(filtered => filtered.id === item.id);\n \n // Check permissions if the item requires them using RBAC hooks\n let hasPermission = true; // Default to true if no permission requirements\n \n if (item.permissions && item.permissions.length > 0 && rbacContext && hasAnyPermission) {\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 (!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 (!hasPermission) {\n // Handle access denied\n if (onNavigationAccessDenied) {\n onNavigationAccessDenied(item.id, 'Insufficient permissions');\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.id, '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 (item.isActive !== undefined) return item.isActive;\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 * @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, 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 * - 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 * <div className=\"flex gap-2\">\n * <Button variant=\"outline\">Export</Button>\n * <Button>New Item</Button>\n * </div>\n * }\n * user={currentUser}\n * onSignOut={handleSignOut}\n * />\n * \n * // Header without event selector\n * <Header\n * logoUrl=\"/logo.svg\"\n * logoHref=\"/dashboard\"\n * showEventSelector={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 18+ - Component framework\n * - Tailwind CSS - Styling\n * - NavigationMenu component\n * - UserMenu component\n * - EventSelector component\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 { EventSelector } from '../EventSelector';\nimport { UserMenu } from '../UserMenu';\nimport { NavigationMenu } from '../NavigationMenu';\nimport type { NavigationItem } from '../NavigationMenu';\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: any }>;\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 event selector */\n showEventSelector?: 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 * <div className=\"flex items-center gap-2\">\n * <Button variant=\"outline\" size=\"sm\">Export</Button>\n * <Button size=\"sm\">New Item</Button>\n * </div>\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 * showEventSelector={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 */\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 showEventSelector = true,\n showUserMenu = true,\n currentPath,\n onNavigate,\n logoHref\n}: HeaderProps) {\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_auto_1fr_auto] gap-4 h-full items-center\">\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=\"h-8 w-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=\"h-8 w-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 />\n )}\n \n\n {/* Right side: Event Selector, Actions, and User Menu */}\n\n {/* Event Selector */}\n {showEventSelector ? (\n <EventSelector \n placeholder=\"Select event\" \n className=\"justify-self-end w-96\" \n data-testid=\"event-selector\" \n />\n ) : (\n <del className=\"justify-self-end invisible\">Event Selector N/A</del>\n )}\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 * <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-8\">\n * <div>\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 * </div>\n * <div>\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 * </div>\n * <div>\n * <h3 className=\"font-semibold mb-2\">Follow Us</h3>\n * <div 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 * </div>\n * </div>\n * </div>\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 18+ - Component framework\n * - Tailwind CSS - Styling\n */\nimport React from 'react';\nimport { cn } from '../../utils/core/cn';\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 * <div>Custom footer content</div>\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 18+ - 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/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport { useCan, useResolvedScope } from '../../rbac/hooks';\nimport { createScopeFromEvent } from '../../rbac/utils/eventContext';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { isSuperAdmin } from '../../rbac/api';\nimport { logger } from '../../utils/core/logger';\nimport type { Permission, Scope } 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/types';\n// Define Operation type locally since old RBAC types are removed\ntype Operation = 'read' | 'create' | 'update' | 'delete' | 'manage';\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 event selector in the header */\n showEventSelector?: 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 /** Enable permission-based navigation filtering */\n filterNavigationByPermissions?: boolean;\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 * // Navigation filtering works independently - no need for enforcePermissions\n * filterNavigationByPermissions={true}\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 showEventSelector,\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 filterNavigationByPermissions = false,\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 } = useUnifiedAuth();\n const { selectedOrganisation } = useOrganisations();\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 } = useResolvedScope({\n supabase: supabase || null,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n \n // Build scope from resolved values\n const scope = useMemo<Scope>(() => {\n if (!resolvedScope?.organisationId) {\n return {\n organisationId: selectedOrganisation?.id || '',\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n }\n return resolvedScope;\n }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id]);\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 return pathSegments[0] || 'home';\n }, [location.pathname, pageIdMapping]);\n\n // Build permission string in format: operation:page.pageId\n const currentPermission = useMemo<Permission>(() => {\n if (!enforcePermissions) {\n return 'read:page.home' 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 const [isSuperAdminUser, setIsSuperAdminUser] = useState<boolean>(false);\n const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState<boolean>(false);\n\n useEffect(() => {\n const checkSuperAdminStatus = async () => {\n if (!user?.id) {\n setIsSuperAdminUser(false);\n setIsCheckingSuperAdmin(false);\n return;\n }\n\n setIsCheckingSuperAdmin(true);\n try {\n const superAdminStatus = await isSuperAdmin(user.id);\n setIsSuperAdminUser(superAdminStatus);\n } catch (error) {\n logger.error('PaceAppLayout', 'Error checking super admin status', { userId: user?.id, error });\n setIsSuperAdminUser(false);\n } finally {\n setIsCheckingSuperAdmin(false);\n }\n };\n\n checkSuperAdminStatus();\n }, [user?.id]);\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 const { can: canFromHook, isLoading: isCheckingPermission, error: permissionError } = useCan(\n user?.id || '',\n scope,\n currentPermission,\n currentPageId,\n true // useCache\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 const can = isSuperAdminUser ? true : canFromHook;\n const hasPermission = enforcePermissions ? can : true;\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 // Wait for both super admin check and permission check to complete\n if (isCheckingSuperAdmin || isCheckingPermission) {\n return;\n }\n\n // NEW: Phase 1 - Enhanced Security Features\n // Handle strict mode violations - skip for super admins\n if (strictMode && !isSuperAdminUser && !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: isSuperAdminUser,\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 (!isSuperAdminUser && !can && onPageAccessDenied) {\n onPageAccessDenied(currentPageId, currentRoutePermission);\n }\n }, [enforcePermissions, can, isCheckingPermission, isCheckingSuperAdmin, isSuperAdminUser, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);\n\n // Filter navigation items based on permissions\n // This works independently of route enforcement - navigation filtering doesn't require enforcePermissions\n const [filteredMenuItems, setFilteredMenuItems] = useState<NavigationItem[]>(baseMenuItems);\n\n useEffect(() => {\n // Allow navigation filtering without route enforcement\n if (!filterNavigationByPermissions) {\n setFilteredMenuItems(baseMenuItems);\n return;\n }\n\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 // Check if organisation context is available\n const scope = {\n organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\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 } = await import('../../rbac/api');\n const isSuper = await isSuperAdmin(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 // If no organisation context yet, show all items until context is ready\n // This prevents navigation from being empty while context loads\n if (!scope.organisationId) {\n if (isMounted) {\n setFilteredMenuItems(baseMenuItems);\n }\n return;\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 try {\n const { getPermissionMap } = await import('../../rbac/api');\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope,\n });\n\n // Filter items using the permission map (synchronous, no rate limit issues)\n const filtered = baseMenuItems.map((item) => {\n if (!item.href) return { item, hasAccess: true };\n \n const pageId = pageIdMapping[item.href] || item.href.slice(1) || 'home';\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 return { item, hasAccess };\n });\n\n if (!isMounted) return;\n\n const accessibleItems = filtered\n .filter(({ hasAccess }) => hasAccess)\n .map(({ item }) => item);\n\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, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id, user?.user_metadata, user?.app_metadata]);\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/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 await signOut();\n };\n\n const handleChangePassword = async (newPassword: string) => {\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 }\n // The form will handle closing the modal on success\n return result || { error: null };\n };\n\n // Show loading state while checking permissions or super admin status\n // Keep loading active until BOTH checks complete to prevent exposing protected content\n // This ensures we don't render the main layout when permission check failed but super admin check is pending\n if (enforcePermissions && (isCheckingSuperAdmin || 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 h-8 w-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 BOTH checks are complete)\n // Super admins bypass all permission checks, so don't show errors for them\n if (enforcePermissions && permissionError && !isSuperAdminUser) {\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 if (enforcePermissions && hasPermission === false && !isCheckingSuperAdmin && !isSuperAdminUser) {\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 showEventSelector={showEventSelector}\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 18+ - 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\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 = '/user-dashboard',\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 logger.debug('PaceLoginPage', 'Could not restore persisted event (service may not be ready):', error);\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 logger.debug('PaceLoginPage', 'No pages configured for app:', appName);\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: orgData } = 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 .single();\n\n if (!orgData) {\n logger.debug('PaceLoginPage', 'User has no organisation access');\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: orgData.organisation_id,\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 logger.debug('PaceLoginPage', 'Permission check for page:', { pageName: page.page_name, hasPermission, error: permError });\n\n if (!permError && hasPermission === true) {\n hasAnyAccess = true;\n break;\n }\n }\n\n if (hasAnyAccess) {\n logger.debug('PaceLoginPage', 'User has access to app');\n setIsCheckingAccess(false);\n navigate(onSuccessRedirectPath, { replace: true });\n return;\n }\n\n // No access - deny\n logger.debug('PaceLoginPage', 'Access denied - no permissions');\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\nimport React from 'react';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\n\nexport interface SessionRestorationLoaderProps {\n /** Customise the status message displayed under the spinner */\n message?: string;\n}\n\nexport const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> = ({\n message = 'Restoring session...'\n}) => {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100%',\n gap: '1rem',\n textAlign: 'center',\n padding: '1rem',\n background: 'var(--background, transparent)'\n }}\n >\n <LoadingSpinner size=\"lg\" />\n <div\n style={{\n fontSize: '0.95rem',\n color: 'var(--muted-foreground, #6b7280)'\n }}\n >\n {message}\n </div>\n </div>\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 } 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';\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 * Whether super admins can bypass event requirement.\n * Note: This feature requires additional RBAC setup. For simple bypass, set requireEvent={false} instead.\n * @default false\n * @deprecated Use requireEvent={false} for routes that don't need events\n */\n allowSuperAdminBypass?: 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 = true,\n allowSuperAdminBypass = false,\n noEventsFallback,\n loadingFallback,\n loginPath = '/login'\n}: ProtectedRouteProps) {\n const { isAuthenticated, authLoading } = useUnifiedAuth();\n const { selectedEvent, events, isLoading: eventLoading } = useEvents();\n const sessionRestoration = useSessionRestoration();\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 if (authLoading && !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 if (!isAuthenticated) {\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 }\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 logger.debug('ProtectedRoute', 'Events available but none selected - allowing render so selector is visible');\n return <Outlet />;\n }\n\n // Event is selected - allow rendering\n return <Outlet />;\n}\n\n","/**\n * @file Error Boundary Component\n * @package @jmruthers/pace-core\n * @module Components/ErrorBoundary\n * @since 0.1.0\n *\n * A comprehensive error boundary component that catches JavaScript errors in child components\n * and provides fallback UI with retry functionality and error reporting.\n *\n * Features:\n * - Catches JavaScript errors in component tree\n * - Custom fallback UI with retry functionality\n * - Error reporting and logging\n * - Performance monitoring integration\n * - Retry mechanism with configurable attempts\n * - Development mode error details\n * - Accessibility compliant error display\n * - Component-specific error tracking\n * - Error ID generation for tracking\n *\n * @example\n * ```tsx\n * // Basic error boundary\n * <ErrorBoundary>\n * <MyComponent />\n * </ErrorBoundary>\n * \n * // Error boundary with custom fallback\n * <ErrorBoundary\n * componentName=\"UserProfile\"\n * fallback={<div>Something went wrong loading the profile.</div>}\n * onError={(error, errorInfo, errorId) => {\n * console.log('Error caught:', errorId, error);\n * }}\n * >\n * <UserProfile />\n * </ErrorBoundary>\n * \n * // Error boundary with retry functionality\n * <ErrorBoundary\n * componentName=\"DataTable\"\n * maxRetries={3}\n * enableRetry={true}\n * enableReporting={true}\n * onError={(error, errorInfo, errorId) => {\n * // Send to error reporting service\n * errorReportingService.report({ error, errorInfo, errorId });\n * }}\n * >\n * <DataTable data={data} />\n * </ErrorBoundary>\n * \n * // Wrapping multiple components\n * <ErrorBoundary componentName=\"App\">\n * <Header />\n * <ErrorBoundary componentName=\"MainContent\">\n * <MainContent />\n * </ErrorBoundary>\n * <Footer />\n * </ErrorBoundary>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA role=\"alert\" for error announcements\n * - Screen reader friendly error messages\n * - Keyboard accessible retry buttons\n * - High contrast error styling\n * - Clear error identification\n *\n * @performance\n * - Efficient error state management\n * - Performance monitoring integration\n * - Minimal impact on normal rendering\n * - Configurable error reporting\n *\n * @dependencies\n * - React 18+ - Component lifecycle\n * - Performance monitoring utilities\n * - Tailwind CSS - Styling\n */\n\nimport React, { Component, ReactNode } from 'react';\nimport { performanceBudgetMonitor } from '../../utils/performance/performanceBudgets';\nimport { logger } from '../../utils/core/logger';\n\n/**\n * State interface for the ErrorBoundary component\n * @public\n */\nexport interface ErrorBoundaryState {\n /** Whether an error has been caught */\n hasError: boolean;\n /** The error that was caught */\n error?: Error;\n /** Additional error information from React */\n errorInfo?: React.ErrorInfo;\n /** Unique identifier for the error */\n errorId?: string;\n /** Number of retry attempts made */\n retryCount: number;\n}\n\n/**\n * Props interface for the ErrorBoundary component\n * @public\n */\nexport interface ErrorBoundaryProps {\n /** Child components to wrap with error boundary */\n children: ReactNode;\n /** Name of the component for error reporting */\n componentName?: string;\n /** Custom fallback UI to display when error occurs */\n fallback?: ReactNode;\n /** Callback function called when an error is caught */\n onError?: (error: Error, errorInfo: React.ErrorInfo, errorId: string) => void;\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Whether to enable retry functionality */\n enableRetry?: boolean;\n /** Whether to enable error reporting */\n enableReporting?: boolean;\n}\n\n/**\n * ErrorBoundary component\n * Catches JavaScript errors in child components and provides fallback UI\n * \n * @example\n * ```tsx\n * <ErrorBoundary\n * componentName=\"MyComponent\"\n * maxRetries={3}\n * onError={(error, errorInfo, errorId) => {\n * console.log('Error caught:', errorId);\n * }}\n * >\n * <MyComponent />\n * </ErrorBoundary>\n * ```\n */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n private retryTimeoutId: NodeJS.Timeout | null = null;\n\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { \n hasError: false, \n retryCount: 0 \n };\n }\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n const errorId = `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n return { \n hasError: true, \n error,\n errorId \n };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n const { componentName = 'Unknown Component', onError, enableReporting = true } = this.props;\n const errorId = this.state.errorId!;\n \n this.setState({ errorInfo });\n \n // Enhanced logging with component name and error ID\n logger.error('ErrorBoundary', `[${componentName}] Caught error ${errorId}:`, error, errorInfo);\n \n // Performance monitoring - track error occurrence\n performanceBudgetMonitor.measure('ERROR_BOUNDARY_TRIGGER', 1, {\n componentName,\n errorId,\n errorMessage: error.message,\n stack: error.stack?.substring(0, 200), // Truncated stack trace\n });\n\n // Report error if enabled\n if (enableReporting) {\n this.reportError(errorId, componentName);\n }\n \n // Call custom error handler if provided\n if (onError) {\n onError(error, errorInfo, errorId);\n }\n }\n\n private reportError = (errorId: string, componentName: string) => {\n // In production, this would send to error reporting service\n if (import.meta.env.MODE === 'production') {\n // Example: Send to error reporting service\n // errorReportingService.report({ error, errorInfo, errorId, componentName });\n logger.warn('ErrorBoundary', 'Error reporting would be triggered in production:', { errorId, componentName });\n }\n };\n\n private handleRetry = () => {\n const { maxRetries = 3 } = this.props;\n const { retryCount } = this.state;\n\n if (retryCount < maxRetries) {\n logger.debug('ErrorBoundary', `Retrying component render (attempt ${retryCount + 1}/${maxRetries})`);\n \n this.setState(prevState => ({\n hasError: false,\n error: undefined,\n errorInfo: undefined,\n errorId: undefined,\n retryCount: prevState.retryCount + 1\n }));\n }\n };\n\n componentWillUnmount() {\n if (this.retryTimeoutId) {\n clearTimeout(this.retryTimeoutId);\n }\n }\n\n render() {\n if (this.state.hasError) {\n const { \n componentName = 'Component', \n fallback, \n enableRetry = true, \n maxRetries = 3 \n } = this.props;\n const { retryCount, errorId } = this.state;\n\n // Use custom fallback if provided\n if (fallback) {\n return fallback;\n }\n\n // Enhanced error UI with retry functionality\n return (\n <div \n role=\"alert\" \n className=\"p-6 bg-destructive/10 border border-destructive/20 rounded-lg\"\n data-error-boundary={errorId}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-shrink-0\">\n <svg className=\"w-5 h-5 text-destructive\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-destructive\">\n Error in {componentName}\n </h3>\n <p className=\"text-destructive/80\">\n {this.state.error?.message || 'An unexpected error occurred.'}\n </p>\n \n {enableRetry && retryCount < maxRetries && (\n <div className=\"flex gap-3 mb-4\">\n <button\n onClick={this.handleRetry}\n className=\"px-4 py-2 bg-destructive text-destructive-foreground rounded-md hover:bg-destructive/90 transition-colors text-sm font-medium\"\n >\n Retry ({retryCount + 1}/{maxRetries})\n </button>\n <button\n onClick={() => window.location.reload()}\n className=\"px-4 py-2 bg-sec-600 text-main-50 rounded-md hover:bg-sec-700 transition-colors text-sm font-medium\"\n >\n Reload Page\n </button>\n </div>\n )}\n\n {retryCount >= maxRetries && (\n <div className=\"mb-4 p-3 bg-acc-50 border border-acc-200 rounded-md\">\n <p className=\"text-acc-800\">\n Maximum retry attempts reached. Please reload the page or contact support.\n </p>\n <button\n onClick={() => window.location.reload()}\n className=\"mt-2 px-3 py-1 bg-acc-600 text-main-50 rounded text-sm hover:bg-acc-700\"\n >\n Reload Page\n </button>\n </div>\n )}\n\n {import.meta.env.MODE === 'development' && this.state.error && (\n <details className=\"text-sm text-destructive/70\">\n <summary className=\"cursor-pointer font-medium mb-2\">\n Error Details (Development)\n </summary>\n <div className=\"bg-destructive/5 p-3 rounded border\">\n <p className=\"font-mono\">Error ID: {errorId}</p>\n <pre className=\"whitespace-pre-wrap text-xs overflow-auto max-h-32\">\n {this.state.error.toString()}\n {this.state.errorInfo?.componentStack}\n </pre>\n </div>\n </details>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\nexport default ErrorBoundary;\n","/**\n * @file Organisation Selector Component\n * @package @jmruthers/pace-core\n * @module Components/OrganisationSelector\n * @since 0.4.0\n *\n * A secure organisation selector component that allows users to switch between organisations\n * they have access to. Includes role display and security validation.\n *\n * Features:\n * - Secure organisation switching with validation\n * - Role display for each organisation\n * - Real-time organisation validation\n * - Accessible dropdown interface\n * - Error handling for security violations\n * - Loading states and feedback\n * - Integration with OrganisationProvider\n *\n * @example\n * ```tsx\n * // Basic organisation selector\n * <OrganisationSelector \n * onOrganisationChange={(org) => console.log('Switched to:', org.display_name)}\n * />\n * \n * // Compact version for header\n * <OrganisationSelector \n * className=\"w-48\" \n * compact={true}\n * showRole={true}\n * />\n * \n * // With custom placeholder\n * <OrganisationSelector \n * placeholder=\"Choose organisation...\"\n * showNoOrganisationsMessage={true}\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 * - Validates user access to organisations\n * - Prevents switching to unauthorised organisations\n * - Error handling for security violations\n * - Real-time access validation\n * - Secure organisation data handling\n */\n\nimport React, { useState, useCallback } from 'react';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select';\nimport { Alert, AlertDescription } from '../Alert/Alert';\nimport { Button } from '../Button/Button';\nimport { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';\nimport { RefreshCw, AlertCircle, Building2, Shield } from 'lucide-react';\nimport { useOrganisations } from '../../providers/OrganisationProvider';\nimport type { Organisation } from '../../types/organisation';\nimport { logger } from '../../utils/core/logger';\n\nexport interface OrganisationSelectorProps {\n /** Placeholder text for the dropdown */\n placeholder?: string;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when organisation changes, providing full organisation object */\n onOrganisationChange?: (org: Organisation) => void;\n /** Show friendly message when no organisations available */\n showNoOrganisationsMessage?: boolean;\n /** Show retry button on errors */\n showRetryButton?: boolean;\n /** Show user's role in each organisation */\n showRole?: boolean;\n /** Compact display mode */\n compact?: boolean;\n /** Disabled state */\n disabled?: boolean;\n}\n\n/**\n * OrganisationSelector component for secure organisation switching\n * \n * This component provides secure organisation selection with:\n * - User membership validation\n * - Role-based access display\n * - Security error handling\n * - Real-time organisation switching\n * - Accessible interface design\n * \n * Security: Only shows organisations the user has valid access to\n */\nexport function OrganisationSelector({\n placeholder = \"Select organisation\",\n className,\n onOrganisationChange,\n showNoOrganisationsMessage = true,\n showRetryButton = true,\n showRole = false,\n compact = false,\n disabled = false\n}: OrganisationSelectorProps) {\n const [isLoading, setIsLoading] = useState(false);\n const [switchError, setSwitchError] = useState<string | null>(null);\n \n const { \n organisations, \n selectedOrganisation, \n isLoading: orgLoading,\n error: orgError,\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations\n } = useOrganisations();\n\n\n const handleOrganisationChange = useCallback(async (orgId: string) => {\n if (disabled || isLoading) return;\n \n setSwitchError(null);\n setIsLoading(true);\n \n try {\n // Validate access before attempting switch\n if (!validateOrganisationAccess(orgId)) {\n throw new Error('You do not have access to this organisation');\n }\n \n await switchOrganisation(orgId);\n \n const newOrganisation = organisations.find(org => org.id === orgId);\n if (newOrganisation && onOrganisationChange) {\n onOrganisationChange(newOrganisation);\n }\n \n logger.debug('OrganisationSelector', 'Successfully switched to organisation:', orgId);\n } catch (error) {\n logger.error('OrganisationSelector', 'Failed to switch organisation:', error);\n setSwitchError(error instanceof Error ? error.message : 'Failed to switch organisation');\n } finally {\n setIsLoading(false);\n }\n }, [\n disabled, \n isLoading, \n validateOrganisationAccess, \n switchOrganisation, \n organisations, \n onOrganisationChange\n ]);\n\n const handleRetry = useCallback(async () => {\n setIsLoading(true);\n setSwitchError(null);\n try {\n await refreshOrganisations();\n } catch (error) {\n logger.error('OrganisationSelector', 'Failed to refresh organisations:', error);\n setSwitchError('Failed to refresh organisations');\n } finally {\n setIsLoading(false);\n }\n }, [refreshOrganisations]);\n\n // Loading state\n if (orgLoading) {\n return (\n <div className={`flex items-center gap-2 ${className}`}>\n <LoadingSpinner size=\"sm\" />\n <span className=\"text-sm text-muted-foreground\">\n {compact ? \"Loading...\" : \"Loading organisations...\"}\n </span>\n </div>\n );\n }\n\n // Error state\n if (orgError) {\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert variant=\"destructive\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertDescription>\n Failed to load organisations: {orgError.message}\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={`h-4 w-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Retry\n </Button>\n )}\n </div>\n );\n }\n\n // No organisations available\n if (organisations.length === 0) {\n if (showNoOrganisationsMessage) {\n return (\n <div className={`space-y-2 ${className}`}>\n <Alert>\n <Building2 className=\"h-4 w-4\" />\n <AlertDescription>\n No organisations available. Please contact your administrator to be added to an organisation.\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={`h-4 w-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />\n Check Again\n </Button>\n )}\n </div>\n );\n }\n return null;\n }\n\n // Switch error display\n const switchErrorDisplay = switchError && (\n <Alert variant=\"destructive\" className=\"mt-2\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertDescription>{switchError}</AlertDescription>\n </Alert>\n );\n\n // Normal selector state - with null check\n return (\n <div className={`space-y-2 ${className}`}>\n <Select \n value={selectedOrganisation?.id || ''}\n onValueChange={handleOrganisationChange}\n disabled={disabled || isLoading || !selectedOrganisation}\n >\n <SelectTrigger className={`${isLoading ? 'opacity-50' : ''}`}>\n <div className=\"flex items-center gap-2\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Building2 className=\"h-4 w-4 text-muted-foreground\" />\n )}\n <SelectValue placeholder={placeholder} />\n </div>\n </SelectTrigger>\n <SelectContent>\n {organisations.map((org) => {\n const userRole = getUserRole(org.id);\n const hasAccess = validateOrganisationAccess(org.id);\n \n return (\n <SelectItem \n key={org.id} \n value={org.id}\n disabled={!hasAccess}\n className={!hasAccess ? 'opacity-50' : ''}\n >\n <div className=\"flex items-center justify-between w-full\">\n <div className=\"flex items-center gap-2\">\n <Building2 className=\"h-4 w-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 {showRole && (\n <div className=\"flex items-center gap-1 ml-4\">\n <Shield className=\"h-3 w-3 text-muted-foreground\" />\n <span className=\"text-xs text-muted-foreground capitalize\">\n {userRole?.replace('_', ' ') || 'No Role'}\n </span>\n </div>\n )}\n </div>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n \n {switchErrorDisplay}\n </div>\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 } from '../utils/storage/helpers';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useFileReference');\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 urlRefreshIntervalRef = useRef<NodeJS.Timeout | 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 (!fileReference || fileReference.is_public) {\n // Only refresh private files (signed URLs expire)\n if (urlRefreshIntervalRef.current) {\n clearInterval(urlRefreshIntervalRef.current);\n urlRefreshIntervalRef.current = null;\n }\n return;\n }\n\n // Refresh signed URL 5 minutes before expiration (55 minutes into the 1-hour expiry)\n urlRefreshIntervalRef.current = setInterval(() => {\n loadFileUrl();\n }, 55 * 60 * 1000); // 55 minutes\n\n return () => {\n if (urlRefreshIntervalRef.current) {\n clearInterval(urlRefreshIntervalRef.current);\n urlRefreshIntervalRef.current = null;\n }\n };\n }, [fileReference, loadFileUrl]);\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 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 };\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\n const urlMap = new Map<string, string>();\n \n for (const fileRef of files) {\n try {\n let url: string | null = null;\n\n if (fileRef.is_public) {\n // Public files: generate public URL\n url = getPublicUrl(supabase, fileRef.file_path, true);\n } else {\n // Private files: generate signed URL\n const signedUrlResult = await getSignedUrl(supabase, fileRef.file_path, {\n appName: 'file-reference',\n orgId: organisation_id,\n expiresIn: 3600\n });\n url = signedUrlResult?.url || null;\n }\n\n if (url) {\n urlMap.set(fileRef.id, url);\n }\n } catch (err) {\n log.error(`Failed to load URL for file ${fileRef.id}:`, err);\n }\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\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\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","// File Upload Component\n// Provides a file upload interface using the file reference system\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';\n\nexport interface FileUploadProps {\n supabase: SupabaseClient;\n table_name: string;\n record_id: string;\n organisation_id: string;\n app_id?: string; // Optional - will be resolved from app name if not provided\n category: FileCategory;\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 app_id,\n category,\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 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 const result = await uploadFile({\n table_name,\n record_id,\n organisation_id,\n app_id: resolvedAppId,\n category,\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, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);\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 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 >\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 />\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 className=\"absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-500\"></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 className=\"animate-spin rounded-full h-5 w-5 border-b-2 border-main-500\"></div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n \n {appIdError && (\n <div className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\">\n {appIdError}\n </div>\n )}\n {error && (\n <div className=\"p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600\">\n {error}\n </div>\n )}\n </div>\n );\n}\n\n\n","import React, { useState, useEffect, useCallback, useRef, useContext, useMemo } from '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 { logger } from '../../utils/core/logger';\n\n/**\n * Size classes for fallback display\n */\nconst fallbackSizeClasses = {\n xs: 'h-4 w-4 text-xs',\n sm: 'h-6 w-6 text-sm',\n md: 'h-8 w-8 text-base',\n lg: 'h-12 w-12 text-lg',\n xl: 'h-16 w-16 text-xl',\n '2xl': 'h-20 w-20 text-2xl'\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 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 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 /** Size variant for fallback display (only applies when showFallback is true) */\n fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\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 children?: React.ReactNode;\n onDelete?: () => Promise<void>;\n clearError?: () => void;\n organisation_id: string;\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 fallbackSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n}\n\nfunction FileDisplayContent({\n isLoading,\n error,\n fileUrl,\n fileReference,\n fileReferences,\n fileUrls,\n fileCount,\n category,\n displayOnly,\n showDelete,\n className,\n children,\n onDelete,\n clearError,\n organisation_id,\n loadingComponent: LoadingComponent,\n errorComponent: ErrorComponent,\n showFallback = false,\n generateFallbackText = defaultGenerateFallbackText,\n fallbackText,\n fallbackSize = 'md'\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\n // Compute fallback text\n const computedFallbackText = useMemo(() => {\n if (fallbackText) return fallbackText;\n const fileName = fileReference?.file_metadata?.fileName;\n return generateFallbackText(fileName);\n }, [fallbackText, fileReference, generateFallbackText]);\n\n // Compute fallback classes\n const fallbackClasses = useMemo(() => {\n const sizeClass = fallbackSizeClasses[fallbackSize];\n const baseClasses = 'flex items-center justify-center bg-sec-100 text-sec-600 font-semibold rounded';\n return `${baseClasses} ${sizeClass} ${className}`.trim();\n }, [fallbackSize, className]);\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 if (onDelete) {\n await onDelete();\n }\n setImageError(false);\n };\n\n const handleImageError = (e?: React.SyntheticEvent<HTMLImageElement>) => {\n setImageError(true);\n \n // If fallback is enabled, show fallback UI when image fails to load\n if (showFallback && e) {\n const target = e.target as HTMLImageElement;\n target.style.display = 'none';\n \n // Check if fallback already exists\n if (target.nextSibling && (target.nextSibling as HTMLElement).className.includes('bg-sec-100')) {\n return; // Fallback already shown\n }\n \n // Create fallback element\n const fallback = document.createElement('div');\n fallback.className = fallbackClasses;\n fallback.textContent = computedFallbackText;\n fallback.title = fileReference?.file_metadata?.fileName || 'File';\n \n // Insert fallback after the image\n target.parentNode?.insertBefore(fallback, target.nextSibling);\n }\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 <div className={fallbackClasses} title=\"File unavailable\">\n {computedFallbackText}\n </div>\n );\n }\n \n return (\n <div className={`p-4 bg-acc-50 border border-acc-200 rounded-lg ${className}`}>\n <div className=\"text-acc-600\">\n Error loading file: {error instanceof Error ? error.message : String(error)}\n </div>\n {clearError && (\n <button\n onClick={clearError}\n className=\"mt-2 text-sm text-acc-700 hover:text-acc-800 underline\"\n >\n Try again\n </button>\n )}\n </div>\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 <div className={fallbackClasses} title=\"No file\">\n {computedFallbackText}\n {children}\n </div>\n );\n }\n \n return (\n <div className={`text-sec-500 text-center p-4 ${className}`}>\n No files found\n {children}\n </div>\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 <div className={fallbackClasses} title=\"Loading...\">\n {computedFallbackText}\n {children}\n </div>\n );\n }\n\n if (isLoading) {\n if (LoadingComponent) {\n return <LoadingComponent />;\n }\n return (\n <div className={`flex items-center justify-center p-4 ${className}`}>\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-500\"></div>\n </div>\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 if (displayOnly && isImage && !showDelete) {\n // Show fallback if image error occurred and fallback is enabled\n if (imageError && showFallback) {\n return (\n <div className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>\n {computedFallbackText}\n </div>\n );\n }\n \n // Show loading skeleton if URL is not available yet\n if (!fileUrl) {\n return (\n <div className={`bg-sec-100 rounded animate-pulse ${className || \"max-w-full h-48\"}`}>\n <div className=\"w-full h-full flex items-center justify-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-main-500\"></div>\n </div>\n </div>\n );\n }\n \n return (\n <img\n src={fileUrl}\n alt={fileReference.file_metadata.fileName || 'File'}\n className={className || \"max-w-full h-auto\"}\n onError={handleImageError}\n />\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 && (!fileUrl || imageError || !isImage)) {\n return (\n <div className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>\n {computedFallbackText}\n </div>\n );\n }\n \n return (\n <div className={`space-y-2 ${className}`}>\n {isImage && fileUrl && !imageError ? (\n <div className=\"relative\">\n <img\n src={fileUrl}\n alt={fileReference.file_metadata.fileName || 'File'}\n className=\"max-w-full h-auto\"\n onError={handleImageError}\n />\n {showDelete && (\n <>\n <button\n onClick={handleDeleteClick}\n className=\"absolute top-2 right-2 bg-acc-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-sm hover:bg-acc-600\"\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 </div>\n ) : isImage && imageError && showFallback ? (\n // Show fallback when image fails to load and fallback is enabled\n <div className={fallbackClasses} title={fileReference.file_metadata.fileName || 'File'}>\n {computedFallbackText}\n </div>\n ) : (\n <div 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 <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sec-900 truncate\">\n {fileReference.file_metadata.fileName || 'Unknown file'}\n </div>\n <div className=\"text-sm text-sec-500\">\n {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}\n {fileReference.file_metadata.fileType && ` • ${fileReference.file_metadata.fileType}`}\n </div>\n </div>\n {showDelete && (\n <>\n <button\n onClick={handleDeleteClick}\n className=\"text-acc-500 hover:text-acc-700 p-1\"\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 </div>\n )}\n {children}\n </div>\n );\n }\n\n // Multiple files display\n return (\n <div 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 <div 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 src={fileUrl}\n alt={fileRef.file_metadata.fileName || 'File'}\n className=\"w-12 h-12 object-cover rounded\"\n onError={handleImageError}\n />\n ) : (\n <span className=\"text-2xl\">\n {getFileIcon(fileRef.file_metadata.fileType || '')}\n </span>\n )}\n <div className=\"flex-1 min-w-0\">\n <div className=\"font-medium text-sec-900 truncate\">\n {fileRef.file_metadata.fileName || 'Unknown file'}\n </div>\n <div className=\"text-sm text-sec-500\">\n {fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize)}\n {fileRef.file_metadata.fileType && ` • ${fileRef.file_metadata.fileType}`}\n {fileRef.file_metadata.category && ` • ${fileRef.file_metadata.category}`}\n </div>\n </div>\n <div 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 onClick={handleDeleteClick}\n className=\"text-acc-500 hover:text-acc-700 p-1\"\n title=\"Delete file\"\n aria-label=\"Delete file\"\n >\n ×\n </button>\n )}\n </div>\n </div>\n );\n })}\n {children}\n </div>\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 children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSize\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 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 fallbackSize={fallbackSize}\n />\n );\n }\n \n // Only show error if fallback is not enabled\n return (\n <div className={`text-sec-500 text-center p-4 ${className}`}>\n Supabase client not available in public context\n </div>\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 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 fallbackSize={fallbackSize}\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 children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSize\n}: FileDisplayProps) {\n const { supabase } = useUnifiedAuth();\n\n if (!supabase) {\n return (\n <div className={`text-sec-500 text-center p-4 ${className}`}>\n Supabase client not available in authenticated context\n </div>\n );\n }\n\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 }\n );\n\n // Consolidated state for displayOnly mode\n const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState<FileReference | null>(null);\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,\n organisation_id,\n autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference\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 // 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 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 fallbackSize={fallbackSize}\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 with an image, renders a simplified image-only display without metadata or wrapper divs.\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 */\nexport function FileDisplay({\n table_name,\n record_id,\n organisation_id,\n category,\n displayOnly = false,\n showDelete = false,\n className = '',\n children,\n loadingComponent,\n errorComponent,\n showFallback,\n generateFallbackText,\n fallbackText,\n fallbackSize\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 children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSize={fallbackSize}\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 children={children}\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n showFallback={showFallback}\n generateFallbackText={generateFallbackText}\n fallbackText={fallbackText}\n fallbackSize={fallbackSize}\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\nexport interface UseFileUrlOptions {\n /** Organisation ID for signed URL generation */\n organisation_id: string;\n /** Supabase client instance */\n supabase: SupabaseClient;\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 // 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","/**\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 18+ - 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 Header Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A header component specifically designed for public pages with event-specific branding.\n * Displays app logo, event logo, and event information in a clean, accessible layout.\n *\n * Features:\n * - Event-specific branding\n * - App and event logo display\n * - Responsive design\n * - Print-friendly styling\n * - Accessibility compliant\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { PublicPageHeader, PublicPageProvider } from '@jmruthers/pace-core';\n * \n * const APP_NAME = 'CORE';\n * \n * function PublicEventPage() {\n * return (\n * <PublicPageProvider appName={APP_NAME}>\n * <PublicPageHeader \n * event={event}\n * title=\"Event Details\"\n * description=\"Public information about this event\"\n * showEventLogo={true}\n * />\n * </PublicPageProvider>\n * );\n * }\n * ```\n * \n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - High contrast support\n * - Clear content hierarchy\n *\n * @dependencies\n * - React 18+ - Component framework\n * - Event types - Type definitions\n * - FileDisplay component - Logo display\n * - Tailwind CSS - Styling\n */\n\nimport React, { ReactNode } from 'react';\nimport type { Event } from '../../types/unified';\nimport { FileDisplay } from '../FileDisplay/FileDisplay';\nimport { FileCategory } from '../../types/file-reference';\nimport { useAppConfig } from '../../hooks/useAppConfig';\nimport { cn } from '../../utils/core/cn';\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\n/**\n * Header component for public pages with event-specific branding\n * \n * This component displays the app logo, event logo, and event information\n * in a clean, accessible layout suitable for public pages.\n * \n * The app logo is automatically generated from the appName using the pattern:\n * `/{appName.toLowerCase()}_logo_wide.svg` from the public folder.\n * \n * **Important:** The appName is obtained from PublicPageProvider context, which should\n * receive the APP_NAME constant from your App.tsx file. This ensures consistency with\n * authenticated pages that use the same APP_NAME constant.\n * \n * **Event Logo Requirements:**\n * - Event logo files must be marked as `is_public = true` in the `file_references` table\n * - The RPC function `data_file_reference_by_category_list` must be accessible to the anonymous/public role\n * - Storage bucket must allow public read access for logo files\n * - If no public logo is available, a fallback UI with event initials will be displayed\n * \n * @param props - Header configuration and content\n * @returns React element with public page header\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\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 \n {/* Top row with logos */}\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\n {/* Event Information */}\n\n\n {event && (\n <>\n <h1>\n {event.event_name}\n </h1>\n {/* Event Logo */}\n {showEventLogo && event && (\n <>\n {customEventLogo || (\n <>\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 // Note: FileDisplay automatically detects public page context\n // and uses FileDisplayPublic component which queries only public files (is_public = true)\n // If no public logo is found, fallback UI with event initials will be displayed\n />\n </>\n )}\n </>\n )}\n {event.event_venue && (\n <h4>\n {event.event_venue}\n </h4>\n )}\n </>\n )}\n\n {/* Page Title and Description */}\n {title && (\n <>\n <h1>\n {title}\n </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 && (\n <>\n {children}\n </>\n )}\n\n\n\n\n \n </header>\n );\n}\n\n","/**\n * @file Public Page Footer Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A footer component for public pages that matches the normal PaceAppLayout footer exactly.\n * Uses the same styling and structure as the main Footer component.\n *\n * Features:\n * - Identical to normal Footer component\n * - Consistent branding with main app\n * - Responsive design\n * - Accessibility compliant\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { PublicPageFooter } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * return (\n * <PublicPageFooter \n * event={event}\n * companyName=\"My Company\"\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper semantic HTML structure\n * - Screen reader friendly\n * - High contrast support\n * - Clear content hierarchy\n *\n * @dependencies\n * - React 18+ - Component framework\n * - Event types - Type definitions\n * - Tailwind CSS - Styling\n */\n\nimport React from 'react';\nimport { cn } from '../../utils/core/cn';\nimport type { Event } from '../../types/unified';\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\n/**\n * Footer component for public pages that matches the normal Footer exactly\n * \n * This component uses the same styling and structure as the main Footer component\n * to ensure consistency across the application.\n * \n * @param props - Footer configuration and content\n * @returns React element with public page footer\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 // 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', 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 && (\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\n","/**\n * @file Public Loading Spinner Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A loading spinner component specifically designed for public pages.\n * Provides consistent loading states with event-specific branding.\n *\n * Features:\n * - Consistent loading design\n * - Event-specific branding\n * - Multiple size options\n * - Accessibility compliant\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { PublicLoadingSpinner } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * if (isLoading) {\n * return <PublicLoadingSpinner message=\"Loading event details...\" />;\n * }\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Screen reader friendly\n * - Proper ARIA labels\n * - High contrast support\n *\n * @dependencies\n * - React 18+ - Component framework\n * - Tailwind CSS - Styling\n */\n\nimport React from 'react';\nimport { cn } from '../../utils/core/cn';\n\nexport interface PublicLoadingSpinnerProps {\n /** Loading message to display */\n message?: string;\n /** Size variant */\n size?: 'sm' | 'md' | 'lg' | 'xl';\n /** Custom CSS classes */\n className?: string;\n /** Whether to show the app logo */\n showLogo?: boolean;\n /** Custom loading message */\n customMessage?: string;\n /** Whether to center the spinner */\n centered?: boolean;\n}\n\n/**\n * Size classes for different spinner sizes\n */\nconst sizeClasses = {\n sm: 'h-4 w-4',\n md: 'h-8 w-8',\n lg: 'h-12 w-12',\n xl: 'h-16 w-16'\n};\n\n/**\n * Loading spinner component for public pages\n * \n * This component displays a consistent loading state with optional\n * branding and messaging for public pages.\n * \n * @param props - Spinner configuration and styling\n * @returns React element with loading spinner\n */\nexport function PublicLoadingSpinner({\n message = 'Loading...',\n size = 'md',\n className = '',\n showLogo = true,\n customMessage,\n centered = true\n}: PublicLoadingSpinnerProps) {\n const sizeClass = sizeClasses[size];\n const displayMessage = customMessage || message;\n\n const content = (\n <div className={cn(\"flex flex-col items-center\", className)}>\n {/* App Logo */}\n {showLogo && (\n <div className=\"mb-4\">\n <img\n className=\"h-8 w-auto\"\n src=\"/pace_logo_wide.svg\"\n alt=\"PACE Core\"\n />\n </div>\n )}\n\n {/* Spinner */}\n <div className=\"relative\">\n <div\n className={cn(\n sizeClass,\n \"border-2 border-sec-200 border-t-main-600 rounded-full animate-spin\"\n )}\n role=\"status\"\n aria-label=\"Loading\"\n />\n <span className=\"sr-only\">{displayMessage}</span>\n </div>\n\n {/* Loading Message */}\n {displayMessage && (\n <p className=\"mt-4 text-sm text-sec-600 text-center\">\n {displayMessage}\n </p>\n )}\n </div>\n );\n\n if (centered) {\n return (\n <div className=\"min-h-screen bg-background flex items-center justify-center\">\n <div className=\"max-w-md mx-auto px-4\">\n {content}\n </div>\n </div>\n );\n }\n\n return content;\n}\n\n\n/**\n * Full page loading spinner with event branding\n */\nexport function PublicLoadingSpinnerFullPage({\n message = 'Loading event details...',\n eventName,\n className = ''\n}: Pick<PublicLoadingSpinnerProps, 'message' | 'className'> & {\n eventName?: string;\n}) {\n return (\n <div className={cn(\n \"min-h-screen bg-background flex items-center justify-center\",\n className\n )}>\n <div className=\"max-w-md mx-auto text-center px-4\">\n {/* App Logo */}\n <div className=\"mb-8\">\n <img\n className=\"h-12 w-auto mx-auto\"\n src=\"/pace_logo_wide.svg\"\n alt=\"PACE Core\"\n />\n </div>\n\n {/* Event Name */}\n {eventName && (\n <h1 className=\"text-2xl font-bold text-sec-900 mb-4\">\n {eventName}\n </h1>\n )}\n\n {/* Spinner */}\n <div className=\"relative mb-6\">\n <div\n className=\"h-12 w-12 border-4 border-sec-200 border-t-main-600 rounded-full animate-spin mx-auto\"\n role=\"status\"\n aria-label=\"Loading\"\n />\n </div>\n\n {/* Loading Message */}\n <p className=\"text-lg text-sec-600\">\n {message}\n </p>\n\n {/* Loading Dots Animation */}\n <div className=\"mt-4 flex justify-center space-x-1\">\n <div className=\"h-2 w-2 bg-main-600 rounded-full animate-bounce\" style={{ animationDelay: '0ms' }} />\n <div className=\"h-2 w-2 bg-main-600 rounded-full animate-bounce\" style={{ animationDelay: '150ms' }} />\n <div className=\"h-2 w-2 bg-main-600 rounded-full animate-bounce\" style={{ animationDelay: '300ms' }} />\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * Skeleton loading component for content placeholders\n */\nexport function PublicLoadingSkeleton({\n lines = 3,\n className = ''\n}: {\n lines?: number;\n className?: string;\n}) {\n return (\n <div className={cn(\"animate-pulse\", className)}>\n {Array.from({ length: lines }).map((_, index) => (\n <div\n key={index}\n className={cn(\n \"h-4 bg-sec-200 rounded mb-2\",\n index === lines - 1 ? 'w-3/4' : 'w-full'\n )}\n />\n ))}\n </div>\n );\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 * <div className=\"content\">\n * Your public page content\n * </div>\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 18+ - Component framework\n * - React Router - Routing integration\n * - Public hooks - Data access\n * - Tailwind CSS - Styling\n */\n\nimport React, { ReactNode } from 'react';\nimport { PublicPageHeader } from './PublicPageHeader';\nimport { PublicPageFooter } from './PublicPageFooter';\nimport { PublicErrorBoundary } from './PublicErrorBoundary';\nimport { PublicLoadingSpinner } from './PublicLoadingSpinner';\nimport { Button } from '../Button';\nimport { useEventTheme } from '../../hooks/useEventTheme';\nimport type { Event } from '../../types/unified';\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 /** @deprecated Custom CSS classes for the layout - no longer used as wrapper div was removed */\n className?: string;\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/**\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 className = '',\n errorFallback: ErrorFallback,\n loadingFallback: LoadingFallback = PublicLoadingSpinner,\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 === PublicLoadingSpinner) {\n return (\n <PublicLoadingSpinner \n className=\"items-center justify-center\"\n message={loadingMessage}\n />\n );\n }\n return <LoadingFallback />;\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 <PublicErrorBoundary>\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 </PublicErrorBoundary>\n );\n}\n\n/**\n * Hook for accessing public page context\n * Provides access to event data and layout state within public pages\n * \n * @deprecated This hook is no longer needed as PublicPageLayout no longer\n * automatically fetches event data. Use usePublicRouteParams and usePublicEvent\n * directly in your components instead.\n */\nexport function usePublicPageContext() {\n // This hook is deprecated - use usePublicRouteParams and usePublicEvent directly\n return {\n eventCode: null,\n eventId: null,\n event: null,\n isLoading: false,\n error: null,\n refetch: async () => {},\n isPublicPage: true\n };\n}\n","/**\n * @file Public Page Context Checker\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A simple component that immediately identifies if a public page\n * is being rendered inside authentication context.\n */\n\nimport React, { useEffect } from 'react';\nimport { usePublicPageContext } from './PublicPageProvider';\nimport { logger } from '../../utils/core/logger';\n\nexport interface PublicPageContextCheckerProps {\n /** Whether to enable checking */\n enabled?: boolean;\n /** Custom label for this checker instance */\n label?: string;\n}\n\n/**\n * Context checker component that immediately identifies authentication context issues\n * \n * This component will immediately log to console if authentication context\n * is being triggered in a public page.\n * \n * Only enabled in development mode when VITE_ENABLE_DEBUG_LOGS is 'true'\n */\nexport function PublicPageContextChecker({ enabled = true, label = 'PublicPage' }: PublicPageContextCheckerProps) {\n // Check if debug logging is enabled\n // Allow in development mode with VITE_ENABLE_DEBUG_LOGS, or in test mode\n // Also check for VITEST environment variable which is set by Vitest\n const isDebugEnabled = \n (import.meta.env.MODE === 'development' && import.meta.env.VITE_ENABLE_DEBUG_LOGS === 'true') ||\n import.meta.env.MODE === 'test' ||\n import.meta.env.VITEST === true ||\n (typeof process !== 'undefined' && process.env.NODE_ENV === 'test');\n\n // Early return if not in debug mode\n if (!isDebugEnabled || !enabled) {\n return null;\n }\n\n useEffect(() => {\n\n logger.debug('PublicPageContextChecker', `🚨 [${label}] PUBLIC PAGE CONTEXT CHECK`);\n \n // Check for authentication context\n try {\n // This will throw if we're not in UnifiedAuthProvider\n const { isAuthenticated } = require('../../providers/UnifiedAuthProvider').useUnifiedAuth();\n logger.error('PublicPageContextChecker', `❌ [${label}] AUTHENTICATION CONTEXT DETECTED!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] isAuthenticated:`, isAuthenticated);\n logger.error('PublicPageContextChecker', `❌ [${label}] This public page is inside UnifiedAuthProvider - THIS IS WRONG!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] SOLUTION: Move public routes outside of authentication providers`);\n } catch (error) {\n logger.debug('PublicPageContextChecker', `✅ [${label}] No authentication context detected (GOOD!)`);\n }\n\n // Check for organisation context\n try {\n // This will throw if we're not in OrganisationProvider\n const { selectedOrganisation } = require('../../providers/OrganisationProvider').useOrganisations();\n logger.error('PublicPageContextChecker', `❌ [${label}] ORGANISATION CONTEXT DETECTED!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] selectedOrganisation:`, selectedOrganisation);\n logger.error('PublicPageContextChecker', `❌ [${label}] This public page is inside OrganisationProvider - THIS IS WRONG!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] SOLUTION: Move public routes outside of authentication providers`);\n } catch (error) {\n logger.debug('PublicPageContextChecker', `✅ [${label}] No organisation context detected (GOOD!)`);\n }\n\n // Check for event context\n try {\n // This will throw if we're not in EventProvider\n const { events } = require('../../providers/EventProvider').useEvents();\n logger.error('PublicPageContextChecker', `❌ [${label}] EVENT CONTEXT DETECTED!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] events:`, events);\n logger.error('PublicPageContextChecker', `❌ [${label}] This public page is inside EventProvider - THIS IS WRONG!`);\n logger.error('PublicPageContextChecker', `❌ [${label}] SOLUTION: Move public routes outside of authentication providers`);\n } catch (error) {\n logger.debug('PublicPageContextChecker', `✅ [${label}] No event context detected (GOOD!)`);\n }\n\n // Check for PublicPageProvider context\n try {\n const { isPublicPage } = usePublicPageContext();\n if (isPublicPage) {\n logger.debug('PublicPageContextChecker', `✅ [${label}] Public page context detected (GOOD!)`);\n } else {\n logger.warn('PublicPageContextChecker', `⚠️ [${label}] Not in PublicPageProvider context`);\n logger.warn('PublicPageContextChecker', `⚠️ [${label}] SOLUTION: Wrap your public page in <PublicPageProvider>`);\n }\n } catch (error) {\n logger.warn('PublicPageContextChecker', `⚠️ [${label}] Not in PublicPageProvider context`);\n logger.warn('PublicPageContextChecker', `⚠️ [${label}] SOLUTION: Wrap your public page in <PublicPageProvider>`);\n }\n\n // Provide immediate guidance\n logger.debug('PublicPageContextChecker', `📖 [${label}] IMMEDIATE ACTION REQUIRED`);\n logger.debug('PublicPageContextChecker', `If you see any ❌ errors above, your public page is inside authentication context.`);\n logger.debug('PublicPageContextChecker', `This will cause infinite loading loops and authentication errors.`);\n logger.debug('PublicPageContextChecker', `🔧 SOLUTION: Check your main App.tsx file`);\n logger.debug('PublicPageContextChecker', `Make sure public routes are completely separate from authentication providers`);\n logger.debug('PublicPageContextChecker', `Follow the architecture in: packages/core/docs/public-pages-guide.md`);\n\n }, [enabled, label]);\n\n return (\n <div style={{ \n position: 'fixed', \n top: 0, \n left: 0, \n background: 'rgba(220, 38, 38, 0.95)', \n color: 'white', \n padding: '12px', \n fontSize: '12px',\n zIndex: 9999,\n fontFamily: 'monospace',\n maxWidth: '400px',\n borderRadius: '0 0 8px 0',\n border: '2px solid #dc2626'\n }}>\n <div style={{ fontWeight: 'bold', marginBottom: '8px' }}>🚨 PUBLIC PAGE CONTEXT CHECK</div>\n <div>Check console for authentication context analysis</div>\n <div style={{ marginTop: '8px', fontSize: '10px', opacity: 0.9 }}>\n If you see ❌ errors in console, your public page is inside auth context!\n </div>\n </div>\n );\n}\n","/**\n * @file Event Logo Component\n * @package @jmruthers/pace-core\n * @module Components/PublicLayout\n * @since 1.0.0\n *\n * A context-aware component for displaying event logos with automatic fallback to event initials.\n * Automatically detects whether it's being used in a public or authenticated context and behaves\n * appropriately without triggering authentication context leakage.\n *\n * Features:\n * - Context-aware (works in both public and authenticated contexts)\n * - Automatic fallback to event initials\n * - Logo validation and error handling\n * - Multiple size options\n * - Responsive design\n * - Accessibility compliant\n * - TypeScript support\n *\n * @example\n * ```tsx\n * import { EventLogo } from '@jmruthers/pace-core';\n *\n * function EventHeader() {\n * return (\n * <EventLogo\n * eventId={event.id}\n * eventName={event.event_name}\n * organisationId={event.organisation_id}\n * size=\"lg\"\n * className=\"rounded-full\"\n * />\n * );\n * }\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper alt text for images\n * - Screen reader friendly fallbacks\n * - High contrast support\n *\n * @dependencies\n * - React 18+ - Component framework\n * - FileDisplay component - Logo display and fallback handling\n * - Tailwind CSS - Styling\n */\n\nimport React from 'react';\nimport { FileDisplay } from '../FileDisplay/FileDisplay';\nimport { FileCategory } from '../../types/file-reference';\n\nexport interface EventLogoProps {\n /** The event ID to fetch logo for */\n eventId: string;\n /** The event name for fallback text generation */\n eventName: string;\n /** The organisation ID for storage path */\n organisationId: string;\n /** Logo size variant */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Custom CSS classes */\n className?: string;\n /** Whether to show fallback text when no logo is available */\n showFallback?: boolean;\n /** Custom fallback text generator */\n generateFallbackText?: (eventName: string) => string;\n /** Whether to validate image existence (deprecated - FileDisplay handles this) */\n validateImage?: boolean;\n /** Custom loading component */\n loadingComponent?: React.ComponentType;\n /** Custom error component */\n errorComponent?: React.ComponentType<{ error: Error }>;\n}\n\n/**\n * Default fallback text generator\n */\nfunction defaultGenerateFallbackText(eventName: string): string {\n if (!eventName) return 'EV';\n \n return eventName\n .split(' ')\n .map(word => word.charAt(0).toUpperCase())\n .join('')\n .substring(0, 3); // Max 3 characters\n}\n\n/**\n * Component for displaying event logos with fallback to initials\n * \n * This component is context-aware and automatically detects whether it's being used\n * in a public or authenticated context. It uses FileDisplay internally to fetch and\n * display event logos from storage, with automatic fallback to event initials if no\n * logo is available.\n * \n * @param props - Logo configuration and styling\n * @returns React element with event logo or fallback\n */\nexport function EventLogo({\n eventId,\n eventName,\n organisationId,\n size = 'md',\n className = '',\n showFallback = true,\n generateFallbackText = defaultGenerateFallbackText,\n validateImage = true, // Deprecated but kept for backward compatibility\n loadingComponent: LoadingComponent,\n errorComponent: ErrorComponent\n}: EventLogoProps) {\n // Adapt generateFallbackText to FileDisplay's signature\n // FileDisplay expects (fileName?: string) => string, but we have (eventName: string) => string\n const adaptedGenerateFallbackText = React.useCallback(\n (fileName?: string) => {\n // Use eventName if available, otherwise fall back to fileName\n return generateFallbackText(eventName || fileName || '');\n },\n [eventName, generateFallbackText]\n );\n\n // Adapt error component to FileDisplay's signature\n // FileDisplay expects { error: Error | string | null; retry?: () => void }\n const adaptedErrorComponent = ErrorComponent\n ? React.useCallback(\n ({ error }: { error: Error | string | null; retry?: () => void }) => {\n const errorObj = error instanceof Error ? error : new Error(String(error || 'Unknown error'));\n return <ErrorComponent error={errorObj} />;\n },\n [ErrorComponent]\n )\n : undefined;\n\n return (\n <FileDisplay\n table_name=\"event\"\n record_id={eventId}\n organisation_id={organisationId}\n category={FileCategory.EVENT_LOGOS}\n displayOnly={true}\n showFallback={showFallback}\n fallbackSize={size}\n className={className}\n generateFallbackText={adaptedGenerateFallbackText}\n loadingComponent={LoadingComponent}\n errorComponent={adaptedErrorComponent}\n />\n );\n}\n\n/**\n * Compact event logo for small spaces\n */\nexport function EventLogoCompact(props: EventLogoProps) {\n return (\n <EventLogo\n {...props}\n size=\"sm\"\n className={`${props.className || ''} rounded-sm`}\n />\n );\n}\n\n/**\n * Large event logo for prominent display\n */\nexport function EventLogoLarge(props: EventLogoProps) {\n return (\n <EventLogo\n {...props}\n size=\"xl\"\n className={`${props.className || ''} rounded-lg`}\n />\n );\n}\n"],"mappings":"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","names":["React","jsx","React","jsx","React","jsx","jsx","React","jsx","React","jsx","React","jsx","props","React","jsx","jsxs","jsx","React","jsx","jsxs","React","Calendar","useMemo","jsx","jsxs","Calendar","useState","jsx","jsxs","useState","React","useCallback","useMemo","useState","jsx","jsxs","React","UserMenu","useState","useMemo","useCallback","UserMenuLoading","React","ChevronDown","init_UnifiedAuthProvider","jsx","jsxs","userId","isSuperAdmin","ChevronDown","jsx","jsxs","React","Fragment","jsx","jsxs","React","init_UnifiedAuthProvider","useState","useEffect","useMemo","Fragment","jsx","jsxs","useMemo","useState","useEffect","scope","isSuperAdmin","useUnifiedAuth","useEffect","useState","useNavigate","useLocation","jsx","jsxs","useNavigate","useLocation","useState","useEffect","jsx","jsxs","useMemo","Outlet","jsx","jsxs","useMemo","Outlet","jsx","jsxs","useState","useCallback","RefreshCw","AlertCircle","jsx","jsxs","useState","useCallback","useState","useCallback","useEffect","useRef","useMemo","useState","useMemo","useCallback","getSignedUrl","useRef","useEffect","useState","useCallback","useRef","useEffect","useMemo","Fragment","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","error","isUploading","useState","useEffect","useRef","useContext","useMemo","useState","useEffect","useCallback","useRef","log","useState","useRef","useCallback","error","useEffect","Fragment","jsx","jsxs","useState","useRef","useMemo","useEffect","fileUrl","useContext","React","jsx","Fragment","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","usePublicPageContext","useEffect","jsx","jsxs","useEffect","React","jsx","defaultGenerateFallbackText","React"]}