@jmruthers/pace-core 0.5.101 → 0.5.103

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 (152) hide show
  1. package/dist/{DataTable-DXELRJIX.js → DataTable-EEDFYMJP.js} +2 -2
  2. package/dist/{PublicLoadingSpinner-C2h8zg67.d.ts → PublicLoadingSpinner-48ewSMKK.d.ts} +22 -150
  3. package/dist/{chunk-2ZYHCFUO.js → chunk-5SGBVBRU.js} +2 -2
  4. package/dist/{chunk-EVVRUGQ2.js → chunk-62AVH7CM.js} +78 -55
  5. package/dist/{chunk-EVVRUGQ2.js.map → chunk-62AVH7CM.js.map} +1 -1
  6. package/dist/{chunk-A5DFMP3O.js → chunk-SZWCMVTQ.js} +135 -669
  7. package/dist/chunk-SZWCMVTQ.js.map +1 -0
  8. package/dist/{chunk-MKMKUCPF.js → chunk-X33A4WWI.js} +42 -141
  9. package/dist/chunk-X33A4WWI.js.map +1 -0
  10. package/dist/components.d.ts +1 -1
  11. package/dist/components.js +3 -15
  12. package/dist/components.js.map +1 -1
  13. package/dist/hooks.d.ts +1 -1
  14. package/dist/hooks.js +2 -9
  15. package/dist/hooks.js.map +1 -1
  16. package/dist/index.d.ts +3 -2
  17. package/dist/index.js +4 -22
  18. package/dist/index.js.map +1 -1
  19. package/dist/types.js +3 -3
  20. package/dist/{usePublicRouteParams-BwMR2uub.d.ts → usePublicRouteParams-BiXgKiYa.d.ts} +1 -117
  21. package/dist/utils.js +1 -1
  22. package/docs/api/classes/ColumnFactory.md +1 -1
  23. package/docs/api/classes/ErrorBoundary.md +1 -1
  24. package/docs/api/classes/InvalidScopeError.md +1 -1
  25. package/docs/api/classes/MissingUserContextError.md +1 -1
  26. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  27. package/docs/api/classes/PermissionDeniedError.md +1 -1
  28. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  29. package/docs/api/classes/RBACAuditManager.md +1 -1
  30. package/docs/api/classes/RBACCache.md +1 -1
  31. package/docs/api/classes/RBACEngine.md +1 -1
  32. package/docs/api/classes/RBACError.md +1 -1
  33. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  34. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  35. package/docs/api/classes/StorageUtils.md +2 -1
  36. package/docs/api/enums/FileCategory.md +1 -1
  37. package/docs/api/interfaces/AggregateConfig.md +1 -1
  38. package/docs/api/interfaces/ButtonProps.md +1 -1
  39. package/docs/api/interfaces/CardProps.md +1 -1
  40. package/docs/api/interfaces/ColorPalette.md +1 -1
  41. package/docs/api/interfaces/ColorShade.md +1 -1
  42. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  43. package/docs/api/interfaces/DataRecord.md +1 -1
  44. package/docs/api/interfaces/DataTableAction.md +1 -1
  45. package/docs/api/interfaces/DataTableColumn.md +1 -1
  46. package/docs/api/interfaces/DataTableProps.md +1 -1
  47. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  48. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  49. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  50. package/docs/api/interfaces/FileDisplayProps.md +77 -35
  51. package/docs/api/interfaces/FileMetadata.md +1 -1
  52. package/docs/api/interfaces/FileReference.md +1 -1
  53. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  54. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  55. package/docs/api/interfaces/FileUploadProps.md +1 -1
  56. package/docs/api/interfaces/FooterProps.md +1 -1
  57. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  58. package/docs/api/interfaces/InputProps.md +1 -1
  59. package/docs/api/interfaces/LabelProps.md +1 -1
  60. package/docs/api/interfaces/LoginFormProps.md +1 -1
  61. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  62. package/docs/api/interfaces/NavigationContextType.md +1 -1
  63. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  64. package/docs/api/interfaces/NavigationItem.md +1 -1
  65. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  66. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  67. package/docs/api/interfaces/Organisation.md +1 -1
  68. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  69. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  70. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  71. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  72. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  73. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  74. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  75. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  76. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  77. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  78. package/docs/api/interfaces/PaletteData.md +1 -1
  79. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  80. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  81. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  82. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  83. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  84. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  85. package/docs/api/interfaces/PublicPageHeaderProps.md +11 -24
  86. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  87. package/docs/api/interfaces/RBACConfig.md +1 -1
  88. package/docs/api/interfaces/RBACLogger.md +1 -1
  89. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  90. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  91. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  92. package/docs/api/interfaces/RouteConfig.md +1 -1
  93. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  94. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  95. package/docs/api/interfaces/StorageConfig.md +1 -1
  96. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  97. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  98. package/docs/api/interfaces/StorageListOptions.md +1 -1
  99. package/docs/api/interfaces/StorageListResult.md +1 -1
  100. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  101. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  102. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  103. package/docs/api/interfaces/StyleImport.md +1 -1
  104. package/docs/api/interfaces/SwitchProps.md +1 -1
  105. package/docs/api/interfaces/ToastActionElement.md +1 -1
  106. package/docs/api/interfaces/ToastProps.md +1 -1
  107. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  108. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  109. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  110. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  111. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  112. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  113. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  114. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  115. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  116. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  117. package/docs/api/interfaces/UseResolvedScopeReturn.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 +29 -244
  122. package/docs/implementation-guides/file-reference-system.md +84 -21
  123. package/package.json +1 -1
  124. package/src/components/DataTable/components/DataTableCore.tsx +23 -13
  125. package/src/components/DataTable/hooks/useTableColumns.ts +36 -6
  126. package/src/components/FileDisplay/FileDisplay.test.tsx +1 -1
  127. package/src/components/FileDisplay/FileDisplay.tsx +189 -300
  128. package/src/components/PublicLayout/PublicPageHeader.tsx +15 -10
  129. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +25 -35
  130. package/src/components/PublicLayout/index.ts +2 -5
  131. package/src/components/Toast/Toast.tsx +1 -1
  132. package/src/components/index.ts +0 -2
  133. package/src/examples/PublicEventPage.tsx +17 -7
  134. package/src/examples/PublicPageApp.tsx +18 -8
  135. package/src/hooks/public/index.ts +2 -4
  136. package/src/hooks/useFileReference.ts +10 -1
  137. package/src/index.ts +0 -2
  138. package/src/utils/file-reference.ts +54 -9
  139. package/src/utils/storage/README.md +22 -20
  140. package/src/utils/storage/helpers.ts +12 -1
  141. package/dist/chunk-A5DFMP3O.js.map +0 -1
  142. package/dist/chunk-MKMKUCPF.js.map +0 -1
  143. package/docs/api/interfaces/EventLogoProps.md +0 -152
  144. package/docs/api/interfaces/UseEventLogoOptions.md +0 -74
  145. package/docs/api/interfaces/UseEventLogoReturn.md +0 -81
  146. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  147. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  148. package/src/components/PublicLayout/EventLogo.tsx +0 -474
  149. package/src/hooks/public/usePublicEventLogo.ts +0 -295
  150. package/src/hooks/useEventLogo.ts +0 -316
  151. /package/dist/{DataTable-DXELRJIX.js.map → DataTable-EEDFYMJP.js.map} +0 -0
  152. /package/dist/{chunk-2ZYHCFUO.js.map → chunk-5SGBVBRU.js.map} +0 -0
@@ -1,87 +0,0 @@
1
- [@jmruthers/pace-core - v0.5.101](../README.md) / [Exports](../modules.md) / UsePublicEventLogoOptions
2
-
3
- # Interface: UsePublicEventLogoOptions
4
-
5
- ## Table of contents
6
-
7
- ### Properties
8
-
9
- - [cacheTtl](UsePublicEventLogoOptions.md#cachettl)
10
- - [enableCache](UsePublicEventLogoOptions.md#enablecache)
11
- - [validateImage](UsePublicEventLogoOptions.md#validateimage)
12
- - [generateFallbackText](UsePublicEventLogoOptions.md#generatefallbacktext)
13
- - [supabase](UsePublicEventLogoOptions.md#supabase)
14
-
15
- ## Properties
16
-
17
- ### cacheTtl
18
-
19
- • `Optional` **cacheTtl**: `number`
20
-
21
- Cache TTL in milliseconds (default: 30 minutes)
22
-
23
- #### Defined in
24
-
25
- [packages/core/src/hooks/public/usePublicEventLogo.ts:91](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L91)
26
-
27
- ___
28
-
29
- ### enableCache
30
-
31
- • `Optional` **enableCache**: `boolean`
32
-
33
- Whether to enable caching (default: true)
34
-
35
- #### Defined in
36
-
37
- [packages/core/src/hooks/public/usePublicEventLogo.ts:93](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L93)
38
-
39
- ___
40
-
41
- ### validateImage
42
-
43
- • `Optional` **validateImage**: `boolean`
44
-
45
- Whether to validate image existence (default: true)
46
-
47
- #### Defined in
48
-
49
- [packages/core/src/hooks/public/usePublicEventLogo.ts:95](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L95)
50
-
51
- ___
52
-
53
- ### generateFallbackText
54
-
55
- • `Optional` **generateFallbackText**: (`eventName`: `string`) => `string`
56
-
57
- Custom fallback text generator
58
-
59
- #### Type declaration
60
-
61
- ▸ (`eventName`): `string`
62
-
63
- ##### Parameters
64
-
65
- | Name | Type |
66
- | :------ | :------ |
67
- | `eventName` | `string` |
68
-
69
- ##### Returns
70
-
71
- `string`
72
-
73
- #### Defined in
74
-
75
- [packages/core/src/hooks/public/usePublicEventLogo.ts:97](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L97)
76
-
77
- ___
78
-
79
- ### supabase
80
-
81
- • **supabase**: `default`\<`Database`, ``"public"``, ``"public"``, `never`, {}\>
82
-
83
- Supabase client instance (required)
84
-
85
- #### Defined in
86
-
87
- [packages/core/src/hooks/public/usePublicEventLogo.ts:99](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L99)
@@ -1,81 +0,0 @@
1
- [@jmruthers/pace-core - v0.5.101](../README.md) / [Exports](../modules.md) / UsePublicEventLogoReturn
2
-
3
- # Interface: UsePublicEventLogoReturn
4
-
5
- ## Table of contents
6
-
7
- ### Properties
8
-
9
- - [logoUrl](UsePublicEventLogoReturn.md#logourl)
10
- - [fallbackText](UsePublicEventLogoReturn.md#fallbacktext)
11
- - [isLoading](UsePublicEventLogoReturn.md#isloading)
12
- - [error](UsePublicEventLogoReturn.md#error)
13
- - [refetch](UsePublicEventLogoReturn.md#refetch)
14
-
15
- ## Properties
16
-
17
- ### logoUrl
18
-
19
- • **logoUrl**: ``null`` \| `string`
20
-
21
- The logo URL if available, null if not found or error
22
-
23
- #### Defined in
24
-
25
- [packages/core/src/hooks/public/usePublicEventLogo.ts:78](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L78)
26
-
27
- ___
28
-
29
- ### fallbackText
30
-
31
- • **fallbackText**: `string`
32
-
33
- Fallback text (event initials) if no logo is available
34
-
35
- #### Defined in
36
-
37
- [packages/core/src/hooks/public/usePublicEventLogo.ts:80](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L80)
38
-
39
- ___
40
-
41
- ### isLoading
42
-
43
- • **isLoading**: `boolean`
44
-
45
- Whether the logo is currently loading
46
-
47
- #### Defined in
48
-
49
- [packages/core/src/hooks/public/usePublicEventLogo.ts:82](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L82)
50
-
51
- ___
52
-
53
- ### error
54
-
55
- • **error**: ``null`` \| `Error`
56
-
57
- Any error that occurred during loading
58
-
59
- #### Defined in
60
-
61
- [packages/core/src/hooks/public/usePublicEventLogo.ts:84](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L84)
62
-
63
- ___
64
-
65
- ### refetch
66
-
67
- • **refetch**: () => `Promise`\<`void`\>
68
-
69
- Function to manually refetch the logo
70
-
71
- #### Type declaration
72
-
73
- ▸ (): `Promise`\<`void`\>
74
-
75
- ##### Returns
76
-
77
- `Promise`\<`void`\>
78
-
79
- #### Defined in
80
-
81
- [packages/core/src/hooks/public/usePublicEventLogo.ts:86](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/hooks/public/usePublicEventLogo.ts#L86)
@@ -1,474 +0,0 @@
1
- /**
2
- * @file Event Logo Component
3
- * @package @jmruthers/pace-core
4
- * @module Components/PublicLayout
5
- * @since 1.0.0
6
- *
7
- * A context-aware component for displaying event logos with automatic fallback to event initials.
8
- * Automatically detects whether it's being used in a public or authenticated context and behaves
9
- * appropriately without triggering authentication context leakage.
10
- *
11
- * Features:
12
- * - Context-aware (works in both public and authenticated contexts)
13
- * - Automatic fallback to event initials
14
- * - Logo validation and error handling
15
- * - Multiple size options
16
- * - Responsive design
17
- * - Accessibility compliant
18
- * - TypeScript support
19
- *
20
- * @example
21
- * ```tsx
22
- * import { EventLogo } from '@jmruthers/pace-core';
23
- *
24
- * function EventHeader() {
25
- * return (
26
- * <EventLogo
27
- * eventId={event.id}
28
- * eventName={event.event_name}
29
- * organisationId={event.organisation_id}
30
- * size="lg"
31
- * className="rounded-full"
32
- * />
33
- * );
34
- * }
35
- * ```
36
- *
37
- * @accessibility
38
- * - WCAG 2.1 AA compliant
39
- * - Proper alt text for images
40
- * - Screen reader friendly fallbacks
41
- * - High contrast support
42
- *
43
- * @dependencies
44
- * - React 18+ - Component framework
45
- * - usePublicEventLogo hook - Logo data access
46
- * - Tailwind CSS - Styling
47
- */
48
-
49
- import React, { useMemo, useContext } from 'react';
50
- import { usePublicEventLogo } from '../../hooks/public/usePublicEventLogo';
51
- import { useEventLogo } from '../../hooks/useEventLogo';
52
- import { PublicPageContext, useIsPublicPage } from './PublicPageProvider';
53
- import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
54
- import type { SupabaseClient } from '@supabase/supabase-js';
55
- import type { Database } from '../../types/database';
56
-
57
- export interface EventLogoProps {
58
- /** The event ID to fetch logo for */
59
- eventId: string;
60
- /** The event name for fallback text generation */
61
- eventName: string;
62
- /** The organisation ID for storage path */
63
- organisationId: string;
64
- /** Logo size variant */
65
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
66
- /** Custom CSS classes */
67
- className?: string;
68
- /** Whether to show fallback text when no logo is available */
69
- showFallback?: boolean;
70
- /** Custom fallback text generator */
71
- generateFallbackText?: (eventName: string) => string;
72
- /** Whether to validate image existence */
73
- validateImage?: boolean;
74
- /** Custom loading component */
75
- loadingComponent?: React.ComponentType;
76
- /** Custom error component */
77
- errorComponent?: React.ComponentType<{ error: Error }>;
78
- }
79
-
80
- /**
81
- * Size classes for different logo sizes
82
- */
83
- const sizeClasses = {
84
- xs: 'h-4 w-4 text-xs',
85
- sm: 'h-6 w-6 text-sm',
86
- md: 'h-8 w-8 text-base',
87
- lg: 'h-12 w-12 text-lg',
88
- xl: 'h-16 w-16 text-xl',
89
- '2xl': 'h-20 w-20 text-2xl'
90
- };
91
-
92
- /**
93
- * Default fallback text generator
94
- */
95
- function defaultGenerateFallbackText(eventName: string): string {
96
- if (!eventName) return 'EV';
97
-
98
- return eventName
99
- .split(' ')
100
- .map(word => word.charAt(0).toUpperCase())
101
- .join('')
102
- .substring(0, 3); // Max 3 characters
103
- }
104
-
105
- /**
106
- * Component for displaying event logos with fallback to initials
107
- *
108
- * This component is context-aware and automatically detects whether it's being used
109
- * in a public or authenticated context. It fetches and displays event logos from storage,
110
- * with automatic fallback to event initials if no logo is available.
111
- *
112
- * @param props - Logo configuration and styling
113
- * @returns React element with event logo or fallback
114
- */
115
- /**
116
- * Internal component for public page context
117
- * Uses PublicPageContext to get Supabase client
118
- */
119
- function EventLogoPublic({
120
- eventId,
121
- eventName,
122
- organisationId,
123
- size,
124
- className,
125
- showFallback,
126
- generateFallbackText,
127
- validateImage,
128
- LoadingComponent,
129
- ErrorComponent
130
- }: EventLogoProps & { LoadingComponent?: React.ComponentType; ErrorComponent?: React.ComponentType<{ error: Error }> }) {
131
- const publicPageContext = useContext(PublicPageContext);
132
- const supabase = publicPageContext?.supabase ?? null;
133
-
134
- // Validate UUID format for organisationId to prevent database errors
135
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
136
- const hasValidOrganisationId = organisationId && uuidRegex.test(organisationId);
137
-
138
- // If no Supabase client is available, show fallback immediately
139
- if (!supabase) {
140
- const effectiveSize = size || 'md';
141
- return (
142
- <div className={`${sizeClasses[effectiveSize]} ${className}`.trim()} title={`${eventName} logo (Supabase not configured)`}>
143
- {eventName ? defaultGenerateFallbackText(eventName) : 'EV'}
144
- </div>
145
- );
146
- }
147
-
148
- const {
149
- logoUrl,
150
- fallbackText,
151
- isLoading,
152
- error
153
- } = usePublicEventLogo(
154
- eventId,
155
- eventName,
156
- organisationId, // Always pass organisationId, let the hook handle validation
157
- {
158
- validateImage,
159
- generateFallbackText,
160
- supabase
161
- }
162
- );
163
-
164
- // Memoize the size classes - provide default 'md' if size is undefined
165
- const sizeClass = useMemo(() => sizeClasses[size || 'md'], [size]);
166
-
167
- // Memoize the combined classes
168
- const combinedClasses = useMemo(() => {
169
- const baseClasses = 'flex items-center justify-center bg-gray-100 text-gray-600 font-semibold rounded';
170
- return `${baseClasses} ${sizeClass} ${className}`.trim();
171
- }, [sizeClass, className]);
172
-
173
- // Handle invalid organisation ID - show fallback immediately only if we have no data
174
- if (!hasValidOrganisationId && !isLoading && !logoUrl && showFallback) {
175
- return (
176
- <div className={combinedClasses} title={`${eventName} logo (invalid organisation ID)`}>
177
- {fallbackText}
178
- </div>
179
- );
180
- }
181
-
182
- // Handle loading state
183
- if (isLoading) {
184
- if (LoadingComponent) {
185
- return <LoadingComponent />;
186
- }
187
-
188
- return (
189
- <div className={`${combinedClasses} animate-pulse`}>
190
- <div className="w-3/4 h-3/4 bg-gray-300 rounded"></div>
191
- </div>
192
- );
193
- }
194
-
195
- // Handle error state
196
- if (error) {
197
- if (ErrorComponent) {
198
- return <ErrorComponent error={error} />;
199
- }
200
-
201
- if (showFallback) {
202
- return (
203
- <div className={combinedClasses} title={`${eventName} (logo unavailable)`}>
204
- {fallbackText}
205
- </div>
206
- );
207
- }
208
-
209
- return null;
210
- }
211
-
212
- // Handle no logo available
213
- if (!logoUrl) {
214
- if (showFallback) {
215
- return (
216
- <div className={combinedClasses} title={`${eventName} logo`}>
217
- {fallbackText}
218
- </div>
219
- );
220
- }
221
-
222
- return null;
223
- }
224
-
225
- // Render the actual logo
226
- // Apply object-contain to maintain aspect ratio and rounded to match fallback styling
227
- const imageClasses = `${sizeClass} object-contain rounded ${className}`.trim();
228
-
229
- return (
230
- <img
231
- src={logoUrl}
232
- alt={`${eventName} logo`}
233
- className={imageClasses}
234
- onError={(e) => {
235
- // If image fails to load, hide it and show fallback
236
- const target = e.target as HTMLImageElement;
237
- target.style.display = 'none';
238
-
239
- // Create fallback element
240
- const fallback = document.createElement('div');
241
- fallback.className = combinedClasses;
242
- fallback.textContent = fallbackText;
243
- fallback.title = `${eventName} logo`;
244
-
245
- // Insert fallback after the image
246
- target.parentNode?.insertBefore(fallback, target.nextSibling);
247
- }}
248
- />
249
- );
250
- }
251
-
252
- /**
253
- * Internal component for authenticated page context
254
- * Uses UnifiedAuthProvider to get Supabase client
255
- */
256
- function EventLogoAuthenticated({
257
- eventId,
258
- eventName,
259
- organisationId,
260
- size,
261
- className,
262
- showFallback,
263
- generateFallbackText,
264
- validateImage,
265
- LoadingComponent,
266
- ErrorComponent
267
- }: EventLogoProps & { LoadingComponent?: React.ComponentType; ErrorComponent?: React.ComponentType<{ error: Error }> }) {
268
- const { supabase } = useUnifiedAuth();
269
-
270
- // Validate UUID format for organisationId to prevent database errors
271
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
272
- const hasValidOrganisationId = organisationId && uuidRegex.test(organisationId);
273
-
274
- // If no Supabase client is available, show fallback immediately
275
- if (!supabase) {
276
- const effectiveSize = size || 'md';
277
- return (
278
- <div className={`${sizeClasses[effectiveSize]} ${className}`.trim()} title={`${eventName} logo (Supabase not configured)`}>
279
- {eventName ? defaultGenerateFallbackText(eventName) : 'EV'}
280
- </div>
281
- );
282
- }
283
-
284
- // Use the authenticated event logo hook (supports both public and private logos)
285
- const {
286
- logoUrl,
287
- fallbackText,
288
- isLoading,
289
- error
290
- } = useEventLogo(
291
- supabase,
292
- eventId,
293
- eventName,
294
- organisationId,
295
- {
296
- validateImage,
297
- generateFallbackText
298
- }
299
- );
300
-
301
- // Memoize the size classes - provide default 'md' if size is undefined
302
- const sizeClass = useMemo(() => sizeClasses[size || 'md'], [size]);
303
-
304
- // Memoize the combined classes
305
- const combinedClasses = useMemo(() => {
306
- const baseClasses = 'flex items-center justify-center bg-gray-100 text-gray-600 font-semibold rounded';
307
- return `${baseClasses} ${sizeClass} ${className}`.trim();
308
- }, [sizeClass, className]);
309
-
310
- // Handle invalid organisation ID - show fallback immediately only if we have no data
311
- if (!hasValidOrganisationId && !isLoading && !logoUrl && showFallback) {
312
- return (
313
- <div className={combinedClasses} title={`${eventName} logo (invalid organisation ID)`}>
314
- {fallbackText}
315
- </div>
316
- );
317
- }
318
-
319
- // Handle loading state
320
- if (isLoading) {
321
- if (LoadingComponent) {
322
- return <LoadingComponent />;
323
- }
324
-
325
- return (
326
- <div className={`${combinedClasses} animate-pulse`}>
327
- <div className="w-3/4 h-3/4 bg-gray-300 rounded"></div>
328
- </div>
329
- );
330
- }
331
-
332
- // Handle error state
333
- if (error) {
334
- if (ErrorComponent) {
335
- return <ErrorComponent error={error} />;
336
- }
337
-
338
- if (showFallback) {
339
- return (
340
- <div className={combinedClasses} title={`${eventName} (logo unavailable)`}>
341
- {fallbackText}
342
- </div>
343
- );
344
- }
345
-
346
- return null;
347
- }
348
-
349
- // Handle no logo available
350
- if (!logoUrl) {
351
- if (showFallback) {
352
- return (
353
- <div className={combinedClasses} title={`${eventName} logo`}>
354
- {fallbackText}
355
- </div>
356
- );
357
- }
358
-
359
- return null;
360
- }
361
-
362
- // Render the actual logo
363
- // Apply object-contain to maintain aspect ratio and rounded to match fallback styling
364
- const imageClasses = `${sizeClass} object-contain rounded ${className}`.trim();
365
-
366
- return (
367
- <img
368
- src={logoUrl}
369
- alt={`${eventName} logo`}
370
- className={imageClasses}
371
- onError={(e) => {
372
- // If image fails to load, hide it and show fallback
373
- const target = e.target as HTMLImageElement;
374
- target.style.display = 'none';
375
-
376
- // Create fallback element
377
- const fallback = document.createElement('div');
378
- fallback.className = combinedClasses;
379
- fallback.textContent = fallbackText;
380
- fallback.title = `${eventName} logo`;
381
-
382
- // Insert fallback after the image
383
- target.parentNode?.insertBefore(fallback, target.nextSibling);
384
- }}
385
- />
386
- );
387
- }
388
-
389
- /**
390
- * Component for displaying event logos with fallback to initials
391
- *
392
- * This component is context-aware and automatically detects whether it's being used
393
- * in a public or authenticated context. It fetches and displays event logos from storage,
394
- * with automatic fallback to event initials if no logo is available.
395
- *
396
- * @param props - Logo configuration and styling
397
- * @returns React element with event logo or fallback
398
- */
399
- export function EventLogo({
400
- eventId,
401
- eventName,
402
- organisationId,
403
- size = 'md',
404
- className = '',
405
- showFallback = true,
406
- generateFallbackText = defaultGenerateFallbackText,
407
- validateImage = true,
408
- loadingComponent: LoadingComponent,
409
- errorComponent: ErrorComponent
410
- }: EventLogoProps) {
411
- // Check which context we're in and route to the appropriate component
412
- const isPublicPage = useIsPublicPage();
413
-
414
- // If we're in a public page context, use the public component
415
- if (isPublicPage) {
416
- return (
417
- <EventLogoPublic
418
- eventId={eventId}
419
- eventName={eventName}
420
- organisationId={organisationId}
421
- size={size}
422
- className={className}
423
- showFallback={showFallback}
424
- generateFallbackText={generateFallbackText}
425
- validateImage={validateImage}
426
- LoadingComponent={LoadingComponent}
427
- ErrorComponent={ErrorComponent}
428
- />
429
- );
430
- }
431
-
432
- // Otherwise, try to use the authenticated component
433
- // It will throw if not in UnifiedAuthProvider, which will be caught by error boundary
434
- return (
435
- <EventLogoAuthenticated
436
- eventId={eventId}
437
- eventName={eventName}
438
- organisationId={organisationId}
439
- size={size}
440
- className={className}
441
- showFallback={showFallback}
442
- generateFallbackText={generateFallbackText}
443
- validateImage={validateImage}
444
- LoadingComponent={LoadingComponent}
445
- ErrorComponent={ErrorComponent}
446
- />
447
- );
448
- }
449
-
450
- /**
451
- * Compact event logo for small spaces
452
- */
453
- export function EventLogoCompact(props: EventLogoProps) {
454
- return (
455
- <EventLogo
456
- {...props}
457
- size="sm"
458
- className={`${props.className || ''} rounded-sm`}
459
- />
460
- );
461
- }
462
-
463
- /**
464
- * Large event logo for prominent display
465
- */
466
- export function EventLogoLarge(props: EventLogoProps) {
467
- return (
468
- <EventLogo
469
- {...props}
470
- size="xl"
471
- className={`${props.className || ''} rounded-lg`}
472
- />
473
- );
474
- }