@jmruthers/pace-core 0.5.102 → 0.5.104

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 (143) hide show
  1. package/dist/{DataTable-DXELRJIX.js → DataTable-EEDFYMJP.js} +2 -2
  2. package/dist/{PublicLoadingSpinner-Cvgk-V0F.d.ts → PublicLoadingSpinner-48ewSMKK.d.ts} +1 -96
  3. package/dist/{chunk-EVVRUGQ2.js → chunk-62AVH7CM.js} +78 -55
  4. package/dist/{chunk-EVVRUGQ2.js.map → chunk-62AVH7CM.js.map} +1 -1
  5. package/dist/{chunk-SZWRW5FD.js → chunk-B6LDHZGA.js} +33 -4
  6. package/dist/chunk-B6LDHZGA.js.map +1 -0
  7. package/dist/{chunk-7ME4Z5OY.js → chunk-S7TZKHG3.js} +12 -148
  8. package/dist/chunk-S7TZKHG3.js.map +1 -0
  9. package/dist/{chunk-UDWTCBSH.js → chunk-SF6VFEWO.js} +12 -175
  10. package/dist/chunk-SF6VFEWO.js.map +1 -0
  11. package/dist/components.d.ts +1 -1
  12. package/dist/components.js +3 -9
  13. package/dist/components.js.map +1 -1
  14. package/dist/hooks.d.ts +1 -1
  15. package/dist/hooks.js +2 -9
  16. package/dist/hooks.js.map +1 -1
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +4 -16
  19. package/dist/index.js.map +1 -1
  20. package/dist/types.js +3 -3
  21. package/dist/{usePublicRouteParams-BwMR2uub.d.ts → usePublicRouteParams-BiXgKiYa.d.ts} +1 -117
  22. package/dist/utils.js +1 -1
  23. package/docs/api/classes/ColumnFactory.md +1 -1
  24. package/docs/api/classes/ErrorBoundary.md +1 -1
  25. package/docs/api/classes/InvalidScopeError.md +1 -1
  26. package/docs/api/classes/MissingUserContextError.md +1 -1
  27. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  28. package/docs/api/classes/PermissionDeniedError.md +1 -1
  29. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  30. package/docs/api/classes/RBACAuditManager.md +1 -1
  31. package/docs/api/classes/RBACCache.md +1 -1
  32. package/docs/api/classes/RBACEngine.md +1 -1
  33. package/docs/api/classes/RBACError.md +1 -1
  34. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  35. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  36. package/docs/api/classes/StorageUtils.md +1 -1
  37. package/docs/api/enums/FileCategory.md +1 -1
  38. package/docs/api/interfaces/AggregateConfig.md +1 -1
  39. package/docs/api/interfaces/ButtonProps.md +1 -1
  40. package/docs/api/interfaces/CardProps.md +1 -1
  41. package/docs/api/interfaces/ColorPalette.md +1 -1
  42. package/docs/api/interfaces/ColorShade.md +1 -1
  43. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  44. package/docs/api/interfaces/DataRecord.md +1 -1
  45. package/docs/api/interfaces/DataTableAction.md +1 -1
  46. package/docs/api/interfaces/DataTableColumn.md +1 -1
  47. package/docs/api/interfaces/DataTableProps.md +1 -1
  48. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  49. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  50. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  51. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  52. package/docs/api/interfaces/FileMetadata.md +1 -1
  53. package/docs/api/interfaces/FileReference.md +1 -1
  54. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  55. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  56. package/docs/api/interfaces/FileUploadProps.md +1 -1
  57. package/docs/api/interfaces/FooterProps.md +1 -1
  58. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  59. package/docs/api/interfaces/InputProps.md +1 -1
  60. package/docs/api/interfaces/LabelProps.md +1 -1
  61. package/docs/api/interfaces/LoginFormProps.md +1 -1
  62. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  63. package/docs/api/interfaces/NavigationContextType.md +1 -1
  64. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  65. package/docs/api/interfaces/NavigationItem.md +1 -1
  66. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  67. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  68. package/docs/api/interfaces/Organisation.md +1 -1
  69. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  70. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  71. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  72. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  73. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  74. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  75. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  76. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  77. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  78. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  79. package/docs/api/interfaces/PaletteData.md +1 -1
  80. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  81. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  82. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  83. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  84. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  85. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  86. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  87. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  88. package/docs/api/interfaces/RBACConfig.md +1 -1
  89. package/docs/api/interfaces/RBACLogger.md +1 -1
  90. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  91. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  92. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  93. package/docs/api/interfaces/RouteConfig.md +1 -1
  94. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  95. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  96. package/docs/api/interfaces/StorageConfig.md +1 -1
  97. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  98. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  99. package/docs/api/interfaces/StorageListOptions.md +1 -1
  100. package/docs/api/interfaces/StorageListResult.md +1 -1
  101. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  102. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  103. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  104. package/docs/api/interfaces/StyleImport.md +1 -1
  105. package/docs/api/interfaces/SwitchProps.md +1 -1
  106. package/docs/api/interfaces/ToastActionElement.md +1 -1
  107. package/docs/api/interfaces/ToastProps.md +1 -1
  108. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  109. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  110. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  111. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  112. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  113. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  114. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  115. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  116. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  117. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  118. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  119. package/docs/api/interfaces/UserEventAccess.md +1 -1
  120. package/docs/api/interfaces/UserMenuProps.md +1 -1
  121. package/docs/api/interfaces/UserProfile.md +1 -1
  122. package/docs/api/modules.md +4 -152
  123. package/docs/implementation-guides/file-reference-system.md +31 -19
  124. package/package.json +1 -1
  125. package/src/components/DataTable/components/DataTableCore.tsx +23 -13
  126. package/src/components/DataTable/hooks/useTableColumns.ts +36 -6
  127. package/src/components/PublicLayout/PublicPageHeader.tsx +1 -1
  128. package/src/components/index.ts +0 -2
  129. package/src/hooks/public/index.ts +2 -4
  130. package/src/hooks/public/usePublicFileDisplay.ts +19 -1
  131. package/src/index.ts +0 -2
  132. package/src/utils/file-reference.ts +30 -2
  133. package/src/utils/storage/README.md +22 -20
  134. package/dist/chunk-7ME4Z5OY.js.map +0 -1
  135. package/dist/chunk-SZWRW5FD.js.map +0 -1
  136. package/dist/chunk-UDWTCBSH.js.map +0 -1
  137. package/docs/api/interfaces/UseEventLogoOptions.md +0 -74
  138. package/docs/api/interfaces/UseEventLogoReturn.md +0 -81
  139. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  140. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  141. package/src/hooks/public/usePublicEventLogo.ts +0 -295
  142. package/src/hooks/useEventLogo.ts +0 -316
  143. /package/dist/{DataTable-DXELRJIX.js.map → DataTable-EEDFYMJP.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useOrganisationSecurity.ts","../src/hooks/useOrganisationPermissions.ts","../src/hooks/useEventTheme.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["/**\n * @file Organisation Security Hook\n * @package @jmruthers/pace-core\n * @module Hooks/OrganisationSecurity\n * @since 0.4.0\n *\n * Security-focused hook for organisation access validation and super admin functionality.\n * Provides utilities for validating user access to organisations and checking permissions.\n */\n\nimport { useCallback, useMemo, useEffect, useState } from 'react';\nimport { useUnifiedAuth } from '../providers';\nimport { useOrganisations } from './useOrganisations';\n// Legacy useRBAC hook removed - use new RBAC system instead\nimport type { OrganisationSecurityError, SuperAdminContext } from '../types/organisation';\nimport type { Permission } from '../rbac/types';\n\nexport interface OrganisationSecurityHook {\n // Super admin context\n superAdminContext: SuperAdminContext;\n \n // Access validation\n validateOrganisationAccess: (orgId: string) => Promise<boolean>;\n hasMinimumRole: (minRole: string, orgId?: string) => boolean;\n canAccessChildOrganisations: (orgId?: string) => boolean;\n \n // Permission checks\n hasPermission: (permission: string, orgId?: string) => Promise<boolean>;\n getUserPermissions: (orgId?: string) => Promise<string[]>;\n \n // Audit logging\n logOrganisationAccess: (action: string, details?: any) => Promise<void>;\n \n // Security utilities\n ensureOrganisationAccess: (orgId: string) => Promise<void>;\n validateUserAccess: (userId: string, orgId: string) => Promise<boolean>;\n}\n\nexport const useOrganisationSecurity = (): OrganisationSecurityHook => {\n const { user, session, supabase } = useUnifiedAuth();\n const { selectedOrganisation, getUserRole, validateOrganisationAccess: validateAccess } = useOrganisations();\n \n // Super admin status - query database for security (user_metadata can be spoofed)\n const [isSuperAdmin, setIsSuperAdmin] = useState<boolean>(false);\n const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(false);\n\n // Check super admin status from database\n useEffect(() => {\n if (!user || !session || !supabase) {\n setIsSuperAdmin(false);\n return;\n }\n\n const checkSuperAdmin = async () => {\n setIsCheckingSuperAdmin(true);\n try {\n const now = new Date().toISOString();\n const { data, error } = await supabase\n .from('rbac_global_roles')\n .select('role')\n .eq('user_id', user.id)\n .eq('role', 'super_admin')\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .limit(1);\n\n setIsSuperAdmin(!error && data && data.length > 0);\n } catch (error) {\n console.error('[useOrganisationSecurity] Error checking super admin status:', error);\n setIsSuperAdmin(false);\n } finally {\n setIsCheckingSuperAdmin(false);\n }\n };\n\n checkSuperAdmin();\n }, [user, session, supabase]);\n\n // Super admin context\n const superAdminContext = useMemo((): SuperAdminContext => {\n return {\n isSuperAdmin,\n hasGlobalAccess: isSuperAdmin,\n canManageAllOrganisations: isSuperAdmin\n };\n }, [isSuperAdmin]);\n\n // Validate organisation access with database check\n const validateOrganisationAccess = useCallback(async (orgId: string): Promise<boolean> => {\n if (!user || !session || !supabase) return false;\n \n try {\n // Super admin has access to all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Check organisation membership using consolidated rbac_organisation_roles table\n const { data, error } = await supabase\n .from('rbac_organisation_roles')\n .select('id')\n .eq('user_id', user.id)\n .eq('organisation_id', orgId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']) // Only actual members, not supporters\n .single();\n\n if (error) {\n console.error('[useOrganisationSecurity] Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating organisation access:', error);\n return false;\n }\n }, [user, session, supabase, superAdminContext.isSuperAdmin]);\n\n // Check if user has minimum role\n const hasMinimumRole = useCallback((minRole: string, orgId?: string): boolean => {\n // Super admin has all roles\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n const roleHierarchy = ['supporter', 'member', 'leader', 'org_admin'];\n \n const userRoleIndex = roleHierarchy.indexOf(userRole);\n const minRoleIndex = roleHierarchy.indexOf(minRole);\n \n return userRoleIndex >= minRoleIndex;\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check if user can access child organisations\n const canAccessChildOrganisations = useCallback((orgId?: string): boolean => {\n // Super admin can access all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n return userRole === 'org_admin';\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check specific permission using the new RBAC system\n const hasPermission = useCallback(async (permission: string, orgId?: string): Promise<boolean> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return false;\n\n try {\n // Use the new RBAC system\n const { isPermitted } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n return await isPermitted({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception checking permission:', error);\n return false;\n }\n }, [selectedOrganisation, user, superAdminContext.isSuperAdmin]);\n\n // Get user's permissions for organisation using the new RBAC system\n const getUserPermissions = useCallback(async (orgId?: string): Promise<string[]> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return ['*']; // All permissions\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return [];\n\n try {\n // Use the new RBAC system\n const { getPermissionMap } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope\n });\n \n // Flatten all permissions from all pages\n const allPermissions = Object.entries(permissionMap)\n .filter(([, allowed]) => allowed)\n .map(([permission]) => permission);\n return [...new Set(allPermissions)]; // Remove duplicates\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception getting user permissions:', error);\n return [];\n }\n }, [selectedOrganisation, user, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Log organisation access for audit using the new RBAC audit system\n const logOrganisationAccess = useCallback(async (action: string, details?: any): Promise<void> => {\n if (!user || !selectedOrganisation) return;\n\n try {\n // Use the new RBAC audit system - only if we have a valid organisation ID\n if (selectedOrganisation.id) {\n const { emitAuditEvent } = await import('../rbac/audit');\n \n await emitAuditEvent({\n type: 'permission_check',\n userId: user.id,\n organisationId: selectedOrganisation.id,\n permission: action,\n decision: true, // Assume access was granted if we're logging it\n source: 'api',\n duration_ms: 0, // No actual permission check performed here\n metadata: details || {}\n });\n }\n } catch (error) {\n console.error('[useOrganisationSecurity] Error logging organisation access:', error);\n }\n }, [user, selectedOrganisation]);\n\n // Ensure organisation access (throws if no access)\n const ensureOrganisationAccess = useCallback(async (orgId: string): Promise<void> => {\n const hasAccess = await validateOrganisationAccess(orgId);\n \n if (!hasAccess) {\n const error = new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n error.name = 'OrganisationSecurityError';\n error.code = 'ACCESS_DENIED';\n error.organisationId = orgId;\n error.userId = user?.id;\n throw error;\n }\n }, [validateOrganisationAccess, user]);\n\n // Validate user access (for admin functions)\n const validateUserAccess = useCallback(async (userId: string, orgId: string): Promise<boolean> => {\n if (!supabase) return false;\n\n try {\n // Super admin can validate any user\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Regular users can only validate their own access\n if (userId !== user?.id) {\n return false;\n }\n\n return await validateOrganisationAccess(orgId);\n } catch (error) {\n console.error('[useOrganisationSecurity] Exception validating user access:', error);\n return false;\n }\n }, [supabase, superAdminContext.isSuperAdmin, user, validateOrganisationAccess]);\n\n return {\n superAdminContext,\n validateOrganisationAccess,\n hasMinimumRole,\n canAccessChildOrganisations,\n hasPermission,\n getUserPermissions,\n logOrganisationAccess,\n ensureOrganisationAccess,\n validateUserAccess\n };\n}; ","/**\n * @file useOrganisationPermissions Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useOrganisationPermissions\n * @since 0.4.0\n *\n * Hook for managing organisation-specific permissions and role validation.\n * Provides secure access to user's role and permissions within organisations.\n *\n * @example\n * ```tsx\n * function OrganisationComponent() {\n * const { \n * isOrgAdmin, \n * canManageMembers,\n * userRole,\n * hasOrganisationAccess\n * } = useOrganisationPermissions();\n * \n * return (\n * <div>\n * {isOrgAdmin && <AdminPanel />}\n * {canManageMembers && <MemberManagement />}\n * <p>Your role: {userRole}</p>\n * </div>\n * );\n * }\n * \n * // For specific organisation\n * function MultiOrgComponent() {\n * const permissions = useOrganisationPermissions('org-123');\n * \n * if (!permissions.hasOrganisationAccess) {\n * return <div>No access to this organisation</div>;\n * }\n * \n * return <div>Role in org-123: {permissions.userRole}</div>;\n * }\n * ```\n *\n * @security\n * - Validates user membership in organisation\n * - Provides role-based permission checks\n * - Ensures secure access to organisation data\n * - Real-time permission validation\n */\n\nimport { useMemo } from 'react';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport { useOrganisationSecurity } from './useOrganisationSecurity';\nimport type { OrganisationRole, OrganisationPermission } from '../types/organisation';\n\nexport interface UseOrganisationPermissionsReturn {\n /** User's role in the organisation */\n userRole: OrganisationRole | 'no_access';\n \n /** Whether user has organisation admin role */\n isOrgAdmin: boolean;\n \n /** Whether user is a super admin */\n isSuperAdmin: boolean;\n \n /** Whether user can moderate content */\n canModerate: boolean;\n \n /** Whether user can manage members */\n canManageMembers: boolean;\n \n /** Whether user can manage organisation settings */\n canManageSettings: boolean;\n \n /** Whether user can manage events */\n canManageEvents: boolean;\n \n /** Whether user has any admin privileges */\n hasAdminPrivileges: boolean;\n \n /** Whether user has access to the organisation */\n hasOrganisationAccess: boolean;\n \n /** Check if user has specific permission */\n hasPermission: (permission: OrganisationPermission) => boolean;\n \n /** Get all permissions for the user */\n getAllPermissions: () => OrganisationPermission[];\n \n /** Organisation ID being checked */\n organisationId: string;\n}\n\n/**\n * Hook to access organisation-specific permissions and roles\n * \n * @param orgId - Optional organisation ID. Defaults to currently selected organisation\n * @returns Organisation permissions and role information\n */\nexport function useOrganisationPermissions(orgId?: string): UseOrganisationPermissionsReturn {\n const { \n selectedOrganisation, \n getUserRole, \n validateOrganisationAccess,\n ensureOrganisationContext\n } = useOrganisations();\n \n // Get super admin context if available (may not be available in all contexts)\n let superAdminContext: { isSuperAdmin: boolean } = { isSuperAdmin: false };\n try {\n superAdminContext = useOrganisationSecurity().superAdminContext;\n } catch {\n // Not available in this context, default to false\n }\n\n const organisationId = useMemo(() => {\n if (orgId) {\n return orgId;\n }\n try {\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n } catch {\n return '';\n }\n }, [orgId, ensureOrganisationContext]);\n\n const userRole = useMemo(() => {\n if (!organisationId) return 'no_access';\n const role = getUserRole(organisationId);\n // Map to valid OrganisationRole or 'no_access'\n if (role === 'org_admin' || role === 'leader' || role === 'member' || role === 'supporter') {\n return role as OrganisationRole;\n }\n return 'no_access';\n }, [organisationId, getUserRole]);\n\n const hasOrganisationAccess = useMemo(() => {\n if (!organisationId) return false;\n return validateOrganisationAccess(organisationId);\n }, [organisationId, validateOrganisationAccess]);\n\n const permissions = useMemo(() => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return {\n isOrgAdmin: false,\n isSuperAdmin: false,\n canModerate: false,\n canManageMembers: false,\n canManageSettings: false,\n canManageEvents: false,\n hasAdminPrivileges: false\n };\n }\n\n const isOrgAdmin = userRole === 'org_admin';\n const isLeader = userRole === 'leader';\n const isMember = userRole === 'member';\n const isSupporter = userRole === 'supporter';\n\n // Super admin status - database backed (user_metadata can be spoofed)\n // Get super admin status from the security hook\n const isSuperAdmin = superAdminContext.isSuperAdmin;\n\n return {\n isOrgAdmin,\n isSuperAdmin,\n canModerate: isSuperAdmin || isOrgAdmin || isLeader,\n canManageMembers: isSuperAdmin || isOrgAdmin || isLeader, // Leaders can manage members\n canManageSettings: isSuperAdmin || isOrgAdmin,\n canManageEvents: isSuperAdmin || isOrgAdmin || isLeader,\n hasAdminPrivileges: isSuperAdmin || isOrgAdmin || isLeader // Leaders have admin privileges\n };\n }, [hasOrganisationAccess, userRole]);\n\n const hasPermission = useMemo(() => {\n return (permission: OrganisationPermission): boolean => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return false;\n }\n\n // Super admin has all permissions (org_admin acts as super admin within org)\n if (userRole === 'org_admin' || permission === '*') {\n return true;\n }\n\n // Map permissions to roles using the defined permissions from organisation types\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n const userPermissions = rolePermissions[userRole as OrganisationRole] || [];\n return userPermissions.includes(permission) || userPermissions.includes('*');\n };\n }, [hasOrganisationAccess, userRole]);\n\n const getAllPermissions = useMemo(() => {\n return (): OrganisationPermission[] => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return [];\n }\n\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n return rolePermissions[userRole as OrganisationRole] || [];\n };\n }, [hasOrganisationAccess, userRole]);\n\n return useMemo(() => ({\n userRole,\n organisationId,\n hasOrganisationAccess,\n hasPermission,\n getAllPermissions,\n ...permissions\n }), [userRole, organisationId, hasOrganisationAccess, hasPermission, getAllPermissions, permissions]);\n} ","/**\n * @file Event Theme Hook\n * @package @jmruthers/pace-core\n * @module Hooks/EventTheme\n * @since 2.0.0\n * \n * Hook that automatically applies event-specific theming when an event is selected.\n * This ensures consistent UX across all apps in the pace suite.\n * \n * @example\n * ```tsx\n * import { useEventTheme } from '@jmruthers/pace-core/hooks';\n * \n * function MyApp() {\n * // Automatically applies event colors when event is selected\n * useEventTheme();\n * \n * return <div>Your app content</div>;\n * }\n * ```\n */\n\nimport { useEffect } from 'react';\nimport { useEvents } from './useEvents';\nimport { applyPalette, clearPalette } from '../theming/runtime';\nimport type { PaletteData, ColorPalette } from '../theming/runtime';\n\n/**\n * Hook that automatically applies event-specific theming\n * \n * This hook watches the selected event and applies its colors using the theming system.\n * It will:\n * - Apply event colors when an event with `event_colours` is selected\n * - Clear theming when no event is selected\n * - Handle cleanup when the component unmounts\n * \n * @returns void - This is an effect hook with no return value\n */\nexport function useEventTheme(): void {\n const { selectedEvent } = useEvents();\n\n useEffect(() => {\n // If there's no selected event, clear any dynamic theming\n if (!selectedEvent) {\n clearPalette();\n return;\n }\n\n // Check if the event has theme colors\n const eventColours = selectedEvent.event_colours;\n\n if (!eventColours || typeof eventColours !== 'object') {\n clearPalette();\n return;\n }\n\n // Validate that event_colours has the expected structure\n const palette = eventColours as Partial<PaletteData>;\n \n // Check if we have at least one valid palette (main, sec, or acc)\n if (!palette.main && !palette.sec && !palette.acc) {\n clearPalette();\n return;\n }\n\n // Apply the palette\n // The system expects main, sec, and acc, so we ensure all are present (empty if needed)\n const fullPalette: PaletteData = {\n main: (palette.main as ColorPalette) || {},\n sec: (palette.sec as ColorPalette) || {},\n acc: (palette.acc as ColorPalette) || {},\n };\n\n try {\n applyPalette(fullPalette);\n } catch (error) {\n console.error('[useEventTheme] Failed to apply event palette:', error);\n }\n\n // Cleanup function to clear palette when component unmounts or event changes\n return () => {\n // Don't clear on unmount since we want the theme to persist\n // The next event selection will update it\n };\n }, [selectedEvent]);\n}\n","/**\n * @file Public Event Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event data without authentication.\n * Provides event information by event_code for public pages.\n *\n * Features:\n * - No authentication required\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Automatic refetch capabilities\n *\n * @example\n * ```tsx\n * import { usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams();\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode);\n *\n * if (isLoading) return <div>Loading event...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Date: {event.event_date}</p>\n * <p>Venue: {event.event_venue}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible public event display\n * - Supports screen reader friendly loading states\n *\n * @security\n * - Only returns public-safe event data\n * - Validates event_code before querying\n * - No sensitive information exposed\n * - Rate limiting applied at database level\n *\n * @performance\n * - Built-in caching with TTL\n * - Minimal re-renders with stable references\n * - Lazy loading support\n * - Error boundary integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Database integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createClient } from '@supabase/supabase-js';\nimport type { Event } from '../../types/unified';\nimport type { Database } from '../../types/database';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventReturn {\n /** The event data, null if not loaded or not found */\n event: Event | null;\n /** Whether the data is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the data */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventOptions {\n /** Cache TTL in milliseconds (default: 5 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n}\n\n/**\n * Hook for accessing public event data by event_code\n * \n * This hook provides access to public event information without requiring\n * authentication. It includes caching, error handling, and loading states.\n * \n * @param eventCode - The event code to look up\n * @param options - Configuration options for caching and behavior\n * @returns Object containing event data, loading state, error, and refetch function\n */\nexport function usePublicEvent(\n eventCode: string,\n options: UsePublicEventOptions = {}\n): UsePublicEventReturn {\n const {\n cacheTtl = 5 * 60 * 1000, // 5 minutes\n enableCache = true\n } = options;\n\n const [event, setEvent] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get environment variables from public page context or fallback to direct access\n let environment: { supabaseUrl: string | null; supabaseKey: string | null };\n \n try {\n environment = usePublicPageContext().environment;\n } catch {\n // Fallback to direct environment variable access if not in PublicPageProvider\n environment = {\n supabaseUrl: (import.meta as any).env?.VITE_SUPABASE_URL || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_URL || null,\n supabaseKey: (import.meta as any).env?.VITE_SUPABASE_ANON_KEY || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_ANON_KEY || null\n };\n }\n \n // Create a simple Supabase client for public access\n const supabase = useMemo(() => {\n if (typeof window === 'undefined') return null;\n \n if (!environment.supabaseUrl || !environment.supabaseKey) {\n console.warn('[usePublicEvent] Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment.');\n return null;\n }\n\n return createClient<Database>(environment.supabaseUrl, environment.supabaseKey);\n }, [environment.supabaseUrl, environment.supabaseKey]);\n\n // Helper function to try refreshing schema cache\n const refreshSchemaCache = useCallback(async () => {\n try {\n // Try to trigger a schema refresh by querying a system table\n await (supabase as any).from('information_schema.routines').select('routine_name').limit(1);\n } catch (error) {\n // Ignore errors, this is just an attempt to refresh cache\n console.debug('[usePublicEvent] Schema cache refresh attempt failed:', error);\n }\n }, [supabase]);\n\n const fetchEvent = useCallback(async (): Promise<void> => {\n if (!eventCode || !supabase) {\n setError(new Error('Invalid event code or Supabase client not available'));\n setIsLoading(false);\n return;\n }\n\n // Check cache first\n const cacheKey = `public_event_${eventCode}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setEvent(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n let eventData: any = null;\n\n try {\n // Try to call the public event RPC function first\n const response = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const data = response?.data;\n const rpcError = response?.error;\n\n if (rpcError) {\n // If RPC function doesn't exist or schema cache issue, try refresh first, then fallback\n if (rpcError.message?.includes('Could not find the function') || \n rpcError.message?.includes('does not exist') ||\n rpcError.message?.includes('schema cache')) {\n console.warn('[usePublicEvent] RPC function not found or schema cache issue, attempting refresh:', rpcError.message);\n \n // Try to refresh schema cache first\n await refreshSchemaCache();\n \n // Try RPC call one more time after refresh\n try {\n const retryResponse = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const retryData = retryResponse?.data;\n const retryError = retryResponse?.error;\n \n if (!retryError && retryData && retryData.length > 0) {\n eventData = retryData[0];\n } else {\n throw new Error('RPC still failing after cache refresh');\n }\n } catch (retryError) {\n console.warn('[usePublicEvent] RPC still failing after cache refresh, falling back to direct table access');\n \n // Fallback: Direct table access with public RLS policy\n const tableResponse2 = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse2?.data;\n const tableError = tableResponse2?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n } else {\n // For RPC errors that aren't schema cache issues, throw immediately without fallback\n const errorMessage = rpcError?.message || rpcError?.toString() || 'Failed to fetch event';\n setEvent(null);\n setError(new Error(errorMessage));\n setIsLoading(false);\n return;\n }\n } else {\n if (!data || data.length === 0 || !data[0]) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n eventData = data[0];\n }\n } catch (rpcError) {\n // If RPC call fails for any reason (including schema cache issues), try direct table access\n console.warn('[usePublicEvent] RPC call failed, falling back to direct table access:', rpcError);\n \n const tableResponse = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse?.data;\n const tableError = tableResponse?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n \n // Transform to Event type\n const transformedEvent: Event = {\n id: eventData.event_id,\n event_id: eventData.event_id,\n event_name: eventData.event_name,\n event_code: eventCode,\n event_date: eventData.event_date,\n event_venue: eventData.event_venue,\n event_participants: eventData.event_participants,\n event_logo: eventData.event_logo,\n event_colours: eventData.event_colours,\n organisation_id: eventData.organisation_id,\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n // Legacy compatibility\n name: eventData.event_name,\n start_date: eventData.event_date\n };\n\n setEvent(transformedEvent);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: transformedEvent,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n console.error('[usePublicEvent] Error fetching event:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setEvent(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventCode, supabase, cacheTtl, enableCache]);\n\n // Fetch event when eventCode changes\n useEffect(() => {\n fetchEvent();\n }, [fetchEvent]);\n\n const refetch = useCallback(async (): Promise<void> => {\n // Clear cache for this event\n if (enableCache) {\n const cacheKey = `public_event_${eventCode}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchEvent();\n }, [fetchEvent, eventCode, enableCache]);\n\n return {\n event,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public event data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicEventCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_event_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicEventCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_event_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Route Params Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for extracting and validating public route parameters.\n * Provides event code extraction and validation for public pages.\n *\n * Features:\n * - URL parameter extraction\n * - Event code validation\n * - TypeScript support\n * - Error handling\n * - Route pattern support\n *\n * @example\n * ```tsx\n * import { usePublicRouteParams } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode, eventId, event, error, isLoading } = usePublicRouteParams();\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Event Code: {eventCode}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible route parameter handling\n * - Supports screen reader friendly error states\n *\n * @security\n * - Validates event codes before processing\n * - Sanitizes URL parameters\n * - No sensitive information exposed\n * - Rate limiting applied at route level\n *\n * @performance\n * - Minimal re-renders with stable references\n * - Efficient parameter extraction\n * - Caching integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - React Router - URL parameter extraction\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport type { Event } from '../../types/unified';\nimport { usePublicEvent } from './usePublicEvent';\n\nexport interface UsePublicRouteParamsReturn {\n /** The event code from the URL */\n eventCode: string | null;\n /** The event ID (resolved from event code) */\n eventId: string | null;\n /** The full event object */\n event: Event | null;\n /** Whether the route parameters are being processed */\n isLoading: boolean;\n /** Any error that occurred during processing */\n error: Error | null;\n /** Function to manually refetch the event data */\n refetch: () => Promise<void>;\n}\n\ninterface UsePublicRouteParamsOptions {\n /** Whether to automatically fetch event data (default: true) */\n fetchEventData?: boolean;\n /** Custom event code parameter name (default: 'eventCode') */\n eventCodeParam?: string;\n /** Whether to validate event code format (default: true) */\n validateEventCode?: boolean;\n}\n\n/**\n * Validate event code format\n * Event codes should be alphanumeric with optional hyphens/underscores in the middle\n */\nfunction validateEventCodeFormat(eventCode: string): boolean {\n if (!eventCode || typeof eventCode !== 'string') return false;\n \n // Allow alphanumeric characters, hyphens, and underscores\n // Length between 3 and 50 characters\n // Must not start or end with hyphen/underscore\n const eventCodeRegex = /^[a-zA-Z0-9][a-zA-Z0-9_-]{1,48}[a-zA-Z0-9]$/;\n const matchesFormat = eventCodeRegex.test(eventCode);\n \n if (!matchesFormat) return false;\n \n // Additional check: no consecutive hyphens or underscores\n if (eventCode.includes('--') || eventCode.includes('__') || eventCode.includes('-_') || eventCode.includes('_-')) {\n return false;\n }\n \n return true;\n}\n\n/**\n * Hook for extracting and validating public route parameters\n * \n * This hook extracts event codes from URL parameters and optionally\n * fetches the corresponding event data. It provides validation and\n * error handling for public routes.\n * \n * @param options - Configuration options for behavior\n * @returns Object containing route parameters, event data, loading state, error, and refetch function\n */\nexport function usePublicRouteParams(\n options: UsePublicRouteParamsOptions = {}\n): UsePublicRouteParamsReturn {\n const {\n fetchEventData = true,\n eventCodeParam = 'eventCode',\n validateEventCode = true\n } = options;\n\n const params = useParams();\n const location = useLocation();\n \n const [error, setError] = useState<Error | null>(null);\n\n // Extract event code from URL parameters\n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n // Don't set error immediately - let the component handle missing eventCode gracefully\n return null;\n }\n\n // Validate event code format if requested\n if (validateEventCode && !validateEventCodeFormat(code)) {\n setError(new Error(`Invalid event code format: ${code}`));\n return null;\n }\n\n setError(null);\n return code;\n }, [params, eventCodeParam, validateEventCode]);\n\n // Use the public event hook to fetch event data\n const {\n event,\n isLoading: eventLoading,\n error: eventError,\n refetch: refetchEvent\n } = usePublicEvent(eventCode || '', {\n enableCache: true,\n cacheTtl: 5 * 60 * 1000 // 5 minutes\n });\n\n // Determine if we should show loading state\n const isLoading = useMemo(() => {\n if (!fetchEventData) return false;\n return eventLoading;\n }, [fetchEventData, eventLoading]);\n\n // Determine the final error state\n const finalError = useMemo(() => {\n if (error) return error;\n if (eventError) return eventError;\n return null;\n }, [error, eventError]);\n\n // Extract event ID from event data\n const eventId = useMemo(() => {\n if (!event) return null;\n return event.event_id || event.id;\n }, [event]);\n\n // Refetch function\n const refetch = useCallback(async (): Promise<void> => {\n if (!fetchEventData) return;\n await refetchEvent();\n }, [fetchEventData, refetchEvent]);\n\n // Log route access for debugging\n useEffect(() => {\n if (eventCode && event) {\n console.log('[usePublicRouteParams] Public route accessed:', {\n eventCode,\n eventId: event.event_id,\n eventName: event.event_name,\n path: location.pathname\n });\n }\n }, [eventCode, event, location.pathname]);\n\n return {\n eventCode,\n eventId,\n event: fetchEventData ? event : null,\n isLoading,\n error: finalError,\n refetch\n };\n}\n\n/**\n * Hook for extracting just the event code without fetching event data\n * Useful when you only need the event code and will fetch data separately\n */\nexport function usePublicEventCode(\n eventCodeParam: string = 'eventCode'\n): { eventCode: string | null; error: Error | null } {\n const params = useParams();\n \n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n return null;\n }\n\n // Validate event code format\n if (!validateEventCodeFormat(code)) {\n return null;\n }\n\n return code;\n }, [params, eventCodeParam]);\n\n const error = useMemo(() => {\n if (!eventCode) {\n return new Error(`Event code parameter '${eventCodeParam}' not found or invalid`);\n }\n return null;\n }, [eventCode, eventCodeParam]);\n\n return {\n eventCode,\n error\n };\n}\n\n/**\n * Utility function to generate public route paths\n */\nexport function generatePublicRoutePath(\n eventCode: string,\n pageName: string = 'index'\n): string {\n if (!eventCode || !validateEventCodeFormat(eventCode)) {\n throw new Error('Invalid event code for route generation');\n }\n \n return `/public/event/${eventCode}/${pageName}`;\n}\n\n/**\n * Utility function to extract event code from a public route path\n */\nexport function extractEventCodeFromPath(path: string): string | null {\n const match = path.match(/^\\/public\\/event\\/([a-zA-Z0-9_-]{3,50})(?:\\/.*)?$/);\n return match ? match[1] : null;\n}\n"],"mappings":"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","names":["useMemo","useMemo","useEffect","useEffect","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","error","useEffect","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","useEffect"]}
@@ -25,7 +25,7 @@ import {
25
25
  SelectSeparator,
26
26
  SelectTrigger,
27
27
  SelectValue
28
- } from "./chunk-EVVRUGQ2.js";
28
+ } from "./chunk-62AVH7CM.js";
29
29
  import {
30
30
  isPermitted,
31
31
  isSuperAdmin
@@ -44,7 +44,7 @@ import {
44
44
  useIsPublicPage,
45
45
  usePublicFileDisplay,
46
46
  usePublicPageContext
47
- } from "./chunk-SZWRW5FD.js";
47
+ } from "./chunk-B6LDHZGA.js";
48
48
  import {
49
49
  useToast
50
50
  } from "./chunk-QPCAGLUS.js";
@@ -3608,166 +3608,6 @@ function FileDisplay({
3608
3608
  );
3609
3609
  }
3610
3610
 
3611
- // src/hooks/useEventLogo.ts
3612
- import { useState as useState13, useEffect as useEffect9, useCallback as useCallback9, useMemo as useMemo10 } from "react";
3613
- function defaultGenerateFallbackText2(eventName) {
3614
- if (!eventName) return "EV";
3615
- return eventName.split(" ").map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
3616
- }
3617
- var authenticatedLogoCache = /* @__PURE__ */ new Map();
3618
- var MAX_CACHE_SIZE = 100;
3619
- function cleanupCache() {
3620
- const now = Date.now();
3621
- const entries = Array.from(authenticatedLogoCache.entries());
3622
- entries.forEach(([key, value]) => {
3623
- if (now - value.timestamp > value.ttl) {
3624
- authenticatedLogoCache.delete(key);
3625
- }
3626
- });
3627
- if (authenticatedLogoCache.size > MAX_CACHE_SIZE) {
3628
- const sortedEntries = Array.from(authenticatedLogoCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
3629
- const toRemove = sortedEntries.slice(0, authenticatedLogoCache.size - MAX_CACHE_SIZE);
3630
- toRemove.forEach(([key]) => authenticatedLogoCache.delete(key));
3631
- }
3632
- }
3633
- function useEventLogo(supabase, eventId, eventName, organisationId, options = {}) {
3634
- const {
3635
- cacheTtl = 30 * 60 * 1e3,
3636
- // 30 minutes
3637
- enableCache = true,
3638
- validateImage = true,
3639
- generateFallbackText = defaultGenerateFallbackText2
3640
- } = options;
3641
- const [logoUrl, setLogoUrl] = useState13(null);
3642
- const [isLoading, setIsLoading] = useState13(false);
3643
- const [error, setError] = useState13(null);
3644
- const fallbackText = useMemo10(() => {
3645
- return eventName ? generateFallbackText(eventName) : "EV";
3646
- }, [eventName, generateFallbackText]);
3647
- const fetchLogo = useCallback9(async () => {
3648
- if (!eventId || !organisationId || !supabase) {
3649
- setLogoUrl(null);
3650
- setIsLoading(false);
3651
- return;
3652
- }
3653
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3654
- if (!uuidRegex.test(organisationId)) {
3655
- console.warn("[useEventLogo] Invalid organisationId format (not a valid UUID):", organisationId);
3656
- }
3657
- const cacheKey = `event_logo_${eventId}_${organisationId}`;
3658
- if (enableCache) {
3659
- const cached = authenticatedLogoCache.get(cacheKey);
3660
- if (cached && Date.now() - cached.timestamp < cached.ttl) {
3661
- setLogoUrl(cached.data);
3662
- setIsLoading(false);
3663
- setError(null);
3664
- return;
3665
- }
3666
- }
3667
- try {
3668
- setIsLoading(true);
3669
- setError(null);
3670
- const service = createFileReferenceService(supabase);
3671
- const files = await service.getFilesByCategory(
3672
- "event",
3673
- eventId,
3674
- "event_logos" /* EVENT_LOGOS */,
3675
- organisationId
3676
- );
3677
- if (!files || files.length === 0) {
3678
- setLogoUrl(null);
3679
- return;
3680
- }
3681
- const logoFileRef = files[0];
3682
- const logoPath = logoFileRef.file_path;
3683
- const isPublic = logoFileRef.is_public ?? true;
3684
- let url = null;
3685
- if (isPublic) {
3686
- url = getPublicUrl(supabase, logoPath, true);
3687
- } else {
3688
- const signedUrlResult = await getSignedUrl(supabase, logoPath, {
3689
- appName: "pace-core",
3690
- orgId: organisationId,
3691
- expiresIn: 3600
3692
- });
3693
- url = signedUrlResult?.url || null;
3694
- }
3695
- if (!url) {
3696
- setLogoUrl(null);
3697
- return;
3698
- }
3699
- if (validateImage) {
3700
- try {
3701
- const response = await fetch(url, { method: "HEAD" });
3702
- if (!response.ok) {
3703
- console.warn("[useEventLogo] Logo URL not accessible:", url);
3704
- setLogoUrl(null);
3705
- return;
3706
- }
3707
- } catch (fetchError) {
3708
- console.warn("[useEventLogo] Error validating logo URL:", fetchError);
3709
- setLogoUrl(null);
3710
- return;
3711
- }
3712
- }
3713
- setLogoUrl(url);
3714
- if (enableCache) {
3715
- authenticatedLogoCache.set(cacheKey, {
3716
- data: url,
3717
- timestamp: Date.now(),
3718
- ttl: cacheTtl
3719
- });
3720
- cleanupCache();
3721
- }
3722
- } catch (err) {
3723
- console.error("[useEventLogo] Error fetching logo:", err);
3724
- const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
3725
- setError(error2);
3726
- setLogoUrl(null);
3727
- } finally {
3728
- setIsLoading(false);
3729
- }
3730
- }, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
3731
- useEffect9(() => {
3732
- if (eventId && organisationId && supabase) {
3733
- fetchLogo();
3734
- } else {
3735
- setLogoUrl(null);
3736
- setIsLoading(false);
3737
- setError(null);
3738
- }
3739
- }, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
3740
- const refetch = useCallback9(async () => {
3741
- if (!eventId || !organisationId || !supabase) return;
3742
- if (enableCache) {
3743
- const cacheKey = `event_logo_${eventId}_${organisationId}`;
3744
- authenticatedLogoCache.delete(cacheKey);
3745
- }
3746
- await fetchLogo();
3747
- }, [fetchLogo, eventId, organisationId, supabase, enableCache]);
3748
- return {
3749
- logoUrl,
3750
- fallbackText,
3751
- isLoading,
3752
- error,
3753
- refetch
3754
- };
3755
- }
3756
- function clearEventLogoCache() {
3757
- for (const [key] of authenticatedLogoCache) {
3758
- if (key.startsWith("event_logo_")) {
3759
- authenticatedLogoCache.delete(key);
3760
- }
3761
- }
3762
- }
3763
- function getEventLogoCacheStats() {
3764
- const keys = Array.from(authenticatedLogoCache.keys()).filter((key) => key.startsWith("event_logo_"));
3765
- return {
3766
- size: keys.length,
3767
- keys
3768
- };
3769
- }
3770
-
3771
3611
  // src/components/Table/Table.tsx
3772
3612
  import * as React19 from "react";
3773
3613
  import { jsx as jsx23 } from "react/jsx-runtime";
@@ -4015,7 +3855,7 @@ function PublicLoadingSkeleton({
4015
3855
  }
4016
3856
 
4017
3857
  // src/components/PublicLayout/PublicPageLayout.tsx
4018
- import { useMemo as useMemo11 } from "react";
3858
+ import { useMemo as useMemo10 } from "react";
4019
3859
  import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
4020
3860
  function PublicPageLayout({
4021
3861
  eventCode,
@@ -4033,7 +3873,7 @@ function PublicPageLayout({
4033
3873
  const error = null;
4034
3874
  const refetch = async () => {
4035
3875
  };
4036
- const layoutClasses = useMemo11(() => {
3876
+ const layoutClasses = useMemo10(() => {
4037
3877
  const baseClasses = "min-h-screen bg-white flex flex-col";
4038
3878
  return `${baseClasses} ${className}`.trim();
4039
3879
  }, [className]);
@@ -4098,10 +3938,10 @@ function usePublicPageContext2() {
4098
3938
  }
4099
3939
 
4100
3940
  // src/components/PublicLayout/PublicPageDebugger.tsx
4101
- import { useEffect as useEffect10 } from "react";
3941
+ import { useEffect as useEffect9 } from "react";
4102
3942
  import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
4103
3943
  function PublicPageDebugger({ enabled = true, label = "PublicPage" }) {
4104
- useEffect10(() => {
3944
+ useEffect9(() => {
4105
3945
  if (!enabled) return;
4106
3946
  console.log(`[${label}] Component mounted`);
4107
3947
  try {
@@ -4159,10 +3999,10 @@ function PublicPageDebugger({ enabled = true, label = "PublicPage" }) {
4159
3999
  }
4160
4000
 
4161
4001
  // src/components/PublicLayout/PublicPageDiagnostic.tsx
4162
- import { useEffect as useEffect11, useState as useState14 } from "react";
4002
+ import { useEffect as useEffect10, useState as useState13 } from "react";
4163
4003
  import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
4164
4004
  function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
4165
- const [diagnostics, setDiagnostics] = useState14({
4005
+ const [diagnostics, setDiagnostics] = useState13({
4166
4006
  hasPublicPageContext: false,
4167
4007
  hasAuthContext: false,
4168
4008
  hasOrgContext: false,
@@ -4170,7 +4010,7 @@ function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
4170
4010
  hasEnvironmentVars: false,
4171
4011
  routeParams: null
4172
4012
  });
4173
- useEffect11(() => {
4013
+ useEffect10(() => {
4174
4014
  if (!enabled) return;
4175
4015
  const runDiagnostics = () => {
4176
4016
  const newDiagnostics = {
@@ -4284,10 +4124,10 @@ function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
4284
4124
  }
4285
4125
 
4286
4126
  // src/components/PublicLayout/PublicPageContextChecker.tsx
4287
- import { useEffect as useEffect12 } from "react";
4127
+ import { useEffect as useEffect11 } from "react";
4288
4128
  import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
4289
4129
  function PublicPageContextChecker({ enabled = true, label = "PublicPage" }) {
4290
- useEffect12(() => {
4130
+ useEffect11(() => {
4291
4131
  if (!enabled) return;
4292
4132
  console.group(`\u{1F6A8} [${label}] PUBLIC PAGE CONTEXT CHECK`);
4293
4133
  try {
@@ -4406,9 +4246,6 @@ export {
4406
4246
  useFilesByCategory,
4407
4247
  FileUpload,
4408
4248
  FileDisplay,
4409
- useEventLogo,
4410
- clearEventLogoCache,
4411
- getEventLogoCacheStats,
4412
4249
  Table,
4413
4250
  TableHeader,
4414
4251
  TableBody,
@@ -4428,4 +4265,4 @@ export {
4428
4265
  PublicPageDiagnostic,
4429
4266
  PublicPageContextChecker
4430
4267
  };
4431
- //# sourceMappingURL=chunk-UDWTCBSH.js.map
4268
+ //# sourceMappingURL=chunk-SF6VFEWO.js.map