@jmruthers/pace-core 0.5.102 → 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 (141) 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-7ME4Z5OY.js → chunk-5SGBVBRU.js} +12 -148
  4. package/dist/chunk-5SGBVBRU.js.map +1 -0
  5. package/dist/{chunk-EVVRUGQ2.js → chunk-62AVH7CM.js} +78 -55
  6. package/dist/{chunk-EVVRUGQ2.js.map → chunk-62AVH7CM.js.map} +1 -1
  7. package/dist/{chunk-UDWTCBSH.js → chunk-SZWCMVTQ.js} +12 -175
  8. package/dist/chunk-SZWCMVTQ.js.map +1 -0
  9. package/dist/{chunk-SZWRW5FD.js → chunk-X33A4WWI.js} +23 -3
  10. package/dist/{chunk-SZWRW5FD.js.map → chunk-X33A4WWI.js.map} +1 -1
  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 +2 -150
  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/index.ts +0 -2
  131. package/src/utils/file-reference.ts +30 -2
  132. package/src/utils/storage/README.md +22 -20
  133. package/dist/chunk-7ME4Z5OY.js.map +0 -1
  134. package/dist/chunk-UDWTCBSH.js.map +0 -1
  135. package/docs/api/interfaces/UseEventLogoOptions.md +0 -74
  136. package/docs/api/interfaces/UseEventLogoReturn.md +0 -81
  137. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  138. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  139. package/src/hooks/public/usePublicEventLogo.ts +0 -295
  140. package/src/hooks/useEventLogo.ts +0 -316
  141. /package/dist/{DataTable-DXELRJIX.js.map → DataTable-EEDFYMJP.js.map} +0 -0
@@ -1,316 +0,0 @@
1
- /**
2
- * @file Event Logo Hook (Authenticated)
3
- * @package @jmruthers/pace-core
4
- * @module Hooks
5
- *
6
- * A React hook for accessing event logos in authenticated contexts.
7
- * Can handle both public and private event logos using the file_references system.
8
- *
9
- * Features:
10
- * - Works in authenticated contexts
11
- * - Supports both public and private event logos
12
- * - Automatic fallback to event initials
13
- * - Bucket-aware URL generation
14
- * - Signed URL support for private files
15
- * - Caching for performance
16
- * - Error handling and loading states
17
- *
18
- * @example
19
- * ```tsx
20
- * import { useEventLogo } from '@jmruthers/pace-core';
21
- *
22
- * function EventHeader() {
23
- * const { logoUrl, fallbackText, isLoading, error } = useEventLogo(
24
- * supabase,
25
- * eventId,
26
- * eventName,
27
- * organisationId
28
- * );
29
- *
30
- * if (isLoading) return <div>Loading...</div>;
31
- * if (error) return <div>Error: {error.message}</div>;
32
- *
33
- * return (
34
- * <div>
35
- * {logoUrl ? (
36
- * <img src={logoUrl} alt={`${eventName} logo`} />
37
- * ) : (
38
- * <div className="logo-fallback">{fallbackText}</div>
39
- * )}
40
- * </div>
41
- * );
42
- * }
43
- * ```
44
- */
45
-
46
- import { useState, useEffect, useCallback, useMemo } from 'react';
47
- import type { SupabaseClient } from '@supabase/supabase-js';
48
- import { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';
49
- import { FileCategory } from '../types/file-reference';
50
- import { createFileReferenceService } from '../utils/file-reference';
51
-
52
- export interface UseEventLogoReturn {
53
- /** The logo URL if available, null if not found or error */
54
- logoUrl: string | null;
55
- /** Fallback text (event initials) if no logo is available */
56
- fallbackText: string;
57
- /** Whether the logo is currently loading */
58
- isLoading: boolean;
59
- /** Any error that occurred during loading */
60
- error: Error | null;
61
- /** Function to manually refetch the logo */
62
- refetch: () => Promise<void>;
63
- }
64
-
65
- export interface UseEventLogoOptions {
66
- /** Cache TTL in milliseconds (default: 30 minutes) */
67
- cacheTtl?: number;
68
- /** Whether to enable caching (default: true) */
69
- enableCache?: boolean;
70
- /** Whether to validate image existence (default: true) */
71
- validateImage?: boolean;
72
- /** Custom fallback text generator */
73
- generateFallbackText?: (eventName: string) => string;
74
- }
75
-
76
- /**
77
- * Generate fallback text from event name (first letter of each word)
78
- */
79
- function defaultGenerateFallbackText(eventName: string): string {
80
- if (!eventName) return 'EV';
81
-
82
- return eventName
83
- .split(' ')
84
- .map(word => word.charAt(0).toUpperCase())
85
- .join('')
86
- .substring(0, 3); // Max 3 characters
87
- }
88
-
89
- // Simple in-memory cache for authenticated event logos
90
- const authenticatedLogoCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
91
-
92
- // Cache size limit to prevent memory leaks
93
- const MAX_CACHE_SIZE = 100;
94
-
95
- // Helper function to clean up expired entries and enforce size limit
96
- function cleanupCache() {
97
- const now = Date.now();
98
- const entries = Array.from(authenticatedLogoCache.entries());
99
-
100
- // Remove expired entries
101
- entries.forEach(([key, value]) => {
102
- if (now - value.timestamp > value.ttl) {
103
- authenticatedLogoCache.delete(key);
104
- }
105
- });
106
-
107
- // If still over limit, remove oldest entries
108
- if (authenticatedLogoCache.size > MAX_CACHE_SIZE) {
109
- const sortedEntries = Array.from(authenticatedLogoCache.entries())
110
- .sort((a, b) => a[1].timestamp - b[1].timestamp);
111
-
112
- const toRemove = sortedEntries.slice(0, authenticatedLogoCache.size - MAX_CACHE_SIZE);
113
- toRemove.forEach(([key]) => authenticatedLogoCache.delete(key));
114
- }
115
- }
116
-
117
- /**
118
- * Hook for accessing event logo URLs in authenticated contexts
119
- *
120
- * This hook provides access to event logo URLs for authenticated users.
121
- * It supports both public and private logos, generating appropriate URLs
122
- * (public URLs for public files, signed URLs for private files).
123
- *
124
- * @param supabase - Supabase client instance (required)
125
- * @param eventId - The event ID to fetch logo for
126
- * @param eventName - The event name for fallback text generation
127
- * @param organisationId - The organisation ID for storage path
128
- * @param options - Configuration options for caching and behavior
129
- * @returns Object containing logo URL, fallback text, loading state, error, and refetch function
130
- */
131
- export function useEventLogo(
132
- supabase: SupabaseClient | null,
133
- eventId: string | undefined,
134
- eventName: string | undefined,
135
- organisationId: string | undefined,
136
- options: UseEventLogoOptions = {}
137
- ): UseEventLogoReturn {
138
- const {
139
- cacheTtl = 30 * 60 * 1000, // 30 minutes
140
- enableCache = true,
141
- validateImage = true,
142
- generateFallbackText = defaultGenerateFallbackText
143
- } = options;
144
-
145
- const [logoUrl, setLogoUrl] = useState<string | null>(null);
146
- const [isLoading, setIsLoading] = useState<boolean>(false);
147
- const [error, setError] = useState<Error | null>(null);
148
-
149
- // Generate fallback text
150
- const fallbackText = useMemo(() => {
151
- return eventName ? generateFallbackText(eventName) : 'EV';
152
- }, [eventName, generateFallbackText]);
153
-
154
- const fetchLogo = useCallback(async (): Promise<void> => {
155
- if (!eventId || !organisationId || !supabase) {
156
- setLogoUrl(null);
157
- setIsLoading(false);
158
- return;
159
- }
160
-
161
- // Validate UUID format for organisationId to prevent database errors
162
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
163
- if (!uuidRegex.test(organisationId)) {
164
- console.warn('[useEventLogo] Invalid organisationId format (not a valid UUID):', organisationId);
165
- // Don't return early - let the database handle the validation
166
- // This allows for more graceful error handling
167
- }
168
-
169
- // Check cache first
170
- const cacheKey = `event_logo_${eventId}_${organisationId}`;
171
- if (enableCache) {
172
- const cached = authenticatedLogoCache.get(cacheKey);
173
- if (cached && Date.now() - cached.timestamp < cached.ttl) {
174
- setLogoUrl(cached.data);
175
- setIsLoading(false);
176
- setError(null);
177
- return;
178
- }
179
- }
180
-
181
- try {
182
- setIsLoading(true);
183
- setError(null);
184
-
185
- // Get event logo from file_references using new RPC function
186
- const service = createFileReferenceService(supabase);
187
- const files = await service.getFilesByCategory(
188
- 'event',
189
- eventId,
190
- FileCategory.EVENT_LOGOS,
191
- organisationId
192
- );
193
-
194
- if (!files || files.length === 0) {
195
- setLogoUrl(null);
196
- return;
197
- }
198
-
199
- // Get the first logo (events typically have one logo)
200
- const logoFileRef = files[0];
201
- const logoPath = logoFileRef.file_path;
202
- const isPublic = logoFileRef.is_public ?? true;
203
-
204
- let url: string | null = null;
205
-
206
- if (isPublic) {
207
- // Public files: generate public URL using bucket-aware helper
208
- url = getPublicUrl(supabase, logoPath, true);
209
- } else {
210
- // Private files: generate signed URL
211
- const signedUrlResult = await getSignedUrl(supabase, logoPath, {
212
- appName: 'pace-core',
213
- orgId: organisationId,
214
- expiresIn: 3600
215
- });
216
- url = signedUrlResult?.url || null;
217
- }
218
-
219
- if (!url) {
220
- setLogoUrl(null);
221
- return;
222
- }
223
-
224
- // Validate image existence if requested
225
- if (validateImage) {
226
- try {
227
- const response = await fetch(url, { method: 'HEAD' });
228
- if (!response.ok) {
229
- console.warn('[useEventLogo] Logo URL not accessible:', url);
230
- setLogoUrl(null);
231
- return;
232
- }
233
- } catch (fetchError) {
234
- console.warn('[useEventLogo] Error validating logo URL:', fetchError);
235
- setLogoUrl(null);
236
- return;
237
- }
238
- }
239
-
240
- setLogoUrl(url);
241
-
242
- // Cache the result
243
- if (enableCache) {
244
- authenticatedLogoCache.set(cacheKey, {
245
- data: url,
246
- timestamp: Date.now(),
247
- ttl: cacheTtl
248
- });
249
- // Clean up cache to prevent memory leaks
250
- cleanupCache();
251
- }
252
-
253
- } catch (err) {
254
- console.error('[useEventLogo] Error fetching logo:', err);
255
- const error = err instanceof Error ? err : new Error('Unknown error occurred');
256
- setError(error);
257
- setLogoUrl(null);
258
- } finally {
259
- setIsLoading(false);
260
- }
261
- }, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
262
-
263
- // Fetch logo when parameters change
264
- useEffect(() => {
265
- if (eventId && organisationId && supabase) {
266
- fetchLogo();
267
- } else {
268
- setLogoUrl(null);
269
- setIsLoading(false);
270
- setError(null);
271
- }
272
- }, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
273
-
274
- const refetch = useCallback(async (): Promise<void> => {
275
- if (!eventId || !organisationId || !supabase) return;
276
-
277
- // Clear cache for this logo
278
- if (enableCache) {
279
- const cacheKey = `event_logo_${eventId}_${organisationId}`;
280
- authenticatedLogoCache.delete(cacheKey);
281
- }
282
- await fetchLogo();
283
- }, [fetchLogo, eventId, organisationId, supabase, enableCache]);
284
-
285
- return {
286
- logoUrl,
287
- fallbackText,
288
- isLoading,
289
- error,
290
- refetch
291
- };
292
- }
293
-
294
- /**
295
- * Clear all cached authenticated event logo data
296
- * Useful for testing or when you need to force refresh all data
297
- */
298
- export function clearEventLogoCache(): void {
299
- for (const [key] of authenticatedLogoCache) {
300
- if (key.startsWith('event_logo_')) {
301
- authenticatedLogoCache.delete(key);
302
- }
303
- }
304
- }
305
-
306
- /**
307
- * Get cache statistics for debugging
308
- */
309
- export function getEventLogoCacheStats(): { size: number; keys: string[] } {
310
- const keys = Array.from(authenticatedLogoCache.keys()).filter(key => key.startsWith('event_logo_'));
311
- return {
312
- size: keys.length,
313
- keys
314
- };
315
- }
316
-