@jmruthers/pace-core 0.5.185 → 0.5.186

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 (205) hide show
  1. package/dist/{PublicPageProvider-BABf6JCh.d.ts → PublicPageProvider-DIzEzwKl.d.ts} +4 -2
  2. package/dist/{chunk-STTZQK2I.js → chunk-DAGICKHT.js} +7 -5
  3. package/dist/chunk-DAGICKHT.js.map +1 -0
  4. package/dist/{chunk-AISXLWGZ.js → chunk-GRIQLQ52.js} +2 -2
  5. package/dist/{chunk-HC67NW5K.js → chunk-HDCUMOOI.js} +125 -47
  6. package/dist/chunk-HDCUMOOI.js.map +1 -0
  7. package/dist/{chunk-OKI34GZD.js → chunk-OALXJH4Y.js} +2 -2
  8. package/dist/{chunk-MX3EIJGQ.js → chunk-TC7D3CR3.js} +86 -7
  9. package/dist/chunk-TC7D3CR3.js.map +1 -0
  10. package/dist/{chunk-IXSNYUCT.js → chunk-UQWSHFVX.js} +1 -1
  11. package/dist/chunk-UQWSHFVX.js.map +1 -0
  12. package/dist/components.d.ts +2 -2
  13. package/dist/components.js +3 -3
  14. package/dist/{database.generated-CBmg2950.d.ts → database.generated-DI89OQeI.d.ts} +63 -9
  15. package/dist/{file-reference-BjR39ktt.d.ts → file-reference-PRTSLxKx.d.ts} +3 -0
  16. package/dist/hooks.d.ts +49 -5
  17. package/dist/hooks.js +6 -4
  18. package/dist/hooks.js.map +1 -1
  19. package/dist/index.d.ts +5 -5
  20. package/dist/index.js +9 -8
  21. package/dist/index.js.map +1 -1
  22. package/dist/rbac/index.d.ts +1 -1
  23. package/dist/rbac/index.js +2 -2
  24. package/dist/types.d.ts +2 -2
  25. package/dist/types.js +1 -1
  26. package/dist/{usePublicRouteParams-CvnC3d-e.d.ts → usePublicRouteParams-D71QLlg4.d.ts} +2 -2
  27. package/dist/utils.d.ts +1 -1
  28. package/docs/api/classes/ColumnFactory.md +1 -1
  29. package/docs/api/classes/ErrorBoundary.md +1 -1
  30. package/docs/api/classes/InvalidScopeError.md +1 -1
  31. package/docs/api/classes/Logger.md +1 -1
  32. package/docs/api/classes/MissingUserContextError.md +1 -1
  33. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  34. package/docs/api/classes/PermissionDeniedError.md +1 -1
  35. package/docs/api/classes/RBACAuditManager.md +2 -2
  36. package/docs/api/classes/RBACCache.md +1 -1
  37. package/docs/api/classes/RBACEngine.md +2 -2
  38. package/docs/api/classes/RBACError.md +1 -1
  39. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  40. package/docs/api/classes/SecureSupabaseClient.md +5 -5
  41. package/docs/api/classes/StorageUtils.md +1 -1
  42. package/docs/api/enums/FileCategory.md +1 -1
  43. package/docs/api/enums/LogLevel.md +1 -1
  44. package/docs/api/enums/RBACErrorCode.md +1 -1
  45. package/docs/api/enums/RPCFunction.md +1 -1
  46. package/docs/api/interfaces/AggregateConfig.md +1 -1
  47. package/docs/api/interfaces/BadgeProps.md +1 -1
  48. package/docs/api/interfaces/ButtonProps.md +1 -1
  49. package/docs/api/interfaces/CalendarProps.md +1 -1
  50. package/docs/api/interfaces/CardProps.md +1 -1
  51. package/docs/api/interfaces/ColorPalette.md +1 -1
  52. package/docs/api/interfaces/ColorShade.md +1 -1
  53. package/docs/api/interfaces/ComplianceResult.md +1 -1
  54. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  55. package/docs/api/interfaces/DataRecord.md +1 -1
  56. package/docs/api/interfaces/DataTableAction.md +1 -1
  57. package/docs/api/interfaces/DataTableColumn.md +1 -1
  58. package/docs/api/interfaces/DataTableProps.md +1 -1
  59. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  60. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  61. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  62. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  63. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  64. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  65. package/docs/api/interfaces/ExportColumn.md +1 -1
  66. package/docs/api/interfaces/ExportOptions.md +1 -1
  67. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  68. package/docs/api/interfaces/FileMetadata.md +1 -1
  69. package/docs/api/interfaces/FileReference.md +1 -1
  70. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  71. package/docs/api/interfaces/FileUploadOptions.md +33 -9
  72. package/docs/api/interfaces/FileUploadProps.md +36 -14
  73. package/docs/api/interfaces/FooterProps.md +1 -1
  74. package/docs/api/interfaces/FormFieldProps.md +1 -1
  75. package/docs/api/interfaces/FormProps.md +1 -1
  76. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  77. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  78. package/docs/api/interfaces/InputProps.md +1 -1
  79. package/docs/api/interfaces/LabelProps.md +1 -1
  80. package/docs/api/interfaces/LoggerConfig.md +1 -1
  81. package/docs/api/interfaces/LoginFormProps.md +1 -1
  82. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  83. package/docs/api/interfaces/NavigationContextType.md +1 -1
  84. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  85. package/docs/api/interfaces/NavigationItem.md +1 -1
  86. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  87. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  88. package/docs/api/interfaces/Organisation.md +1 -1
  89. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  90. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  91. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  92. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  93. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  94. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  95. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  96. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  97. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  98. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  99. package/docs/api/interfaces/PaletteData.md +1 -1
  100. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  101. package/docs/api/interfaces/ProgressProps.md +1 -1
  102. package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
  103. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  104. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  105. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  106. package/docs/api/interfaces/QuickFix.md +1 -1
  107. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  108. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  109. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  110. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  111. package/docs/api/interfaces/RBACConfig.md +2 -2
  112. package/docs/api/interfaces/RBACContext.md +1 -1
  113. package/docs/api/interfaces/RBACLogger.md +1 -1
  114. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  115. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  116. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  117. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  118. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  119. package/docs/api/interfaces/RBACResult.md +1 -1
  120. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  121. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  122. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  123. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  124. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  125. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  126. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  127. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  128. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  129. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  130. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  131. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  132. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  134. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  135. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  136. package/docs/api/interfaces/RouteConfig.md +1 -1
  137. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  138. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  139. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  140. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  141. package/docs/api/interfaces/SetupIssue.md +1 -1
  142. package/docs/api/interfaces/StorageConfig.md +1 -1
  143. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  144. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  145. package/docs/api/interfaces/StorageListOptions.md +1 -1
  146. package/docs/api/interfaces/StorageListResult.md +1 -1
  147. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  148. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  149. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  150. package/docs/api/interfaces/StyleImport.md +1 -1
  151. package/docs/api/interfaces/SwitchProps.md +1 -1
  152. package/docs/api/interfaces/TabsContentProps.md +1 -1
  153. package/docs/api/interfaces/TabsListProps.md +1 -1
  154. package/docs/api/interfaces/TabsProps.md +1 -1
  155. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  156. package/docs/api/interfaces/TextareaProps.md +1 -1
  157. package/docs/api/interfaces/ToastActionElement.md +1 -1
  158. package/docs/api/interfaces/ToastProps.md +1 -1
  159. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  160. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  161. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  162. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  163. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  164. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  165. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  166. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  167. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  168. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  169. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  170. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  171. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  172. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  173. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  174. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  175. package/docs/api/interfaces/UserEventAccess.md +1 -1
  176. package/docs/api/interfaces/UserMenuProps.md +1 -1
  177. package/docs/api/interfaces/UserProfile.md +1 -1
  178. package/docs/api/modules.md +17 -17
  179. package/docs/api-reference/components.md +26 -12
  180. package/docs/implementation-guides/file-reference-system.md +24 -2
  181. package/docs/implementation-guides/file-upload-storage.md +9 -1
  182. package/package.json +1 -1
  183. package/scripts/check-pace-core-compliance.js +512 -0
  184. package/src/components/FileUpload/FileUpload.test.tsx +2 -0
  185. package/src/components/FileUpload/FileUpload.tsx +7 -1
  186. package/src/components/Header/Header.tsx +2 -5
  187. package/src/components/ProtectedRoute/ProtectedRoute.tsx +134 -1
  188. package/src/hooks/index.ts +3 -0
  189. package/src/hooks/useFileReference.test.ts +1 -0
  190. package/src/hooks/usePreventTabReload.ts +106 -0
  191. package/src/hooks/useSecureDataAccess.ts +2 -2
  192. package/src/rbac/__tests__/rbac-role-isolation.test.ts +456 -0
  193. package/src/styles/core.css +5 -5
  194. package/src/types/database.generated.ts +63 -9
  195. package/src/types/file-reference.ts +3 -0
  196. package/src/utils/file-reference/__tests__/file-reference.test.ts +58 -4
  197. package/src/utils/file-reference/index.ts +12 -2
  198. package/src/utils/security/secureDataAccess.ts +1 -1
  199. package/src/utils/storage/helpers.ts +68 -0
  200. package/dist/chunk-HC67NW5K.js.map +0 -1
  201. package/dist/chunk-IXSNYUCT.js.map +0 -1
  202. package/dist/chunk-MX3EIJGQ.js.map +0 -1
  203. package/dist/chunk-STTZQK2I.js.map +0 -1
  204. /package/dist/{chunk-AISXLWGZ.js.map → chunk-GRIQLQ52.js.map} +0 -0
  205. /package/dist/{chunk-OKI34GZD.js.map → chunk-OALXJH4Y.js.map} +0 -0
@@ -16,7 +16,7 @@ import { z } from 'zod';
16
16
  import { User, SupabaseClient, createClient } from '@supabase/supabase-js';
17
17
  import { P as Permission, A as AccessLevel } from './types-UU913iLA.js';
18
18
  import { E as Event, O as Organisation } from './event-CW5YB_2p.js';
19
- import { F as FileCategory, e as FileUploadResult, U as UploadProgress, c as FileUploadOptions, a as FileReference } from './file-reference-BjR39ktt.js';
19
+ import { F as FileCategory, e as FileUploadResult, U as UploadProgress, c as FileUploadOptions, a as FileReference } from './file-reference-PRTSLxKx.js';
20
20
 
21
21
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
22
22
  /** Visual variant of the button */
@@ -3496,7 +3496,9 @@ interface FileUploadProps {
3496
3496
  organisation_id: string;
3497
3497
  app_id?: string;
3498
3498
  category: FileCategory;
3499
+ folder: string;
3499
3500
  pageContext: string;
3501
+ event_id?: string;
3500
3502
  accept?: string;
3501
3503
  maxSize?: number;
3502
3504
  multiple?: boolean;
@@ -3510,7 +3512,7 @@ interface FileUploadProps {
3510
3512
  onProgress?: (progress: UploadProgress) => void;
3511
3513
  children?: React__default.ReactNode;
3512
3514
  }
3513
- declare function FileUpload({ supabase, table_name, record_id, organisation_id, app_id, category, pageContext, accept, maxSize, // 10MB default
3515
+ declare function FileUpload({ supabase, table_name, record_id, organisation_id, app_id, category, folder, pageContext, event_id, accept, maxSize, // 10MB default
3514
3516
  multiple, disabled, isPublic, className, showPreview, showProgress, onUploadSuccess, onUploadError, onProgress, children }: FileUploadProps): react_jsx_runtime.JSX.Element;
3515
3517
 
3516
3518
  interface FileDisplayProps {
@@ -70,8 +70,9 @@ function useSecureDataAccess() {
70
70
  "medi_profile_versions",
71
71
  "pace_consent",
72
72
  "pace_contact",
73
- "pace_id_documents",
74
- "pace_qualifications",
73
+ "pace_identification",
74
+ "pace_identification_type",
75
+ "pace_qualification",
75
76
  "form_responses",
76
77
  "form_response_values",
77
78
  "forms",
@@ -207,8 +208,9 @@ function useSecureDataAccess() {
207
208
  "medi_profile_versions",
208
209
  "pace_consent",
209
210
  "pace_contact",
210
- "pace_id_documents",
211
- "pace_qualifications",
211
+ "pace_identification",
212
+ "pace_identification_type",
213
+ "pace_qualification",
212
214
  "form_responses",
213
215
  "form_response_values",
214
216
  "forms",
@@ -386,4 +388,4 @@ function useSecureDataAccess() {
386
388
  export {
387
389
  useSecureDataAccess
388
390
  };
389
- //# sourceMappingURL=chunk-STTZQK2I.js.map
391
+ //# sourceMappingURL=chunk-DAGICKHT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useSecureDataAccess.ts"],"sourcesContent":["/**\n * @file useSecureDataAccess Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useSecureDataAccess\n * @since 0.4.0\n *\n * Hook for secure database operations with mandatory organisation context.\n * Ensures all data access is properly scoped to the user's current organisation.\n *\n * @example\n * ```tsx\n * function DataComponent() {\n * const { secureQuery, secureInsert, secureUpdate, secureDelete } = useSecureDataAccess();\n * \n * const loadData = async () => {\n * try {\n * // Automatically includes organisation_id filter\n * const events = await secureQuery('event', '*', { is_visible: true });\n * console.log('Organisation events:', events);\n * } catch (error) {\n * console.error('Failed to load data:', error);\n * }\n * };\n * \n * const createEvent = async (eventData) => {\n * try {\n * // Automatically sets organisation_id\n * const newEvent = await secureInsert('event', eventData);\n * console.log('Created event:', newEvent);\n * } catch (error) {\n * console.error('Failed to create event:', error);\n * }\n * };\n * \n * return (\n * <div>\n * <button onClick={loadData}>Load Data</button>\n * <button onClick={() => createEvent({ event_name: 'New Event' })}>\n * Create Event\n * </button>\n * </div>\n * );\n * }\n * ```\n *\n * @security\n * - All queries automatically include organisation_id filter\n * - Validates organisation context before any operation\n * - Prevents data leaks between organisations\n * - Error handling for security violations\n * - Type-safe database operations\n */\n\nimport { useCallback, useState, useContext } from 'react';\nimport { useUnifiedAuth } from '../providers';\nimport { useOrganisations } from './useOrganisations';\nimport { EventServiceContext } from '../providers/services/EventServiceProvider';\nimport { setOrganisationContext } from '../utils/context/organisationContext';\nimport { logger } from '../utils/core/logger';\nimport type { Permission } from '../rbac/types';\nimport type { OrganisationSecurityError } from '../types/organisation';\n\nexport interface SecureDataAccessReturn {\n /** Execute a secure query with organisation filtering */\n secureQuery: <T = any>(\n table: string,\n columns: string,\n filters?: Record<string, any>,\n options?: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n }\n ) => Promise<T[]>;\n \n /** Execute a secure insert with organisation context */\n secureInsert: <T = any>(\n table: string,\n data: Record<string, any>\n ) => Promise<T>;\n \n /** Execute a secure update with organisation filtering */\n secureUpdate: <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ) => Promise<T[]>;\n \n /** Execute a secure delete with organisation filtering */\n secureDelete: (\n table: string,\n filters: Record<string, any>\n ) => Promise<void>;\n \n /** Execute a secure RPC call with organisation context */\n secureRpc: <T = any>(\n functionName: string,\n params?: Record<string, any>\n ) => Promise<T>;\n \n /** Get current organisation ID */\n getCurrentOrganisationId: () => string;\n \n /** Validate organisation context */\n validateContext: () => void;\n \n // NEW: Phase 1 - Enhanced Security Features\n /** Check if data access is allowed for a table and operation */\n isDataAccessAllowed: (table: string, operation: string) => boolean;\n \n /** Get all data access permissions for current user */\n getDataAccessPermissions: () => Record<string, string[]>;\n \n /** Check if strict mode is enabled */\n isStrictMode: boolean;\n \n /** Check if audit logging is enabled */\n isAuditLogEnabled: boolean;\n \n /** Get data access history */\n getDataAccessHistory: () => DataAccessRecord[];\n \n /** Clear data access history */\n clearDataAccessHistory: () => void;\n \n /** Validate data access attempt */\n validateDataAccess: (table: string, operation: string) => boolean;\n}\n\nexport interface DataAccessRecord {\n table: string;\n operation: string;\n userId: string;\n organisationId: string;\n allowed: boolean;\n timestamp: string;\n query?: string;\n filters?: Record<string, any>;\n}\n\n/**\n * Hook for secure data access with automatic organisation filtering\n * \n * All database operations automatically include organisation context:\n * - Queries filter by organisation_id\n * - Inserts include organisation_id\n * - Updates/deletes are scoped to organisation\n * - RPC calls include organisation_id parameter\n */\nexport function useSecureDataAccess(): SecureDataAccessReturn {\n const { supabase, user, session } = useUnifiedAuth();\n const { ensureOrganisationContext } = useOrganisations();\n \n // Get selected event for event-scoped RPC calls\n // Use useContext directly to safely check if EventServiceProvider is available\n const eventServiceContext = useContext(EventServiceContext);\n const selectedEvent = eventServiceContext?.eventService?.getSelectedEvent() || null;\n\n const validateContext = useCallback((): void => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n if (!user || !session) {\n throw new Error('User must be authenticated with valid session') as OrganisationSecurityError;\n }\n \n try {\n ensureOrganisationContext();\n } catch (error) {\n throw new Error('Organisation context is required for data access') as OrganisationSecurityError;\n }\n }, [supabase, user, session, ensureOrganisationContext]);\n\n const getCurrentOrganisationId = useCallback((): string => {\n validateContext();\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n }, [validateContext, ensureOrganisationContext]);\n\n // Set organisation context in database session\n const setOrganisationContextInSession = useCallback(async (organisationId: string): Promise<void> => {\n if (!supabase) {\n throw new Error('No Supabase client available') as OrganisationSecurityError;\n }\n\n await setOrganisationContext(supabase, organisationId);\n }, [supabase]);\n\n const secureQuery = useCallback(async <T = any>(\n table: string,\n columns: string,\n filters: Record<string, any> = {},\n options: {\n orderBy?: string;\n ascending?: boolean;\n limit?: number;\n offset?: number;\n } = {}\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build query with organisation filter\n let query = supabase!\n .from(table)\n .select(columns);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_identification', 'pace_identification_type', 'pace_qualification',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply additional filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n // Handle qualified column names (e.g., 'users.role')\n const columnName = key.includes('.') ? key.split('.').pop()! : key;\n query = query.eq(columnName, value);\n }\n });\n\n // Apply options\n if (options.orderBy) {\n // Only use the column name, not a qualified name\n const orderByColumn = options.orderBy.split('.').pop();\n if (orderByColumn) {\n query = query.order(orderByColumn, { ascending: options.ascending ?? true });\n }\n }\n \n if (options.limit) {\n query = query.limit(options.limit);\n }\n \n if (options.offset) {\n query = query.range(options.offset, options.offset + (options.limit || 100) - 1);\n }\n\n const { data, error } = await query;\n \n if (error) {\n logger.error('useSecureDataAccess', 'Query failed', { table, columns, filters, error });\n // NEW: Phase 1 - Record failed data access attempt\n recordDataAccess(table, 'read', false, `SELECT ${columns} FROM ${table}`, filters);\n throw error;\n }\n\n // NEW: Phase 1 - Record successful data access attempt\n recordDataAccess(table, 'read', true, `SELECT ${columns} FROM ${table}`, filters);\n\n return (data as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureInsert = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Ensure organisation_id is set\n const secureData = {\n ...data,\n organisation_id: organisationId\n };\n\n const { data: insertData, error } = await supabase!\n .from(table)\n .insert(secureData)\n .select()\n .single();\n\n if (error) {\n logger.error('useSecureDataAccess', 'Insert failed', { table, data: secureData, error });\n throw error;\n }\n\n return insertData as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureUpdate = useCallback(async <T = any>(\n table: string,\n data: Record<string, any>,\n filters: Record<string, any>\n ): Promise<T[]> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Filter out organisation_id from data to prevent manipulation\n const { organisation_id, ...secureData } = data;\n \n // Build update query with organisation filter\n let query = supabase!\n .from(table)\n .update(secureData);\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { data: updateData, error } = await query.select();\n\n if (error) {\n logger.error('useSecureDataAccess', 'Update failed', { table, data: secureData, filters, error });\n throw error;\n }\n\n return (updateData as T[]) || [];\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureDelete = useCallback(async (\n table: string,\n filters: Record<string, any>\n ): Promise<void> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Build delete query with organisation filter\n let query = supabase!\n .from(table)\n .delete();\n\n // Add organisation filter only if table has organisation_id column\n const tablesWithOrganisation = [\n 'event', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',\n // SECURITY: Phase 3A additions - medical and personal data\n 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',\n 'pace_consent', 'pace_contact', 'pace_identification', 'pace_identification_type', 'pace_qualification',\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n if (tablesWithOrganisation.includes(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n\n // Apply filters\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n\n const { error } = await query;\n\n if (error) {\n logger.error('useSecureDataAccess', 'Delete failed', { table, filters, error });\n throw error;\n }\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase]);\n\n const secureRpc = useCallback(async <T = any>(\n functionName: string,\n params: Record<string, any> = {}\n ): Promise<T> => {\n validateContext();\n const organisationId = getCurrentOrganisationId();\n\n // Set organisation context in database session\n await setOrganisationContextInSession(organisationId);\n\n // Include organisation_id in RPC parameters\n // Some functions use p_organisation_id instead of organisation_id (to avoid conflicts with RETURNS TABLE columns)\n const functionsWithPOrganisationId = [\n 'data_cake_diners_list',\n 'data_cake_mealplans_list'\n ];\n \n const paramName = functionsWithPOrganisationId.includes(functionName) \n ? 'p_organisation_id' \n : 'organisation_id';\n \n // Functions that need p_event_id for event-app role permission checks\n // Note: Even org-scoped functions (like items, packages, suppliers) need event_id\n // for permission checks when users have event-app roles\n const functionsNeedingEventId = [\n 'data_cake_items_list',\n 'data_cake_packages_list',\n 'data_cake_suppliers_list',\n 'data_cake_diettypes_list',\n 'data_cake_mealtypes_list',\n 'data_cake_diners_list',\n 'data_cake_mealplans_list',\n 'data_cake_dishes_list',\n 'data_cake_recipes_list',\n 'data_cake_meals_list',\n 'data_cake_units_list',\n 'data_cake_orders_list',\n 'app_cake_item_create',\n 'app_cake_item_update',\n 'app_cake_package_create',\n 'app_cake_package_update',\n 'app_cake_supplier_create',\n 'app_cake_supplier_update',\n 'app_cake_supplier_delete',\n 'app_cake_meal_create',\n 'app_cake_meal_update',\n 'app_cake_meal_delete',\n 'app_cake_unit_create',\n 'app_cake_unit_update',\n 'app_cake_unit_delete',\n 'app_cake_delivery_upsert'\n ];\n \n // Build secureParams with correct parameter order\n // For functions that require p_event_id as first parameter, ensure it's first\n const secureParams: Record<string, any> = {};\n \n // Functions where p_event_id is the FIRST required parameter (no default)\n const functionsWithEventIdFirst = [\n 'data_cake_meals_list',\n 'data_cake_units_list'\n ];\n \n // Add p_user_id explicitly for functions that need it (even though it has a default)\n // This ensures parameter matching works correctly\n if (user?.id) {\n secureParams.p_user_id = user.id;\n }\n \n // Add organisation_id parameter\n secureParams[paramName] = organisationId;\n \n // Add p_event_id if function needs it and event is selected\n // CRITICAL: This must be added AFTER organisation_id but BEFORE caller params\n // to ensure it's not overwritten. For data_cake_items_list, p_event_id is the 3rd param.\n if (functionsNeedingEventId.includes(functionName) && selectedEvent?.event_id) {\n secureParams.p_event_id = selectedEvent.event_id;\n }\n \n // Add any other params passed by caller (limit, offset, etc.)\n // NOTE: This will NOT overwrite p_event_id if caller passes it, but we want to ensure\n // our value takes precedence if event is selected\n Object.assign(secureParams, params);\n \n // Ensure p_event_id is set if needed (after Object.assign, so it overrides caller params)\n if (functionsNeedingEventId.includes(functionName) && selectedEvent?.event_id) {\n secureParams.p_event_id = selectedEvent.event_id;\n }\n\n const { data, error } = await supabase!.rpc(functionName, secureParams);\n\n if (error) {\n logger.error('useSecureDataAccess', 'RPC failed', { functionName, params: secureParams, error });\n throw error;\n }\n\n return data as T;\n }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, selectedEvent?.event_id, user?.id]);\n\n // NEW: Phase 1 - Enhanced Security Features\n const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);\n const [isStrictMode] = useState(true); // Always enabled in Phase 1\n const [isAuditLogEnabled] = useState(true); // Always enabled in Phase 1\n\n // Check if data access is allowed for a table and operation\n const isDataAccessAllowed = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Use the existing RBAC system to check data access permissions\n // This is a synchronous check for the context - actual permission checking\n // happens in the secure data operations using the RBAC engine\n const permission = `${operation}:data.${table}` as Permission;\n \n // For now, we'll return true and let the secure data operations\n // handle the actual permission checking asynchronously\n // This context is mainly for tracking and audit purposes\n return true;\n }, [user?.id]);\n\n // Get all data access permissions for current user\n const getDataAccessPermissions = useCallback((): Record<string, string[]> => {\n if (!user?.id) return {};\n \n // For now, return empty object - this will be enhanced with actual permission checking\n // when we integrate with the existing RBAC system\n return {};\n }, [user?.id]);\n\n // Get data access history\n const getDataAccessHistory = useCallback((): DataAccessRecord[] => {\n return [...dataAccessHistory];\n }, [dataAccessHistory]);\n\n // Clear data access history\n const clearDataAccessHistory = useCallback(() => {\n setDataAccessHistory([]);\n }, []);\n\n // Validate data access attempt\n const validateDataAccess = useCallback((table: string, operation: string): boolean => {\n if (!user?.id) return false;\n \n // Validate organisation context\n try {\n validateContext();\n } catch (error) {\n logger.error('useSecureDataAccess', 'Organisation context validation failed', { table, operation, error });\n return false;\n }\n \n return isDataAccessAllowed(table, operation);\n }, [user?.id, validateContext, isDataAccessAllowed]);\n\n // Record data access attempt\n const recordDataAccess = useCallback((\n table: string,\n operation: string,\n allowed: boolean,\n query?: string,\n filters?: Record<string, any>\n ) => {\n if (!isAuditLogEnabled || !user?.id) return;\n \n const record: DataAccessRecord = {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n allowed,\n timestamp: new Date().toISOString(),\n query,\n filters\n };\n \n setDataAccessHistory(prev => {\n const newHistory = [record, ...prev];\n return newHistory.slice(0, 1000); // Keep last 1000 records\n });\n \n if (isStrictMode && !allowed) {\n logger.error('useSecureDataAccess', 'STRICT MODE VIOLATION: User attempted data access without permission', {\n table,\n operation,\n userId: user.id,\n organisationId: getCurrentOrganisationId(),\n timestamp: new Date().toISOString()\n });\n }\n }, [isAuditLogEnabled, isStrictMode, user?.id, getCurrentOrganisationId]);\n\n return {\n secureQuery,\n secureInsert,\n secureUpdate,\n secureDelete,\n secureRpc,\n getCurrentOrganisationId,\n validateContext,\n // NEW: Phase 1 - Enhanced Security Features\n isDataAccessAllowed,\n getDataAccessPermissions,\n isStrictMode,\n isAuditLogEnabled,\n getDataAccessHistory,\n clearDataAccessHistory,\n validateDataAccess\n };\n} "],"mappings":"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","names":[]}
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-U6WNSFX5.js";
14
14
  import {
15
15
  useSecureDataAccess
16
- } from "./chunk-STTZQK2I.js";
16
+ } from "./chunk-DAGICKHT.js";
17
17
  import {
18
18
  useUnifiedAuth
19
19
  } from "./chunk-FXFJRTKI.js";
@@ -2105,4 +2105,4 @@ export {
2105
2105
  getDirectSupabaseAuthFixes,
2106
2106
  getQuickFixes
2107
2107
  };
2108
- //# sourceMappingURL=chunk-AISXLWGZ.js.map
2108
+ //# sourceMappingURL=chunk-GRIQLQ52.js.map
@@ -46,8 +46,9 @@ import {
46
46
  useEventTheme,
47
47
  useFileDisplay,
48
48
  useIsPublicPage,
49
+ usePreventTabReload,
49
50
  usePublicFileDisplay
50
- } from "./chunk-MX3EIJGQ.js";
51
+ } from "./chunk-TC7D3CR3.js";
51
52
  import {
52
53
  useToast
53
54
  } from "./chunk-6C4YBBJM.js";
@@ -1839,7 +1840,7 @@ function Header({
1839
1840
  return /* @__PURE__ */ jsx16("header", { className: cn(
1840
1841
  "w-full border-b border-main-200 h-16 shadow-sm bg-main-100 ",
1841
1842
  className
1842
- ), role: "banner", children: /* @__PURE__ */ jsxs10("nav", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_auto_1fr_auto] gap-4 h-full items-center", children: [
1843
+ ), role: "banner", children: /* @__PURE__ */ jsxs10("nav", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto flex items-center gap-4 h-full", children: [
1843
1844
  logo ? logoHref ? /* @__PURE__ */ jsx16(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: logo }) : logo : logoUrl ? logoHref ? /* @__PURE__ */ jsx16(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: /* @__PURE__ */ jsx16(
1844
1845
  "img",
1845
1846
  {
@@ -1880,7 +1881,7 @@ function Header({
1880
1881
  itemsPreFiltered: true
1881
1882
  }
1882
1883
  ),
1883
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-4 justify-end", children: [
1884
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-4 ml-auto", children: [
1884
1885
  showOrgSelector ? /* @__PURE__ */ jsx16(
1885
1886
  OrganisationSelector,
1886
1887
  {
@@ -1897,9 +1898,7 @@ function Header({
1897
1898
  className: "w-96",
1898
1899
  "data-testid": "event-selector"
1899
1900
  }
1900
- ) : null
1901
- ] }),
1902
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-4", children: [
1901
+ ) : null,
1903
1902
  actions,
1904
1903
  showUserMenu && (userMenu ? userMenu : /* @__PURE__ */ jsx16(
1905
1904
  UserMenu,
@@ -2509,7 +2508,7 @@ var SessionRestorationLoader = ({
2509
2508
  };
2510
2509
 
2511
2510
  // src/components/ProtectedRoute/ProtectedRoute.tsx
2512
- import { useMemo as useMemo6 } from "react";
2511
+ import { useMemo as useMemo6, useEffect as useEffect5, useRef as useRef3, useState as useState8 } from "react";
2513
2512
  import { Navigate, Outlet as Outlet2 } from "react-router-dom";
2514
2513
  import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
2515
2514
  function ProtectedRoute({
@@ -2525,6 +2524,67 @@ function ProtectedRoute({
2525
2524
  const events = requireEvent ? eventsContext.events || [] : [];
2526
2525
  const eventLoading = requireEvent ? eventsContext.isLoading || false : false;
2527
2526
  const sessionRestoration = useSessionRestoration();
2527
+ usePreventTabReload({ enabled: true, gracePeriodMs: 2e3 });
2528
+ const wasAuthenticatedRef = useRef3(false);
2529
+ const [shouldRedirect, setShouldRedirect] = useState8(false);
2530
+ const tabJustBecameVisibleRef = useRef3(false);
2531
+ useEffect5(() => {
2532
+ if (isAuthenticated) {
2533
+ wasAuthenticatedRef.current = true;
2534
+ setShouldRedirect(false);
2535
+ tabJustBecameVisibleRef.current = false;
2536
+ }
2537
+ }, [isAuthenticated]);
2538
+ useEffect5(() => {
2539
+ if (typeof document === "undefined") return;
2540
+ let timeoutId = null;
2541
+ let wasHidden = document.hidden;
2542
+ const handleVisibilityChange = () => {
2543
+ const isNowVisible = !document.hidden;
2544
+ if (isNowVisible && wasHidden) {
2545
+ if (!isAuthenticated && wasAuthenticatedRef.current) {
2546
+ tabJustBecameVisibleRef.current = true;
2547
+ setShouldRedirect(false);
2548
+ if (timeoutId) {
2549
+ clearTimeout(timeoutId);
2550
+ }
2551
+ timeoutId = setTimeout(() => {
2552
+ tabJustBecameVisibleRef.current = false;
2553
+ setShouldRedirect((prev) => {
2554
+ return prev;
2555
+ });
2556
+ }, 2e3);
2557
+ }
2558
+ } else if (!isNowVisible) {
2559
+ tabJustBecameVisibleRef.current = false;
2560
+ if (timeoutId) {
2561
+ clearTimeout(timeoutId);
2562
+ timeoutId = null;
2563
+ }
2564
+ }
2565
+ wasHidden = !isNowVisible;
2566
+ };
2567
+ if (!document.hidden && !isAuthenticated && wasAuthenticatedRef.current) {
2568
+ tabJustBecameVisibleRef.current = true;
2569
+ setShouldRedirect(false);
2570
+ timeoutId = setTimeout(() => {
2571
+ tabJustBecameVisibleRef.current = false;
2572
+ }, 2e3);
2573
+ }
2574
+ document.addEventListener("visibilitychange", handleVisibilityChange);
2575
+ return () => {
2576
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
2577
+ if (timeoutId) {
2578
+ clearTimeout(timeoutId);
2579
+ }
2580
+ };
2581
+ }, [isAuthenticated]);
2582
+ useEffect5(() => {
2583
+ if (isAuthenticated) {
2584
+ setShouldRedirect(false);
2585
+ tabJustBecameVisibleRef.current = false;
2586
+ }
2587
+ }, [isAuthenticated]);
2528
2588
  const isRestoringSession = useMemo6(() => {
2529
2589
  return sessionRestoration.isRestoring && !sessionRestoration.restorationComplete && !sessionRestoration.restorationError && !sessionRestoration.hasTimedOut;
2530
2590
  }, [
@@ -2548,6 +2608,20 @@ function ProtectedRoute({
2548
2608
  timedOut: sessionRestoration.hasTimedOut,
2549
2609
  error: sessionRestoration.restorationError?.message
2550
2610
  });
2611
+ return /* @__PURE__ */ jsx21(Navigate, { to: loginPath, replace: true });
2612
+ }
2613
+ if (!wasAuthenticatedRef.current) {
2614
+ return /* @__PURE__ */ jsx21(Navigate, { to: loginPath, replace: true });
2615
+ }
2616
+ const isTabVisible = typeof document !== "undefined" && !document.hidden;
2617
+ if (tabJustBecameVisibleRef.current || isTabVisible && wasAuthenticatedRef.current && isLoading) {
2618
+ return loadingFallback || /* @__PURE__ */ jsx21("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx21(LoadingSpinner, {}) });
2619
+ }
2620
+ if (shouldRedirect) {
2621
+ return /* @__PURE__ */ jsx21(Navigate, { to: loginPath, replace: true });
2622
+ }
2623
+ if (isLoading) {
2624
+ return loadingFallback || /* @__PURE__ */ jsx21("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx21(LoadingSpinner, {}) });
2551
2625
  }
2552
2626
  return /* @__PURE__ */ jsx21(Navigate, { to: loginPath, replace: true });
2553
2627
  }
@@ -2568,11 +2642,11 @@ function ProtectedRoute({
2568
2642
  }
2569
2643
 
2570
2644
  // src/hooks/useFileReference.ts
2571
- import { useState as useState8, useCallback as useCallback5, useEffect as useEffect5, useRef as useRef3, useMemo as useMemo7 } from "react";
2645
+ import { useState as useState9, useCallback as useCallback5, useEffect as useEffect6, useRef as useRef4, useMemo as useMemo7 } from "react";
2572
2646
  var log = createLogger("useFileReference");
2573
2647
  function useFileReference(supabase) {
2574
- const [isLoading, setIsLoading] = useState8(false);
2575
- const [error, setError] = useState8(null);
2648
+ const [isLoading, setIsLoading] = useState9(false);
2649
+ const [error, setError] = useState9(null);
2576
2650
  const service = useMemo7(() => createFileReferenceService(supabase), [supabase]);
2577
2651
  const uploadFile = useCallback5(async (options, file) => {
2578
2652
  setIsLoading(true);
@@ -2736,11 +2810,11 @@ function useFileReferenceForRecord(supabase, table_name, record_id, organisation
2736
2810
  getFileCount,
2737
2811
  clearError
2738
2812
  } = useFileReference(supabase);
2739
- const [fileUrl, setFileUrl] = useState8(null);
2740
- const [fileReference, setFileReference] = useState8(null);
2741
- const [fileReferences, setFileReferences] = useState8([]);
2742
- const [fileCount, setFileCount] = useState8(0);
2743
- const urlRefreshIntervalRef = useRef3(null);
2813
+ const [fileUrl, setFileUrl] = useState9(null);
2814
+ const [fileReference, setFileReference] = useState9(null);
2815
+ const [fileReferences, setFileReferences] = useState9([]);
2816
+ const [fileCount, setFileCount] = useState9(0);
2817
+ const urlRefreshIntervalRef = useRef4(null);
2744
2818
  const loadFileReference = useCallback5(async () => {
2745
2819
  const reference = await getFileReference(table_name, record_id, organisation_id);
2746
2820
  setFileReference(reference);
@@ -2770,7 +2844,7 @@ function useFileReferenceForRecord(supabase, table_name, record_id, organisation
2770
2844
  }
2771
2845
  return success;
2772
2846
  }, [deleteFileReference, table_name, record_id, organisation_id, loadFileCount]);
2773
- useEffect5(() => {
2847
+ useEffect6(() => {
2774
2848
  if (!fileReference || fileReference.is_public) {
2775
2849
  if (urlRefreshIntervalRef.current) {
2776
2850
  clearInterval(urlRefreshIntervalRef.current);
@@ -2811,8 +2885,8 @@ function useFileReferenceById(supabase, fileReferenceId, organisationId) {
2811
2885
  getFileReferenceById,
2812
2886
  clearError
2813
2887
  } = useFileReference(supabase);
2814
- const [fileReference, setFileReference] = useState8(null);
2815
- const [fileUrl, setFileUrl] = useState8(null);
2888
+ const [fileReference, setFileReference] = useState9(null);
2889
+ const [fileUrl, setFileUrl] = useState9(null);
2816
2890
  const loadFileReference = useCallback5(async () => {
2817
2891
  if (!fileReferenceId || !organisationId) {
2818
2892
  setFileReference(null);
@@ -2823,10 +2897,10 @@ function useFileReferenceById(supabase, fileReferenceId, organisationId) {
2823
2897
  setFileReference(reference);
2824
2898
  return reference;
2825
2899
  }, [getFileReferenceById, fileReferenceId, organisationId]);
2826
- useEffect5(() => {
2900
+ useEffect6(() => {
2827
2901
  loadFileReference();
2828
2902
  }, [loadFileReference]);
2829
- useEffect5(() => {
2903
+ useEffect6(() => {
2830
2904
  if (!fileReference || !fileReferenceId || !organisationId) {
2831
2905
  setFileUrl(null);
2832
2906
  return;
@@ -2858,8 +2932,8 @@ function useFilesByCategory(supabase, table_name, record_id, category, organisat
2858
2932
  getFilesByCategory,
2859
2933
  clearError
2860
2934
  } = useFileReference(supabase);
2861
- const [fileReferences, setFileReferences] = useState8([]);
2862
- const [fileUrls, setFileUrls] = useState8(/* @__PURE__ */ new Map());
2935
+ const [fileReferences, setFileReferences] = useState9([]);
2936
+ const [fileUrls, setFileUrls] = useState9(/* @__PURE__ */ new Map());
2863
2937
  const loadFiles = useCallback5(async () => {
2864
2938
  if (!category || !organisation_id) {
2865
2939
  setFileReferences([]);
@@ -2892,7 +2966,7 @@ function useFilesByCategory(supabase, table_name, record_id, category, organisat
2892
2966
  setFileUrls(urlMap);
2893
2967
  return files;
2894
2968
  }, [table_name, record_id, category, organisation_id, supabase, getFilesByCategory]);
2895
- useEffect5(() => {
2969
+ useEffect6(() => {
2896
2970
  loadFiles();
2897
2971
  }, [loadFiles]);
2898
2972
  return {
@@ -2906,7 +2980,7 @@ function useFilesByCategory(supabase, table_name, record_id, category, organisat
2906
2980
  }
2907
2981
 
2908
2982
  // src/components/FileUpload/FileUpload.tsx
2909
- import { useState as useState9, useCallback as useCallback6, useRef as useRef4, useEffect as useEffect6, useMemo as useMemo8 } from "react";
2983
+ import { useState as useState10, useCallback as useCallback6, useRef as useRef5, useEffect as useEffect7, useMemo as useMemo8 } from "react";
2910
2984
  import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
2911
2985
  function FileUpload({
2912
2986
  supabase,
@@ -2915,7 +2989,9 @@ function FileUpload({
2915
2989
  organisation_id,
2916
2990
  app_id,
2917
2991
  category,
2992
+ folder,
2918
2993
  pageContext,
2994
+ event_id,
2919
2995
  accept = "*/*",
2920
2996
  maxSize = 10 * 1024 * 1024,
2921
2997
  // 10MB default
@@ -2930,14 +3006,14 @@ function FileUpload({
2930
3006
  onProgress,
2931
3007
  children
2932
3008
  }) {
2933
- const [isDragging, setIsDragging] = useState9(false);
2934
- const [uploadStates, setUploadStates] = useState9(/* @__PURE__ */ new Map());
2935
- const [resolvedAppId, setResolvedAppId] = useState9(app_id || null);
2936
- const [isResolvingAppId, setIsResolvingAppId] = useState9(!app_id);
2937
- const [appIdError, setAppIdError] = useState9(null);
2938
- const fileInputRef = useRef4(null);
3009
+ const [isDragging, setIsDragging] = useState10(false);
3010
+ const [uploadStates, setUploadStates] = useState10(/* @__PURE__ */ new Map());
3011
+ const [resolvedAppId, setResolvedAppId] = useState10(app_id || null);
3012
+ const [isResolvingAppId, setIsResolvingAppId] = useState10(!app_id);
3013
+ const [appIdError, setAppIdError] = useState10(null);
3014
+ const fileInputRef = useRef5(null);
2939
3015
  const { uploadFile, isLoading, error } = useFileReference(supabase);
2940
- useEffect6(() => {
3016
+ useEffect7(() => {
2941
3017
  if (app_id) {
2942
3018
  setResolvedAppId(app_id);
2943
3019
  setIsResolvingAppId(false);
@@ -3103,7 +3179,9 @@ function FileUpload({
3103
3179
  organisation_id,
3104
3180
  app_id: resolvedAppId ? assertAppId(resolvedAppId) : assertAppId(""),
3105
3181
  category,
3182
+ folder,
3106
3183
  pageContext,
3184
+ event_id,
3107
3185
  is_public: isPublic
3108
3186
  }, file);
3109
3187
  clearInterval(progressInterval);
@@ -3190,7 +3268,7 @@ function FileUpload({
3190
3268
  onUploadError?.(errorMessage, file);
3191
3269
  }
3192
3270
  }
3193
- }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);
3271
+ }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);
3194
3272
  const handleDragOver = useCallback6((e) => {
3195
3273
  e.preventDefault();
3196
3274
  e.stopPropagation();
@@ -3371,17 +3449,17 @@ function FileUpload({
3371
3449
  }
3372
3450
 
3373
3451
  // src/components/FileDisplay/FileDisplay.tsx
3374
- import { useState as useState11, useEffect as useEffect8, useRef as useRef6, useContext as useContext2, useMemo as useMemo9 } from "react";
3452
+ import { useState as useState12, useEffect as useEffect9, useRef as useRef7, useContext as useContext2, useMemo as useMemo9 } from "react";
3375
3453
 
3376
3454
  // src/hooks/useFileUrl.ts
3377
- import { useState as useState10, useEffect as useEffect7, useCallback as useCallback7, useRef as useRef5 } from "react";
3455
+ import { useState as useState11, useEffect as useEffect8, useCallback as useCallback7, useRef as useRef6 } from "react";
3378
3456
  var log2 = createLogger("useFileUrl");
3379
3457
  function useFileUrl(fileReference, options) {
3380
3458
  const { organisation_id, supabase, autoLoad = true } = options;
3381
- const [url, setUrl] = useState10(null);
3382
- const [isLoading, setIsLoading] = useState10(false);
3383
- const [error, setError] = useState10(null);
3384
- const fileReferenceIdRef = useRef5(null);
3459
+ const [url, setUrl] = useState11(null);
3460
+ const [isLoading, setIsLoading] = useState11(false);
3461
+ const [error, setError] = useState11(null);
3462
+ const fileReferenceIdRef = useRef6(null);
3385
3463
  const loadUrl = useCallback7(async () => {
3386
3464
  if (!fileReference) {
3387
3465
  setUrl(null);
@@ -3424,7 +3502,7 @@ function useFileUrl(fileReference, options) {
3424
3502
  setIsLoading(false);
3425
3503
  fileReferenceIdRef.current = null;
3426
3504
  }, []);
3427
- useEffect7(() => {
3505
+ useEffect8(() => {
3428
3506
  if (autoLoad) {
3429
3507
  if (fileReferenceIdRef.current !== fileReference?.id) {
3430
3508
  setUrl(null);
@@ -3484,10 +3562,10 @@ function FileDisplayContent({
3484
3562
  fallbackText,
3485
3563
  fallbackSize = "md"
3486
3564
  }) {
3487
- const [imageError, setImageError] = useState11(false);
3488
- const [internalFileUrls, setInternalFileUrls] = useState11(new Map(fileUrls));
3489
- const [deleteDialogOpen, setDeleteDialogOpen] = useState11(false);
3490
- const fileReferencesRef = useRef6([]);
3565
+ const [imageError, setImageError] = useState12(false);
3566
+ const [internalFileUrls, setInternalFileUrls] = useState12(new Map(fileUrls));
3567
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState12(false);
3568
+ const fileReferencesRef = useRef7([]);
3491
3569
  const computedFallbackText = useMemo9(() => {
3492
3570
  if (fallbackText) return fallbackText;
3493
3571
  const fileName = fileReference?.file_metadata?.fileName;
@@ -3498,7 +3576,7 @@ function FileDisplayContent({
3498
3576
  const baseClasses = "flex items-center justify-center bg-sec-100 text-sec-600 font-semibold rounded";
3499
3577
  return `${baseClasses} ${sizeClass} ${className}`.trim();
3500
3578
  }, [fallbackSize, className]);
3501
- useEffect8(() => {
3579
+ useEffect9(() => {
3502
3580
  const currentIds = fileReferences.map((f) => f.id).join(",");
3503
3581
  const prevIds = fileReferencesRef.current.map((f) => f.id).join(",");
3504
3582
  if (currentIds !== prevIds) {
@@ -3888,7 +3966,7 @@ function FileDisplayAuthenticated({
3888
3966
  category,
3889
3967
  { supabase }
3890
3968
  );
3891
- const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState11(null);
3969
+ const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState12(null);
3892
3970
  const displayOnlyFileUrlFromMap = displayOnlyFileReference ? fileUrls.get(displayOnlyFileReference.id) : null;
3893
3971
  const displayOnlyFileUrlHook = useFileUrl(
3894
3972
  displayOnlyFileReference && !displayOnlyFileUrlFromMap ? displayOnlyFileReference : null,
@@ -3899,7 +3977,7 @@ function FileDisplayAuthenticated({
3899
3977
  }
3900
3978
  );
3901
3979
  const displayOnlyFileUrl = displayOnlyFileUrlFromMap || displayOnlyFileUrlHook.url;
3902
- useEffect8(() => {
3980
+ useEffect9(() => {
3903
3981
  if (displayOnly && !category && fileReferences.length > 0) {
3904
3982
  const imageFiles = fileReferences.filter(
3905
3983
  (f) => f.file_metadata.fileType?.startsWith("image/")
@@ -4279,4 +4357,4 @@ export {
4279
4357
  PublicPageFooter,
4280
4358
  PublicPageLayout
4281
4359
  };
4282
- //# sourceMappingURL=chunk-HC67NW5K.js.map
4360
+ //# sourceMappingURL=chunk-HDCUMOOI.js.map