@jmruthers/pace-core 0.5.87 → 0.5.89
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.
- package/dist/{AuthService-Df3IozMG.d.ts → AuthService-DcTI5Ov4.d.ts} +9 -0
- package/dist/{DataTable-FA6EUX5M.js → DataTable-PWBMKMOG.js} +7 -7
- package/dist/{PublicLoadingSpinner-DecuJBX0.d.ts → PublicLoadingSpinner-BQXD1fbO.d.ts} +160 -130
- package/dist/{UnifiedAuthProvider-K2IZAY5F.js → UnifiedAuthProvider-5D3HEQND.js} +4 -4
- package/dist/{UnifiedAuthProvider-B391Aqum.d.ts → UnifiedAuthProvider-BVKmQd9u.d.ts} +4 -0
- package/dist/auth-DReDSLq9.d.ts +16 -0
- package/dist/{chunk-CBSD3BZ3.js → chunk-3RZBKQ5Y.js} +2 -6
- package/dist/{chunk-CBSD3BZ3.js.map → chunk-3RZBKQ5Y.js.map} +1 -1
- package/dist/{chunk-NTW3KGS4.js → chunk-6UHXQH7P.js} +5 -5
- package/dist/{chunk-ZFLOV3OM.js → chunk-7VJDS5QD.js} +401 -16
- package/dist/chunk-7VJDS5QD.js.map +1 -0
- package/dist/{chunk-YVUZWLQG.js → chunk-AQGF5OG7.js} +3 -3
- package/dist/{chunk-CVMVPYAL.js → chunk-BDZUMRBD.js} +3 -5
- package/dist/chunk-BDZUMRBD.js.map +1 -0
- package/dist/{chunk-KAY3K5TP.js → chunk-BNXBJOGL.js} +4 -4
- package/dist/{chunk-S3JKDMD5.js → chunk-CXKMRKRF.js} +4 -4
- package/dist/{chunk-5BN3YGNK.js → chunk-DP5X5ORK.js} +217 -27
- package/dist/chunk-DP5X5ORK.js.map +1 -0
- package/dist/{chunk-RIXPZJUB.js → chunk-KTPG5VCH.js} +2 -2
- package/dist/{chunk-2FQEQUJT.js → chunk-KWICIQVK.js} +4 -4
- package/dist/{chunk-WUXCWRL6.js → chunk-XJ2HZOBU.js} +6 -1
- package/dist/chunk-XJ2HZOBU.js.map +1 -0
- package/dist/{chunk-I7O3RSMN.js → chunk-YWAFPVJA.js} +1298 -769
- package/dist/chunk-YWAFPVJA.js.map +1 -0
- package/dist/{chunk-I2VVV5PQ.js → chunk-YY4YYM3E.js} +2 -2
- package/dist/components.d.ts +6 -55
- package/dist/components.js +24 -205
- package/dist/components.js.map +1 -1
- package/dist/{file-reference-9xUOnwyt.d.ts → file-reference-C9isKNPn.d.ts} +67 -2
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +152 -26
- package/dist/index.js +64 -194
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +5 -3
- package/dist/providers.js +3 -3
- package/dist/rbac/index.js +8 -8
- package/dist/types.d.ts +2 -1
- package/dist/types.js +3 -3
- package/dist/utils.js +2 -2
- package/docs/DOCUMENTATION_AUDIT.md +6 -6
- package/docs/DOCUMENTATION_STANDARD.md +137 -0
- package/docs/README.md +1 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +83 -40
- package/docs/api/enums/FileCategory.md +56 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +11 -11
- package/docs/api/interfaces/FileDisplayProps.md +10 -10
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +8 -8
- package/docs/api/interfaces/FileUploadProps.md +137 -42
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +83 -50
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseEventLogoOptions.md +74 -0
- package/docs/api/interfaces/UseEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +6 -6
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +290 -95
- package/docs/api-reference/components.md +1 -18
- package/docs/api-reference/hooks.md +1 -4
- package/docs/best-practices/testing.md +2 -0
- package/docs/documentation-index.md +1 -1
- package/docs/getting-started/faq.md +1 -1
- package/docs/implementation-guides/file-reference-system.md +592 -58
- package/docs/implementation-guides/file-upload-storage.md +137 -73
- package/docs/implementation-guides/public-pages-advanced.md +10 -0
- package/docs/rbac/super-admin-guide.md +18 -70
- package/docs/testing/README.md +2 -0
- package/package.json +1 -1
- package/src/__tests__/TEST_STANDARD.md +674 -0
- package/src/__tests__/helpers/test-utils.tsx +3 -2
- package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx.skip → DataTable.comprehensive.test.tsx} +17 -18
- package/src/components/DataTable/__tests__/{DataTable.test.tsx.skip → DataTable.test.tsx} +14 -22
- package/src/components/DataTable/__tests__/{ssr.strict-mode.test.tsx.skip → ssr.strict-mode.test.tsx} +42 -47
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +1 -1
- package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +13 -4
- package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +1 -1
- package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +10 -6
- package/src/components/FileDisplay/FileDisplay.test.tsx +257 -0
- package/src/components/{FileDisplay.tsx → FileDisplay/FileDisplay.tsx} +111 -10
- package/src/components/FileDisplay/index.tsx +4 -0
- package/src/components/FileUpload/FileUpload.test.tsx +171 -621
- package/src/components/FileUpload/FileUpload.tsx +512 -168
- package/src/components/FileUpload/index.tsx +4 -0
- package/src/components/Progress/Progress.test.tsx +38 -0
- package/src/components/PublicLayout/EventLogo.tsx +6 -4
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/SessionRestorationLoader.tsx +48 -0
- package/src/components/Toast/Toast.tsx +13 -8
- package/src/components/index.ts +16 -16
- package/src/hooks/__tests__/ServiceHooks.test.tsx +615 -0
- package/src/hooks/public/usePublicEventLogo.ts +16 -20
- package/src/hooks/useEventLogo.ts +316 -0
- package/src/hooks/useEvents.ts +0 -5
- package/src/hooks/useFileReference.test.ts +659 -0
- package/src/hooks/useFileReference.ts +207 -3
- package/src/hooks/useSessionRestoration.ts +64 -0
- package/src/index.ts +17 -5
- package/src/providers/{UnifiedAuthProvider.test.simple.tsx → UnifiedAuthProvider.smoke.test.tsx} +81 -60
- package/src/providers/services/AuthServiceProvider.tsx +27 -3
- package/src/providers/services/UnifiedAuthProvider.tsx +34 -5
- package/src/rbac/{engine.test.simple.ts → RBACEngine.smoke.test.ts} +17 -12
- package/src/services/AuthService.ts +142 -20
- package/src/services/EventService.ts +0 -4
- package/src/types/auth.ts +15 -0
- package/src/types/file-reference.ts +73 -1
- package/src/types/index.ts +1 -0
- package/src/utils/__tests__/organisationContext.unit.test.ts +2 -4
- package/src/utils/appNameResolver.simple.test.ts +99 -29
- package/src/utils/file-reference.test.ts +535 -0
- package/src/utils/file-reference.ts +200 -30
- package/src/utils/organisationContext.test.ts +5 -19
- package/src/utils/organisationContext.ts +3 -5
- package/src/utils/storage/README.md +269 -262
- package/src/utils/storage/config.ts +9 -0
- package/src/utils/storage/helpers.test.ts +735 -0
- package/src/utils/storage/helpers.ts +189 -16
- package/src/utils/storage/index.ts +3 -0
- package/src/validation/__tests__/sanitization.unit.test.ts +1 -1
- package/src/validation/__tests__/schemaUtils.unit.test.ts +1 -1
- package/src/validation/__tests__/user.unit.test.ts +1 -1
- package/dist/chunk-5BN3YGNK.js.map +0 -1
- package/dist/chunk-CVMVPYAL.js.map +0 -1
- package/dist/chunk-I7O3RSMN.js.map +0 -1
- package/dist/chunk-WUXCWRL6.js.map +0 -1
- package/dist/chunk-ZFLOV3OM.js.map +0 -1
- package/docs/CONTENT_AUDIT_REPORT.md +0 -253
- package/docs/STYLE_GUIDE.md +0 -37
- package/examples/RBAC/__tests__/PermissionExample.test.tsx +0 -150
- package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +0 -159
- package/src/__tests__/TEST_GUIDE_CURSOR.md +0 -1605
- package/src/__tests__/TEST_GUIDE_HUMAN.md +0 -103
- package/src/components/FileUpload/FileUpload.example.tsx +0 -218
- package/src/components/FileUpload/index.ts +0 -6
- package/src/components/FileUpload.tsx +0 -176
- package/src/components/Progress/index.ts +0 -3
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -666
- package/src/components/SuperAdminGuard.tsx +0 -116
- package/src/components/__tests__/FileDisplay.test.tsx +0 -575
- package/src/components/__tests__/FileUpload.test.tsx +0 -446
- package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -627
- package/src/components/examples/PermissionExample.tsx +0 -173
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -583
- package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +0 -640
- package/src/types/__tests__/file-reference.test.ts +0 -447
- package/src/utils/__tests__/file-reference.test.ts +0 -383
- /package/dist/{DataTable-FA6EUX5M.js.map → DataTable-PWBMKMOG.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-K2IZAY5F.js.map → UnifiedAuthProvider-5D3HEQND.js.map} +0 -0
- /package/dist/{chunk-NTW3KGS4.js.map → chunk-6UHXQH7P.js.map} +0 -0
- /package/dist/{chunk-YVUZWLQG.js.map → chunk-AQGF5OG7.js.map} +0 -0
- /package/dist/{chunk-KAY3K5TP.js.map → chunk-BNXBJOGL.js.map} +0 -0
- /package/dist/{chunk-S3JKDMD5.js.map → chunk-CXKMRKRF.js.map} +0 -0
- /package/dist/{chunk-RIXPZJUB.js.map → chunk-KTPG5VCH.js.map} +0 -0
- /package/dist/{chunk-2FQEQUJT.js.map → chunk-KWICIQVK.js.map} +0 -0
- /package/dist/{chunk-I2VVV5PQ.js.map → chunk-YY4YYM3E.js.map} +0 -0
- /package/src/providers/{OrganisationProvider.test.simple.tsx → OrganisationProvider.context.test.tsx} +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
SelectSeparator,
|
|
23
23
|
SelectTrigger,
|
|
24
24
|
SelectValue
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-BNXBJOGL.js";
|
|
26
26
|
import {
|
|
27
27
|
isPermitted,
|
|
28
28
|
isSuperAdmin
|
|
@@ -31,23 +31,28 @@ import {
|
|
|
31
31
|
OrganisationProvider_exports,
|
|
32
32
|
PublicErrorBoundary,
|
|
33
33
|
PublicPageContext,
|
|
34
|
+
deleteFile,
|
|
35
|
+
extractFileMetadata,
|
|
36
|
+
getPublicUrl,
|
|
37
|
+
getSignedUrl,
|
|
34
38
|
init_OrganisationProvider,
|
|
39
|
+
uploadFile,
|
|
35
40
|
useAppConfig,
|
|
36
41
|
useIsPublicPage,
|
|
37
42
|
usePublicEventLogo,
|
|
38
43
|
usePublicPageContext
|
|
39
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-7VJDS5QD.js";
|
|
40
45
|
import {
|
|
41
46
|
useToast
|
|
42
47
|
} from "./chunk-QPCAGLUS.js";
|
|
43
48
|
import {
|
|
44
49
|
useEvents,
|
|
45
50
|
useOrganisations
|
|
46
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-3RZBKQ5Y.js";
|
|
47
52
|
import {
|
|
48
53
|
UnifiedAuthProvider_exports,
|
|
49
54
|
init_UnifiedAuthProvider as init_UnifiedAuthProvider2
|
|
50
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-KTPG5VCH.js";
|
|
51
56
|
import {
|
|
52
57
|
EventServiceContext,
|
|
53
58
|
EventServiceProvider,
|
|
@@ -55,16 +60,23 @@ import {
|
|
|
55
60
|
init_UnifiedAuthProvider,
|
|
56
61
|
useEventService,
|
|
57
62
|
useUnifiedAuth
|
|
58
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-DP5X5ORK.js";
|
|
59
64
|
import {
|
|
60
65
|
LoadingSpinner
|
|
61
66
|
} from "./chunk-CDQ3PX7L.js";
|
|
62
67
|
import {
|
|
63
68
|
cn
|
|
64
69
|
} from "./chunk-PYUXFQJ3.js";
|
|
70
|
+
import {
|
|
71
|
+
getCurrentAppName
|
|
72
|
+
} from "./chunk-JCQZ6LA7.js";
|
|
65
73
|
import {
|
|
66
74
|
performanceBudgetMonitor
|
|
67
75
|
} from "./chunk-O3NWNXDY.js";
|
|
76
|
+
import {
|
|
77
|
+
init_organisationContext,
|
|
78
|
+
setOrganisationContext
|
|
79
|
+
} from "./chunk-BDZUMRBD.js";
|
|
68
80
|
import {
|
|
69
81
|
__esm,
|
|
70
82
|
__export,
|
|
@@ -350,12 +362,15 @@ function Toaster() {
|
|
|
350
362
|
const { toasts } = useToast();
|
|
351
363
|
return /* @__PURE__ */ jsxs2(ToastProvider, { "data-testid": "toast-provider", children: [
|
|
352
364
|
/* @__PURE__ */ jsx5(ToastViewport, {}),
|
|
353
|
-
toasts.map((toast) =>
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
365
|
+
toasts.map((toast) => {
|
|
366
|
+
const { id, title, description, action, dismiss, ...toastProps } = toast;
|
|
367
|
+
return /* @__PURE__ */ jsxs2(Toast, { ...toastProps, children: [
|
|
368
|
+
title && /* @__PURE__ */ jsx5(ToastTitle, { children: title }),
|
|
369
|
+
description && /* @__PURE__ */ jsx5(ToastDescription, { children: description }),
|
|
370
|
+
action && action,
|
|
371
|
+
/* @__PURE__ */ jsx5(ToastClose, { onClick: dismiss })
|
|
372
|
+
] }, id);
|
|
373
|
+
})
|
|
359
374
|
] });
|
|
360
375
|
}
|
|
361
376
|
|
|
@@ -1401,7 +1416,7 @@ function PaceAppLayout({
|
|
|
1401
1416
|
}
|
|
1402
1417
|
}
|
|
1403
1418
|
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
1404
|
-
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-
|
|
1419
|
+
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-5D3HEQND.js");
|
|
1405
1420
|
hasAccess = true;
|
|
1406
1421
|
}
|
|
1407
1422
|
if (!isMounted) return;
|
|
@@ -1785,11 +1800,48 @@ var ErrorBoundary = class extends Component {
|
|
|
1785
1800
|
}
|
|
1786
1801
|
};
|
|
1787
1802
|
|
|
1803
|
+
// src/components/SessionRestorationLoader.tsx
|
|
1804
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1805
|
+
var SessionRestorationLoader = ({
|
|
1806
|
+
message = "Restoring session..."
|
|
1807
|
+
}) => {
|
|
1808
|
+
return /* @__PURE__ */ jsxs13(
|
|
1809
|
+
"div",
|
|
1810
|
+
{
|
|
1811
|
+
style: {
|
|
1812
|
+
display: "flex",
|
|
1813
|
+
flexDirection: "column",
|
|
1814
|
+
alignItems: "center",
|
|
1815
|
+
justifyContent: "center",
|
|
1816
|
+
height: "100vh",
|
|
1817
|
+
width: "100%",
|
|
1818
|
+
gap: "1rem",
|
|
1819
|
+
textAlign: "center",
|
|
1820
|
+
padding: "1rem",
|
|
1821
|
+
background: "var(--background, transparent)"
|
|
1822
|
+
},
|
|
1823
|
+
children: [
|
|
1824
|
+
/* @__PURE__ */ jsx17(LoadingSpinner, { size: "lg" }),
|
|
1825
|
+
/* @__PURE__ */ jsx17(
|
|
1826
|
+
"div",
|
|
1827
|
+
{
|
|
1828
|
+
style: {
|
|
1829
|
+
fontSize: "0.95rem",
|
|
1830
|
+
color: "var(--muted-foreground, #6b7280)"
|
|
1831
|
+
},
|
|
1832
|
+
children: message
|
|
1833
|
+
}
|
|
1834
|
+
)
|
|
1835
|
+
]
|
|
1836
|
+
}
|
|
1837
|
+
);
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1788
1840
|
// src/components/OrganisationSelector/OrganisationSelector.tsx
|
|
1789
1841
|
import { useState as useState7, useCallback as useCallback4 } from "react";
|
|
1790
1842
|
init_OrganisationProvider();
|
|
1791
1843
|
import { RefreshCw as RefreshCw2, AlertCircle as AlertCircle2, Building2, Shield } from "lucide-react";
|
|
1792
|
-
import { jsx as
|
|
1844
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1793
1845
|
function OrganisationSelector({
|
|
1794
1846
|
placeholder = "Select organisation",
|
|
1795
1847
|
className,
|
|
@@ -1853,21 +1905,21 @@ function OrganisationSelector({
|
|
|
1853
1905
|
}
|
|
1854
1906
|
}, [refreshOrganisations]);
|
|
1855
1907
|
if (orgLoading) {
|
|
1856
|
-
return /* @__PURE__ */
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1908
|
+
return /* @__PURE__ */ jsxs14("div", { className: `flex items-center gap-2 ${className}`, children: [
|
|
1909
|
+
/* @__PURE__ */ jsx18(LoadingSpinner, { size: "sm" }),
|
|
1910
|
+
/* @__PURE__ */ jsx18("span", { className: "text-sm text-muted-foreground", children: compact ? "Loading..." : "Loading organisations..." })
|
|
1859
1911
|
] });
|
|
1860
1912
|
}
|
|
1861
1913
|
if (orgError) {
|
|
1862
|
-
return /* @__PURE__ */
|
|
1863
|
-
/* @__PURE__ */
|
|
1864
|
-
/* @__PURE__ */
|
|
1865
|
-
/* @__PURE__ */
|
|
1914
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className}`, children: [
|
|
1915
|
+
/* @__PURE__ */ jsxs14(Alert, { variant: "destructive", children: [
|
|
1916
|
+
/* @__PURE__ */ jsx18(AlertCircle2, { className: "h-4 w-4" }),
|
|
1917
|
+
/* @__PURE__ */ jsxs14(AlertDescription, { children: [
|
|
1866
1918
|
"Failed to load organisations: ",
|
|
1867
1919
|
orgError.message
|
|
1868
1920
|
] })
|
|
1869
1921
|
] }),
|
|
1870
|
-
showRetryButton && /* @__PURE__ */
|
|
1922
|
+
showRetryButton && /* @__PURE__ */ jsxs14(
|
|
1871
1923
|
Button,
|
|
1872
1924
|
{
|
|
1873
1925
|
variant: "outline",
|
|
@@ -1876,7 +1928,7 @@ function OrganisationSelector({
|
|
|
1876
1928
|
disabled: isLoading,
|
|
1877
1929
|
className: "w-full",
|
|
1878
1930
|
children: [
|
|
1879
|
-
/* @__PURE__ */
|
|
1931
|
+
/* @__PURE__ */ jsx18(RefreshCw2, { className: `h-4 w-4 mr-2 ${isLoading ? "animate-spin" : ""}` }),
|
|
1880
1932
|
"Retry"
|
|
1881
1933
|
]
|
|
1882
1934
|
}
|
|
@@ -1885,12 +1937,12 @@ function OrganisationSelector({
|
|
|
1885
1937
|
}
|
|
1886
1938
|
if (organisations.length === 0) {
|
|
1887
1939
|
if (showNoOrganisationsMessage) {
|
|
1888
|
-
return /* @__PURE__ */
|
|
1889
|
-
/* @__PURE__ */
|
|
1890
|
-
/* @__PURE__ */
|
|
1891
|
-
/* @__PURE__ */
|
|
1940
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className}`, children: [
|
|
1941
|
+
/* @__PURE__ */ jsxs14(Alert, { children: [
|
|
1942
|
+
/* @__PURE__ */ jsx18(Building2, { className: "h-4 w-4" }),
|
|
1943
|
+
/* @__PURE__ */ jsx18(AlertDescription, { children: "No organisations available. Please contact your administrator to be added to an organisation." })
|
|
1892
1944
|
] }),
|
|
1893
|
-
showRetryButton && /* @__PURE__ */
|
|
1945
|
+
showRetryButton && /* @__PURE__ */ jsxs14(
|
|
1894
1946
|
Button,
|
|
1895
1947
|
{
|
|
1896
1948
|
variant: "outline",
|
|
@@ -1899,7 +1951,7 @@ function OrganisationSelector({
|
|
|
1899
1951
|
disabled: isLoading,
|
|
1900
1952
|
className: "w-full",
|
|
1901
1953
|
children: [
|
|
1902
|
-
/* @__PURE__ */
|
|
1954
|
+
/* @__PURE__ */ jsx18(RefreshCw2, { className: `h-4 w-4 mr-2 ${isLoading ? "animate-spin" : ""}` }),
|
|
1903
1955
|
"Check Again"
|
|
1904
1956
|
]
|
|
1905
1957
|
}
|
|
@@ -1908,42 +1960,42 @@ function OrganisationSelector({
|
|
|
1908
1960
|
}
|
|
1909
1961
|
return null;
|
|
1910
1962
|
}
|
|
1911
|
-
const switchErrorDisplay = switchError && /* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1963
|
+
const switchErrorDisplay = switchError && /* @__PURE__ */ jsxs14(Alert, { variant: "destructive", className: "mt-2", children: [
|
|
1964
|
+
/* @__PURE__ */ jsx18(AlertCircle2, { className: "h-4 w-4" }),
|
|
1965
|
+
/* @__PURE__ */ jsx18(AlertDescription, { children: switchError })
|
|
1914
1966
|
] });
|
|
1915
|
-
return /* @__PURE__ */
|
|
1916
|
-
/* @__PURE__ */
|
|
1967
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className}`, children: [
|
|
1968
|
+
/* @__PURE__ */ jsxs14(
|
|
1917
1969
|
Select,
|
|
1918
1970
|
{
|
|
1919
1971
|
value: selectedOrganisation?.id || "",
|
|
1920
1972
|
onValueChange: handleOrganisationChange,
|
|
1921
1973
|
disabled: disabled || isLoading || !selectedOrganisation,
|
|
1922
1974
|
children: [
|
|
1923
|
-
/* @__PURE__ */
|
|
1924
|
-
isLoading ? /* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1975
|
+
/* @__PURE__ */ jsx18(SelectTrigger, { className: `${isLoading ? "opacity-50" : ""}`, children: /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
|
|
1976
|
+
isLoading ? /* @__PURE__ */ jsx18(LoadingSpinner, { size: "sm" }) : /* @__PURE__ */ jsx18(Building2, { className: "h-4 w-4 text-muted-foreground" }),
|
|
1977
|
+
/* @__PURE__ */ jsx18(SelectValue, { placeholder })
|
|
1926
1978
|
] }) }),
|
|
1927
|
-
/* @__PURE__ */
|
|
1979
|
+
/* @__PURE__ */ jsx18(SelectContent, { children: organisations.map((org) => {
|
|
1928
1980
|
const userRole = getUserRole(org.id);
|
|
1929
1981
|
const hasAccess = validateOrganisationAccess(org.id);
|
|
1930
|
-
return /* @__PURE__ */
|
|
1982
|
+
return /* @__PURE__ */ jsx18(
|
|
1931
1983
|
SelectItem,
|
|
1932
1984
|
{
|
|
1933
1985
|
value: org.id,
|
|
1934
1986
|
disabled: !hasAccess,
|
|
1935
1987
|
className: !hasAccess ? "opacity-50" : "",
|
|
1936
|
-
children: /* @__PURE__ */
|
|
1937
|
-
/* @__PURE__ */
|
|
1938
|
-
/* @__PURE__ */
|
|
1939
|
-
/* @__PURE__ */
|
|
1940
|
-
/* @__PURE__ */
|
|
1941
|
-
!compact && org.description && /* @__PURE__ */
|
|
1988
|
+
children: /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between w-full", children: [
|
|
1989
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
|
|
1990
|
+
/* @__PURE__ */ jsx18(Building2, { className: "h-4 w-4" }),
|
|
1991
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-col", children: [
|
|
1992
|
+
/* @__PURE__ */ jsx18("span", { className: "font-medium", children: org.display_name }),
|
|
1993
|
+
!compact && org.description && /* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground truncate max-w-40", children: org.description })
|
|
1942
1994
|
] })
|
|
1943
1995
|
] }),
|
|
1944
|
-
showRole && /* @__PURE__ */
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1996
|
+
showRole && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1 ml-4", children: [
|
|
1997
|
+
/* @__PURE__ */ jsx18(Shield, { className: "h-3 w-3 text-muted-foreground" }),
|
|
1998
|
+
/* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground capitalize", children: userRole?.replace("_", " ") || "No Role" })
|
|
1947
1999
|
] })
|
|
1948
2000
|
] })
|
|
1949
2001
|
},
|
|
@@ -1960,7 +2012,7 @@ function OrganisationSelector({
|
|
|
1960
2012
|
// src/components/PasswordReset/PasswordResetForm.tsx
|
|
1961
2013
|
import { useState as useState8 } from "react";
|
|
1962
2014
|
init_UnifiedAuthProvider2();
|
|
1963
|
-
import { jsx as
|
|
2015
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1964
2016
|
function PasswordResetForm({
|
|
1965
2017
|
onSuccess,
|
|
1966
2018
|
onError,
|
|
@@ -2001,13 +2053,13 @@ function PasswordResetForm({
|
|
|
2001
2053
|
setError(null);
|
|
2002
2054
|
};
|
|
2003
2055
|
if (isSuccess) {
|
|
2004
|
-
return /* @__PURE__ */
|
|
2005
|
-
/* @__PURE__ */
|
|
2006
|
-
/* @__PURE__ */
|
|
2056
|
+
return /* @__PURE__ */ jsx19("div", { className: cn("", className), role: "form", children: /* @__PURE__ */ jsxs15("div", { className: "space-y-4 text-center", children: [
|
|
2057
|
+
/* @__PURE__ */ jsx19("h2", { children: "Check your email" }),
|
|
2058
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-sec-600", children: [
|
|
2007
2059
|
"We have sent a password reset link to ",
|
|
2008
2060
|
email
|
|
2009
2061
|
] }),
|
|
2010
|
-
/* @__PURE__ */
|
|
2062
|
+
/* @__PURE__ */ jsx19(
|
|
2011
2063
|
Button,
|
|
2012
2064
|
{
|
|
2013
2065
|
variant: "outline",
|
|
@@ -2018,15 +2070,15 @@ function PasswordResetForm({
|
|
|
2018
2070
|
)
|
|
2019
2071
|
] }) });
|
|
2020
2072
|
}
|
|
2021
|
-
return /* @__PURE__ */
|
|
2022
|
-
/* @__PURE__ */
|
|
2023
|
-
/* @__PURE__ */
|
|
2024
|
-
/* @__PURE__ */
|
|
2073
|
+
return /* @__PURE__ */ jsx19("div", { className: cn("", className), role: "form", children: /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
|
|
2074
|
+
/* @__PURE__ */ jsxs15("div", { className: "space-y-2", children: [
|
|
2075
|
+
/* @__PURE__ */ jsx19("h2", { children: "Reset Password" }),
|
|
2076
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sec-600", children: "Enter your email address and we'll send you a reset link." })
|
|
2025
2077
|
] }),
|
|
2026
|
-
/* @__PURE__ */
|
|
2027
|
-
/* @__PURE__ */
|
|
2028
|
-
/* @__PURE__ */
|
|
2029
|
-
/* @__PURE__ */
|
|
2078
|
+
/* @__PURE__ */ jsxs15("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
2079
|
+
/* @__PURE__ */ jsxs15("div", { className: "space-y-2", children: [
|
|
2080
|
+
/* @__PURE__ */ jsx19(Label, { htmlFor: "email", children: "Email Address" }),
|
|
2081
|
+
/* @__PURE__ */ jsx19(
|
|
2030
2082
|
Input,
|
|
2031
2083
|
{
|
|
2032
2084
|
id: "email",
|
|
@@ -2039,8 +2091,8 @@ function PasswordResetForm({
|
|
|
2039
2091
|
}
|
|
2040
2092
|
)
|
|
2041
2093
|
] }),
|
|
2042
|
-
error && /* @__PURE__ */
|
|
2043
|
-
/* @__PURE__ */
|
|
2094
|
+
error && /* @__PURE__ */ jsx19("div", { className: "text-sm text-destructive", role: "alert", children: error }),
|
|
2095
|
+
/* @__PURE__ */ jsx19(
|
|
2044
2096
|
Button,
|
|
2045
2097
|
{
|
|
2046
2098
|
type: "submit",
|
|
@@ -2053,513 +2105,47 @@ function PasswordResetForm({
|
|
|
2053
2105
|
] }) });
|
|
2054
2106
|
}
|
|
2055
2107
|
|
|
2056
|
-
// src/utils/storage/config.ts
|
|
2057
|
-
var FILE_SIZE_LIMITS = {
|
|
2058
|
-
// Images
|
|
2059
|
-
"image/jpeg": 5 * 1024 * 1024,
|
|
2060
|
-
// 5MB
|
|
2061
|
-
"image/png": 5 * 1024 * 1024,
|
|
2062
|
-
// 5MB
|
|
2063
|
-
"image/gif": 10 * 1024 * 1024,
|
|
2064
|
-
// 10MB (for animations)
|
|
2065
|
-
"image/webp": 5 * 1024 * 1024,
|
|
2066
|
-
// 5MB
|
|
2067
|
-
"image/svg+xml": 1 * 1024 * 1024,
|
|
2068
|
-
// 1MB (vector graphics)
|
|
2069
|
-
// Documents
|
|
2070
|
-
"application/pdf": 50 * 1024 * 1024,
|
|
2071
|
-
// 50MB
|
|
2072
|
-
"application/msword": 25 * 1024 * 1024,
|
|
2073
|
-
// 25MB
|
|
2074
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": 25 * 1024 * 1024,
|
|
2075
|
-
// 25MB
|
|
2076
|
-
"application/vnd.ms-excel": 25 * 1024 * 1024,
|
|
2077
|
-
// 25MB
|
|
2078
|
-
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": 25 * 1024 * 1024,
|
|
2079
|
-
// 25MB
|
|
2080
|
-
// Archives
|
|
2081
|
-
"application/zip": 100 * 1024 * 1024,
|
|
2082
|
-
// 100MB
|
|
2083
|
-
"application/x-rar-compressed": 100 * 1024 * 1024,
|
|
2084
|
-
// 100MB
|
|
2085
|
-
// Text files
|
|
2086
|
-
"text/plain": 1 * 1024 * 1024,
|
|
2087
|
-
// 1MB
|
|
2088
|
-
"text/csv": 10 * 1024 * 1024,
|
|
2089
|
-
// 10MB
|
|
2090
|
-
"application/json": 10 * 1024 * 1024
|
|
2091
|
-
// 10MB
|
|
2092
|
-
};
|
|
2093
|
-
var DEFAULT_FILE_SIZE_LIMIT = 10 * 1024 * 1024;
|
|
2094
|
-
var APP_PATH_MAPPING = {
|
|
2095
|
-
"PACE": "event_logos",
|
|
2096
|
-
"TRAC": "trac_accommodation",
|
|
2097
|
-
// Default category for TRAC files
|
|
2098
|
-
"MEDI": "documents",
|
|
2099
|
-
"CAKE": "documents"
|
|
2100
|
-
};
|
|
2101
|
-
var STORAGE_CONFIG = {
|
|
2102
|
-
bucketName: "files",
|
|
2103
|
-
fileSizeLimits: FILE_SIZE_LIMITS,
|
|
2104
|
-
defaultFileSizeLimit: DEFAULT_FILE_SIZE_LIMIT
|
|
2105
|
-
};
|
|
2106
|
-
function getFileSizeLimit(mimeType) {
|
|
2107
|
-
return STORAGE_CONFIG.fileSizeLimits[mimeType] || STORAGE_CONFIG.defaultFileSizeLimit;
|
|
2108
|
-
}
|
|
2109
|
-
function validateFileSize(file) {
|
|
2110
|
-
const limit = getFileSizeLimit(file.type);
|
|
2111
|
-
if (file.size > limit) {
|
|
2112
|
-
const limitMB = Math.round(limit / (1024 * 1024));
|
|
2113
|
-
const fileMB = Math.round(file.size / (1024 * 1024));
|
|
2114
|
-
return {
|
|
2115
|
-
isValid: false,
|
|
2116
|
-
error: `File size (${fileMB}MB) exceeds limit (${limitMB}MB) for ${file.type}`
|
|
2117
|
-
};
|
|
2118
|
-
}
|
|
2119
|
-
return { isValid: true };
|
|
2120
|
-
}
|
|
2121
|
-
function formatFileSize(bytes) {
|
|
2122
|
-
if (bytes === 0) return "0 Bytes";
|
|
2123
|
-
if (bytes < 0) return `${bytes} Bytes`;
|
|
2124
|
-
const k = 1024;
|
|
2125
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
2126
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
2127
|
-
const sizeIndex = Math.min(Math.max(i, 0), sizes.length - 1);
|
|
2128
|
-
return parseFloat((bytes / Math.pow(k, sizeIndex)).toFixed(2)) + " " + sizes[sizeIndex];
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
// src/utils/storage/helpers.ts
|
|
2132
|
-
function generateFilePath(options, fileName) {
|
|
2133
|
-
const { orgId, isPublic = false, customPath } = options;
|
|
2134
|
-
if (isPublic) {
|
|
2135
|
-
if (customPath) {
|
|
2136
|
-
return `${orgId}/${customPath}/${fileName}`;
|
|
2137
|
-
}
|
|
2138
|
-
return `${orgId}/public/${fileName}`;
|
|
2139
|
-
}
|
|
2140
|
-
if (customPath) {
|
|
2141
|
-
return `${orgId}/${customPath}/${fileName}`;
|
|
2142
|
-
}
|
|
2143
|
-
const pathCategory = customPath || "files";
|
|
2144
|
-
return `${orgId}/${pathCategory}/${fileName}`;
|
|
2145
|
-
}
|
|
2146
|
-
function generateUniqueFileName(originalName) {
|
|
2147
|
-
const timestamp = Date.now();
|
|
2148
|
-
const uuid = crypto.randomUUID();
|
|
2149
|
-
const extension = originalName.split(".").pop() || "";
|
|
2150
|
-
const baseName = originalName.replace(/\.[^/.]+$/, "");
|
|
2151
|
-
if (!extension || extension === originalName) {
|
|
2152
|
-
return `${timestamp}-${uuid}-${baseName}`;
|
|
2153
|
-
}
|
|
2154
|
-
return `${timestamp}-${uuid}-${baseName}.${extension}`;
|
|
2155
|
-
}
|
|
2156
|
-
async function extractFileMetadata(file, options, uploadedBy) {
|
|
2157
|
-
const metadata = {
|
|
2158
|
-
mimeType: file.type,
|
|
2159
|
-
size: file.size,
|
|
2160
|
-
orgId: options.orgId,
|
|
2161
|
-
appName: options.appName || "pace-core",
|
|
2162
|
-
uploadedBy,
|
|
2163
|
-
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2164
|
-
tags: options.tags || [],
|
|
2165
|
-
isPublic: options.isPublic || false,
|
|
2166
|
-
customMetadata: options.metadata || {}
|
|
2167
|
-
};
|
|
2168
|
-
if (file.type.startsWith("image/")) {
|
|
2169
|
-
try {
|
|
2170
|
-
const dimensions = await getImageDimensions(file);
|
|
2171
|
-
metadata.width = dimensions.width;
|
|
2172
|
-
metadata.height = dimensions.height;
|
|
2173
|
-
} catch (error) {
|
|
2174
|
-
console.warn("Could not extract image dimensions:", error);
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
try {
|
|
2178
|
-
metadata.hash = await generateFileHash(file);
|
|
2179
|
-
} catch (error) {
|
|
2180
|
-
console.warn("Could not generate file hash:", error);
|
|
2181
|
-
}
|
|
2182
|
-
return metadata;
|
|
2183
|
-
}
|
|
2184
|
-
async function getImageDimensions(file) {
|
|
2185
|
-
return new Promise((resolve, reject) => {
|
|
2186
|
-
const img = new Image();
|
|
2187
|
-
const url = URL.createObjectURL(file);
|
|
2188
|
-
img.onload = () => {
|
|
2189
|
-
URL.revokeObjectURL(url);
|
|
2190
|
-
resolve({ width: img.width, height: img.height });
|
|
2191
|
-
};
|
|
2192
|
-
img.onerror = () => {
|
|
2193
|
-
URL.revokeObjectURL(url);
|
|
2194
|
-
reject(new Error("Could not load image"));
|
|
2195
|
-
};
|
|
2196
|
-
img.src = url;
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
async function generateFileHash(file) {
|
|
2200
|
-
const buffer = await file.arrayBuffer();
|
|
2201
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
2202
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
2203
|
-
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2204
|
-
return `sha256:${hashHex}`;
|
|
2205
|
-
}
|
|
2206
|
-
async function uploadFile(supabase, file, options) {
|
|
2207
|
-
try {
|
|
2208
|
-
const sizeValidation = validateFileSize(file);
|
|
2209
|
-
if (!sizeValidation.isValid) {
|
|
2210
|
-
return {
|
|
2211
|
-
success: false,
|
|
2212
|
-
error: sizeValidation.error
|
|
2213
|
-
};
|
|
2214
|
-
}
|
|
2215
|
-
const uniqueFileName = generateUniqueFileName(file.name);
|
|
2216
|
-
const filePath = generateFilePath(options, uniqueFileName);
|
|
2217
|
-
const metadata = await extractFileMetadata(file, options, "current-user");
|
|
2218
|
-
const { data, error } = await supabase.storage.from(STORAGE_CONFIG.bucketName).upload(filePath, file, {
|
|
2219
|
-
cacheControl: "3600",
|
|
2220
|
-
upsert: false,
|
|
2221
|
-
contentType: file.type
|
|
2222
|
-
});
|
|
2223
|
-
if (error) {
|
|
2224
|
-
return {
|
|
2225
|
-
success: false,
|
|
2226
|
-
error: `Upload failed: ${error.message}`
|
|
2227
|
-
};
|
|
2228
|
-
}
|
|
2229
|
-
let publicUrl;
|
|
2230
|
-
if (options.isPublic) {
|
|
2231
|
-
const { data: urlData } = supabase.storage.from(STORAGE_CONFIG.bucketName).getPublicUrl(filePath);
|
|
2232
|
-
publicUrl = urlData.publicUrl;
|
|
2233
|
-
}
|
|
2234
|
-
return {
|
|
2235
|
-
success: true,
|
|
2236
|
-
path: filePath,
|
|
2237
|
-
publicUrl,
|
|
2238
|
-
metadata
|
|
2239
|
-
};
|
|
2240
|
-
} catch (error) {
|
|
2241
|
-
return {
|
|
2242
|
-
success: false,
|
|
2243
|
-
error: `Upload failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2244
|
-
};
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
function getPublicUrl(supabase, path) {
|
|
2248
|
-
const { data } = supabase.storage.from(STORAGE_CONFIG.bucketName).getPublicUrl(path);
|
|
2249
|
-
return data.publicUrl;
|
|
2250
|
-
}
|
|
2251
|
-
async function getSignedUrl(supabase, path, options) {
|
|
2252
|
-
try {
|
|
2253
|
-
const { data, error } = await supabase.storage.from(STORAGE_CONFIG.bucketName).createSignedUrl(path, options.expiresIn || 3600);
|
|
2254
|
-
if (error) {
|
|
2255
|
-
console.error("Failed to create signed URL:", error);
|
|
2256
|
-
return null;
|
|
2257
|
-
}
|
|
2258
|
-
return {
|
|
2259
|
-
url: data.signedUrl,
|
|
2260
|
-
expiresAt: new Date(Date.now() + (options.expiresIn || 3600) * 1e3).toISOString()
|
|
2261
|
-
};
|
|
2262
|
-
} catch (error) {
|
|
2263
|
-
console.error("Failed to create signed URL:", error);
|
|
2264
|
-
return null;
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
async function deleteFile(supabase, path) {
|
|
2268
|
-
try {
|
|
2269
|
-
const { error } = await supabase.storage.from(STORAGE_CONFIG.bucketName).remove([path]);
|
|
2270
|
-
if (error) {
|
|
2271
|
-
return {
|
|
2272
|
-
success: false,
|
|
2273
|
-
error: `Delete failed: ${error.message}`
|
|
2274
|
-
};
|
|
2275
|
-
}
|
|
2276
|
-
return { success: true };
|
|
2277
|
-
} catch (error) {
|
|
2278
|
-
return {
|
|
2279
|
-
success: false,
|
|
2280
|
-
error: `Delete failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2281
|
-
};
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
async function listFiles(supabase, options) {
|
|
2285
|
-
try {
|
|
2286
|
-
const pathPrefix = `${options.orgId}/`;
|
|
2287
|
-
const searchPath = options.pathPrefix ? `${pathPrefix}${options.pathPrefix}` : pathPrefix;
|
|
2288
|
-
const { data, error } = await supabase.storage.from(STORAGE_CONFIG.bucketName).list(searchPath, {
|
|
2289
|
-
limit: options.limit || 100,
|
|
2290
|
-
offset: options.offset || 0,
|
|
2291
|
-
sortBy: { column: "created_at", order: "desc" }
|
|
2292
|
-
});
|
|
2293
|
-
if (error) {
|
|
2294
|
-
console.error("Failed to list files:", error);
|
|
2295
|
-
return { files: [], totalCount: 0, hasMore: false };
|
|
2296
|
-
}
|
|
2297
|
-
const files = (data || []).map((item) => ({
|
|
2298
|
-
name: item.name,
|
|
2299
|
-
path: `${searchPath}${item.name}`,
|
|
2300
|
-
size: item.metadata?.size || 0,
|
|
2301
|
-
mimeType: item.metadata?.mimetype || "application/octet-stream",
|
|
2302
|
-
lastModified: item.updated_at || item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2303
|
-
metadata: {
|
|
2304
|
-
mimeType: item.metadata?.mimetype || "application/octet-stream",
|
|
2305
|
-
size: item.metadata?.size || 0,
|
|
2306
|
-
orgId: options.orgId,
|
|
2307
|
-
appName: options.appName,
|
|
2308
|
-
uploadedBy: "unknown",
|
|
2309
|
-
uploadedAt: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2310
|
-
isPublic: false
|
|
2311
|
-
}
|
|
2312
|
-
}));
|
|
2313
|
-
return {
|
|
2314
|
-
files,
|
|
2315
|
-
totalCount: files.length,
|
|
2316
|
-
hasMore: files.length >= (options.limit || 100)
|
|
2317
|
-
};
|
|
2318
|
-
} catch (error) {
|
|
2319
|
-
console.error("Failed to list files:", error);
|
|
2320
|
-
return { files: [], totalCount: 0, hasMore: false };
|
|
2321
|
-
}
|
|
2322
|
-
}
|
|
2323
|
-
async function archiveFile(supabase, path, options) {
|
|
2324
|
-
try {
|
|
2325
|
-
const archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
|
|
2326
|
-
const { error: copyError } = await supabase.storage.from(STORAGE_CONFIG.bucketName).copy(path, archivedPath);
|
|
2327
|
-
if (copyError) {
|
|
2328
|
-
return {
|
|
2329
|
-
success: false,
|
|
2330
|
-
error: `Archive failed: ${copyError.message}`
|
|
2331
|
-
};
|
|
2332
|
-
}
|
|
2333
|
-
const deleteResult = await deleteFile(supabase, path);
|
|
2334
|
-
if (!deleteResult.success) {
|
|
2335
|
-
return deleteResult;
|
|
2336
|
-
}
|
|
2337
|
-
return { success: true };
|
|
2338
|
-
} catch (error) {
|
|
2339
|
-
return {
|
|
2340
|
-
success: false,
|
|
2341
|
-
error: `Archive failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2342
|
-
};
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
|
|
2346
|
-
// src/utils/storage/index.ts
|
|
2347
|
-
var StorageUtils = class {
|
|
2348
|
-
};
|
|
2349
|
-
StorageUtils.generateFilePath = generateFilePath;
|
|
2350
|
-
StorageUtils.generateUniqueFileName = generateUniqueFileName;
|
|
2351
|
-
StorageUtils.extractFileMetadata = extractFileMetadata;
|
|
2352
|
-
StorageUtils.uploadFile = uploadFile;
|
|
2353
|
-
StorageUtils.getPublicUrl = getPublicUrl;
|
|
2354
|
-
StorageUtils.getSignedUrl = getSignedUrl;
|
|
2355
|
-
StorageUtils.deleteFile = deleteFile;
|
|
2356
|
-
StorageUtils.listFiles = listFiles;
|
|
2357
|
-
StorageUtils.archiveFile = archiveFile;
|
|
2358
|
-
|
|
2359
|
-
// src/hooks/useStorage.ts
|
|
2360
|
-
import { useState as useState9, useCallback as useCallback5 } from "react";
|
|
2361
|
-
function useStorage({ supabase, appName, orgId }) {
|
|
2362
|
-
const [isUploading, setIsUploading] = useState9(false);
|
|
2363
|
-
const [uploadError, setUploadError] = useState9(null);
|
|
2364
|
-
const [isListing, setIsListing] = useState9(false);
|
|
2365
|
-
const [listError, setListError] = useState9(null);
|
|
2366
|
-
const [files, setFiles] = useState9([]);
|
|
2367
|
-
const handleUploadFile = useCallback5(async (file, options = {}) => {
|
|
2368
|
-
setIsUploading(true);
|
|
2369
|
-
setUploadError(null);
|
|
2370
|
-
try {
|
|
2371
|
-
const uploadOptions = {
|
|
2372
|
-
appName,
|
|
2373
|
-
orgId,
|
|
2374
|
-
isPublic: false,
|
|
2375
|
-
...options
|
|
2376
|
-
};
|
|
2377
|
-
const result = await uploadFile(supabase, file, uploadOptions);
|
|
2378
|
-
if (result.success) {
|
|
2379
|
-
await refreshFiles();
|
|
2380
|
-
} else {
|
|
2381
|
-
setUploadError(result.error || "Upload failed");
|
|
2382
|
-
}
|
|
2383
|
-
return result;
|
|
2384
|
-
} catch (error) {
|
|
2385
|
-
const errorMessage = error instanceof Error ? error.message : "Upload failed";
|
|
2386
|
-
setUploadError(errorMessage);
|
|
2387
|
-
return {
|
|
2388
|
-
success: false,
|
|
2389
|
-
error: errorMessage
|
|
2390
|
-
};
|
|
2391
|
-
} finally {
|
|
2392
|
-
setIsUploading(false);
|
|
2393
|
-
}
|
|
2394
|
-
}, [supabase, appName, orgId]);
|
|
2395
|
-
const handleGetPublicUrl = useCallback5((path) => {
|
|
2396
|
-
return getPublicUrl(supabase, path);
|
|
2397
|
-
}, [supabase]);
|
|
2398
|
-
const handleGetSignedUrl = useCallback5(async (path, expiresIn) => {
|
|
2399
|
-
try {
|
|
2400
|
-
const result = await getSignedUrl(supabase, path, {
|
|
2401
|
-
appName,
|
|
2402
|
-
orgId,
|
|
2403
|
-
expiresIn
|
|
2404
|
-
});
|
|
2405
|
-
return result?.url || null;
|
|
2406
|
-
} catch (error) {
|
|
2407
|
-
console.error("Failed to get signed URL:", error);
|
|
2408
|
-
return null;
|
|
2409
|
-
}
|
|
2410
|
-
}, [supabase, appName, orgId]);
|
|
2411
|
-
const handleDeleteFile = useCallback5(async (path) => {
|
|
2412
|
-
try {
|
|
2413
|
-
const result = await deleteFile(supabase, path);
|
|
2414
|
-
if (result.success) {
|
|
2415
|
-
await refreshFiles();
|
|
2416
|
-
}
|
|
2417
|
-
return result;
|
|
2418
|
-
} catch (error) {
|
|
2419
|
-
return {
|
|
2420
|
-
success: false,
|
|
2421
|
-
error: error instanceof Error ? error.message : "Delete failed"
|
|
2422
|
-
};
|
|
2423
|
-
}
|
|
2424
|
-
}, [supabase]);
|
|
2425
|
-
const handleArchiveFile = useCallback5(async (path) => {
|
|
2426
|
-
try {
|
|
2427
|
-
const result = await archiveFile(supabase, path, { appName, orgId });
|
|
2428
|
-
if (result.success) {
|
|
2429
|
-
await refreshFiles();
|
|
2430
|
-
}
|
|
2431
|
-
return result;
|
|
2432
|
-
} catch (error) {
|
|
2433
|
-
return {
|
|
2434
|
-
success: false,
|
|
2435
|
-
error: error instanceof Error ? error.message : "Archive failed"
|
|
2436
|
-
};
|
|
2437
|
-
}
|
|
2438
|
-
}, [supabase, appName, orgId]);
|
|
2439
|
-
const handleListFiles = useCallback5(async (options = {}) => {
|
|
2440
|
-
setIsListing(true);
|
|
2441
|
-
setListError(null);
|
|
2442
|
-
try {
|
|
2443
|
-
const listOptions = {
|
|
2444
|
-
appName,
|
|
2445
|
-
orgId,
|
|
2446
|
-
...options
|
|
2447
|
-
};
|
|
2448
|
-
const result = await listFiles(supabase, listOptions);
|
|
2449
|
-
setFiles(result.files);
|
|
2450
|
-
return result;
|
|
2451
|
-
} catch (error) {
|
|
2452
|
-
const errorMessage = error instanceof Error ? error.message : "List failed";
|
|
2453
|
-
setListError(errorMessage);
|
|
2454
|
-
return { files: [], totalCount: 0, hasMore: false };
|
|
2455
|
-
} finally {
|
|
2456
|
-
setIsListing(false);
|
|
2457
|
-
}
|
|
2458
|
-
}, [supabase, appName, orgId]);
|
|
2459
|
-
const refreshFiles = useCallback5(async () => {
|
|
2460
|
-
await handleListFiles();
|
|
2461
|
-
}, [handleListFiles]);
|
|
2462
|
-
return {
|
|
2463
|
-
// Upload
|
|
2464
|
-
uploadFile: handleUploadFile,
|
|
2465
|
-
isUploading,
|
|
2466
|
-
uploadError,
|
|
2467
|
-
// URLs
|
|
2468
|
-
getPublicUrl: handleGetPublicUrl,
|
|
2469
|
-
getSignedUrl: handleGetSignedUrl,
|
|
2470
|
-
getFileUrl: handleGetPublicUrl,
|
|
2471
|
-
// Alias for getPublicUrl
|
|
2472
|
-
// File management
|
|
2473
|
-
deleteFile: handleDeleteFile,
|
|
2474
|
-
archiveFile: handleArchiveFile,
|
|
2475
|
-
// Listing
|
|
2476
|
-
listFiles: handleListFiles,
|
|
2477
|
-
isListing,
|
|
2478
|
-
listError,
|
|
2479
|
-
isLoading: isListing,
|
|
2480
|
-
// Alias for isListing
|
|
2481
|
-
error: listError,
|
|
2482
|
-
// Alias for listError
|
|
2483
|
-
// State
|
|
2484
|
-
files,
|
|
2485
|
-
refreshFiles
|
|
2486
|
-
};
|
|
2487
|
-
}
|
|
2488
|
-
function useFileUpload({ supabase, appName, orgId }) {
|
|
2489
|
-
const [uploadProgress, setUploadProgress] = useState9(0);
|
|
2490
|
-
const [isUploading, setIsUploading] = useState9(false);
|
|
2491
|
-
const [uploadError, setUploadError] = useState9(null);
|
|
2492
|
-
const uploadWithProgress = useCallback5(async (file, options = {}) => {
|
|
2493
|
-
setIsUploading(true);
|
|
2494
|
-
setUploadProgress(0);
|
|
2495
|
-
setUploadError(null);
|
|
2496
|
-
try {
|
|
2497
|
-
const progressInterval = setInterval(() => {
|
|
2498
|
-
setUploadProgress((prev) => Math.min(prev + 10, 90));
|
|
2499
|
-
}, 100);
|
|
2500
|
-
const uploadOptions = {
|
|
2501
|
-
appName,
|
|
2502
|
-
orgId,
|
|
2503
|
-
isPublic: false,
|
|
2504
|
-
...options
|
|
2505
|
-
};
|
|
2506
|
-
const result = await uploadFile(supabase, file, uploadOptions);
|
|
2507
|
-
clearInterval(progressInterval);
|
|
2508
|
-
setUploadProgress(100);
|
|
2509
|
-
if (!result.success) {
|
|
2510
|
-
setUploadError(result.error || "Upload failed");
|
|
2511
|
-
}
|
|
2512
|
-
return result;
|
|
2513
|
-
} catch (error) {
|
|
2514
|
-
const errorMessage = error instanceof Error ? error.message : "Upload failed";
|
|
2515
|
-
setUploadError(errorMessage);
|
|
2516
|
-
return {
|
|
2517
|
-
success: false,
|
|
2518
|
-
error: errorMessage
|
|
2519
|
-
};
|
|
2520
|
-
} finally {
|
|
2521
|
-
setIsUploading(false);
|
|
2522
|
-
setTimeout(() => setUploadProgress(0), 1e3);
|
|
2523
|
-
}
|
|
2524
|
-
}, [supabase, appName, orgId]);
|
|
2525
|
-
return {
|
|
2526
|
-
uploadWithProgress,
|
|
2527
|
-
uploadProgress,
|
|
2528
|
-
isUploading,
|
|
2529
|
-
uploadError
|
|
2530
|
-
};
|
|
2531
|
-
}
|
|
2532
|
-
|
|
2533
2108
|
// src/hooks/useFileReference.ts
|
|
2534
|
-
import { useState as
|
|
2109
|
+
import { useState as useState9, useCallback as useCallback5, useEffect as useEffect5, useRef as useRef2, useMemo as useMemo6 } from "react";
|
|
2535
2110
|
|
|
2536
2111
|
// src/utils/file-reference.ts
|
|
2112
|
+
init_organisationContext();
|
|
2537
2113
|
var FileReferenceServiceImpl = class {
|
|
2538
2114
|
constructor(supabase) {
|
|
2539
2115
|
this.supabase = supabase;
|
|
2540
2116
|
}
|
|
2541
2117
|
async createFileReference(options, file) {
|
|
2542
2118
|
try {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2119
|
+
if (!options.organisation_id) {
|
|
2120
|
+
throw new Error("organisation_id is required for file upload");
|
|
2121
|
+
}
|
|
2122
|
+
if (!options.table_name) {
|
|
2123
|
+
throw new Error("table_name is required for file upload");
|
|
2124
|
+
}
|
|
2125
|
+
if (!options.record_id) {
|
|
2126
|
+
throw new Error("record_id is required for file upload");
|
|
2127
|
+
}
|
|
2548
2128
|
const uploadResult = await uploadFile(this.supabase, file, {
|
|
2549
2129
|
appName: "file-reference",
|
|
2550
2130
|
orgId: options.organisation_id,
|
|
2551
2131
|
isPublic: options.is_public || false,
|
|
2552
|
-
customPath:
|
|
2132
|
+
customPath: options.category
|
|
2133
|
+
// Use category as the custom path
|
|
2553
2134
|
});
|
|
2554
2135
|
if (!uploadResult.success) {
|
|
2555
2136
|
throw new Error(`Failed to upload file: ${uploadResult.error}`);
|
|
2556
2137
|
}
|
|
2138
|
+
if (!uploadResult.path) {
|
|
2139
|
+
throw new Error("File upload did not return a path");
|
|
2140
|
+
}
|
|
2141
|
+
const filePath = uploadResult.path;
|
|
2557
2142
|
const metadata = await extractFileMetadata(file, {
|
|
2558
2143
|
appName: "file-reference",
|
|
2559
2144
|
orgId: options.organisation_id,
|
|
2560
2145
|
isPublic: options.is_public || false
|
|
2561
2146
|
}, "system");
|
|
2562
|
-
|
|
2147
|
+
await setOrganisationContext(this.supabase, options.organisation_id);
|
|
2148
|
+
const { data, error } = await this.supabase.rpc("data_file_reference_create", {
|
|
2563
2149
|
p_table_name: options.table_name,
|
|
2564
2150
|
p_record_id: options.record_id,
|
|
2565
2151
|
p_file_path: filePath,
|
|
@@ -2576,7 +2162,7 @@ var FileReferenceServiceImpl = class {
|
|
|
2576
2162
|
p_is_public: options.is_public || false
|
|
2577
2163
|
});
|
|
2578
2164
|
if (error) {
|
|
2579
|
-
await deleteFile(this.supabase, filePath);
|
|
2165
|
+
await deleteFile(this.supabase, filePath, options.is_public || false);
|
|
2580
2166
|
throw new Error(`Failed to create file reference: ${error.message}`);
|
|
2581
2167
|
}
|
|
2582
2168
|
const { data: fileRef, error: fetchError } = await this.supabase.from("file_references").select("*").eq("id", data).single();
|
|
@@ -2606,15 +2192,23 @@ var FileReferenceServiceImpl = class {
|
|
|
2606
2192
|
}
|
|
2607
2193
|
async getFileUrl(table_name, record_id, organisation_id) {
|
|
2608
2194
|
try {
|
|
2609
|
-
const
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2195
|
+
const fileRef = await this.getFileReference(table_name, record_id, organisation_id);
|
|
2196
|
+
if (!fileRef) {
|
|
2197
|
+
return null;
|
|
2198
|
+
}
|
|
2199
|
+
if (fileRef.is_public) {
|
|
2200
|
+
const { data: pathData } = await this.supabase.rpc("data_file_reference_url_get", {
|
|
2201
|
+
p_table_name: table_name,
|
|
2202
|
+
p_record_id: record_id,
|
|
2203
|
+
p_organisation_id: organisation_id
|
|
2204
|
+
});
|
|
2205
|
+
if (!pathData) {
|
|
2206
|
+
return null;
|
|
2207
|
+
}
|
|
2208
|
+
return getPublicUrl(this.supabase, pathData, true);
|
|
2209
|
+
} else {
|
|
2210
|
+
return await this.getSignedUrl(table_name, record_id, organisation_id);
|
|
2616
2211
|
}
|
|
2617
|
-
return data;
|
|
2618
2212
|
} catch (error) {
|
|
2619
2213
|
console.error("Error getting file URL:", error);
|
|
2620
2214
|
throw error;
|
|
@@ -2622,7 +2216,7 @@ var FileReferenceServiceImpl = class {
|
|
|
2622
2216
|
}
|
|
2623
2217
|
async getSignedUrl(table_name, record_id, organisation_id, expires_in = 3600) {
|
|
2624
2218
|
try {
|
|
2625
|
-
const { data, error } = await this.supabase.rpc("
|
|
2219
|
+
const { data: filePath, error } = await this.supabase.rpc("data_file_reference_signed_url_get", {
|
|
2626
2220
|
p_table_name: table_name,
|
|
2627
2221
|
p_record_id: record_id,
|
|
2628
2222
|
p_organisation_id: organisation_id,
|
|
@@ -2631,7 +2225,15 @@ var FileReferenceServiceImpl = class {
|
|
|
2631
2225
|
if (error) {
|
|
2632
2226
|
throw new Error(`Failed to get signed URL: ${error.message}`);
|
|
2633
2227
|
}
|
|
2634
|
-
|
|
2228
|
+
if (!filePath) {
|
|
2229
|
+
return null;
|
|
2230
|
+
}
|
|
2231
|
+
const signedUrlResult = await getSignedUrl(this.supabase, filePath, {
|
|
2232
|
+
appName: "file-reference",
|
|
2233
|
+
orgId: organisation_id,
|
|
2234
|
+
expiresIn: expires_in
|
|
2235
|
+
});
|
|
2236
|
+
return signedUrlResult?.url || null;
|
|
2635
2237
|
} catch (error) {
|
|
2636
2238
|
console.error("Error getting signed URL:", error);
|
|
2637
2239
|
throw error;
|
|
@@ -2651,7 +2253,8 @@ var FileReferenceServiceImpl = class {
|
|
|
2651
2253
|
}
|
|
2652
2254
|
async deleteFileReference(table_name, record_id, organisation_id, delete_file = false) {
|
|
2653
2255
|
try {
|
|
2654
|
-
const
|
|
2256
|
+
const fileRef = await this.getFileReference(table_name, record_id, organisation_id);
|
|
2257
|
+
const { error } = await this.supabase.rpc("data_file_reference_delete", {
|
|
2655
2258
|
p_table_name: table_name,
|
|
2656
2259
|
p_record_id: record_id,
|
|
2657
2260
|
p_organisation_id: organisation_id,
|
|
@@ -2660,6 +2263,9 @@ var FileReferenceServiceImpl = class {
|
|
|
2660
2263
|
if (error) {
|
|
2661
2264
|
throw new Error(`Failed to delete file reference: ${error.message}`);
|
|
2662
2265
|
}
|
|
2266
|
+
if (delete_file && fileRef) {
|
|
2267
|
+
await deleteFile(this.supabase, fileRef.file_path, fileRef.is_public || false);
|
|
2268
|
+
}
|
|
2663
2269
|
return true;
|
|
2664
2270
|
} catch (error) {
|
|
2665
2271
|
console.error("Error deleting file reference:", error);
|
|
@@ -2668,7 +2274,7 @@ var FileReferenceServiceImpl = class {
|
|
|
2668
2274
|
}
|
|
2669
2275
|
async listFileReferences(table_name, record_id, organisation_id) {
|
|
2670
2276
|
try {
|
|
2671
|
-
const { data, error } = await this.supabase.rpc("
|
|
2277
|
+
const { data, error } = await this.supabase.rpc("data_file_reference_list", {
|
|
2672
2278
|
p_table_name: table_name,
|
|
2673
2279
|
p_record_id: record_id,
|
|
2674
2280
|
p_organisation_id: organisation_id
|
|
@@ -2676,7 +2282,15 @@ var FileReferenceServiceImpl = class {
|
|
|
2676
2282
|
if (error) {
|
|
2677
2283
|
throw new Error(`Failed to list file references: ${error.message}`);
|
|
2678
2284
|
}
|
|
2679
|
-
|
|
2285
|
+
if (!data || data.length === 0) {
|
|
2286
|
+
return [];
|
|
2287
|
+
}
|
|
2288
|
+
const ids = data.map((item) => item.id);
|
|
2289
|
+
const { data: fullData, error: fetchError } = await this.supabase.from("file_references").select("*").in("id", ids);
|
|
2290
|
+
if (fetchError) {
|
|
2291
|
+
throw new Error(`Failed to fetch file references: ${fetchError.message}`);
|
|
2292
|
+
}
|
|
2293
|
+
return fullData || [];
|
|
2680
2294
|
} catch (error) {
|
|
2681
2295
|
console.error("Error listing file references:", error);
|
|
2682
2296
|
throw error;
|
|
@@ -2684,7 +2298,7 @@ var FileReferenceServiceImpl = class {
|
|
|
2684
2298
|
}
|
|
2685
2299
|
async getFileCount(table_name, record_id, organisation_id) {
|
|
2686
2300
|
try {
|
|
2687
|
-
const { data, error } = await this.supabase.rpc("
|
|
2301
|
+
const { data, error } = await this.supabase.rpc("data_file_reference_count_get", {
|
|
2688
2302
|
p_table_name: table_name,
|
|
2689
2303
|
p_record_id: record_id,
|
|
2690
2304
|
p_organisation_id: organisation_id
|
|
@@ -2698,6 +2312,78 @@ var FileReferenceServiceImpl = class {
|
|
|
2698
2312
|
throw error;
|
|
2699
2313
|
}
|
|
2700
2314
|
}
|
|
2315
|
+
async getFileReferenceById(id, organisation_id) {
|
|
2316
|
+
try {
|
|
2317
|
+
const { data, error } = await this.supabase.rpc("data_file_reference_get", {
|
|
2318
|
+
p_file_reference_id: id,
|
|
2319
|
+
p_organisation_id: organisation_id
|
|
2320
|
+
});
|
|
2321
|
+
if (error) {
|
|
2322
|
+
throw new Error(`Failed to get file reference by ID: ${error.message}`);
|
|
2323
|
+
}
|
|
2324
|
+
if (!data || data.length === 0) {
|
|
2325
|
+
return null;
|
|
2326
|
+
}
|
|
2327
|
+
return data[0];
|
|
2328
|
+
} catch (error) {
|
|
2329
|
+
console.error("Error getting file reference by ID:", error);
|
|
2330
|
+
throw error;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
async getFilesByCategory(table_name, record_id, category, organisation_id) {
|
|
2334
|
+
try {
|
|
2335
|
+
const { data, error } = await this.supabase.rpc("data_file_reference_by_category_list", {
|
|
2336
|
+
p_table_name: table_name,
|
|
2337
|
+
p_record_id: record_id,
|
|
2338
|
+
p_category: category,
|
|
2339
|
+
p_organisation_id: organisation_id
|
|
2340
|
+
});
|
|
2341
|
+
if (error) {
|
|
2342
|
+
throw new Error(`Failed to get files by category: ${error.message}`);
|
|
2343
|
+
}
|
|
2344
|
+
if (!data || data.length === 0) {
|
|
2345
|
+
return [];
|
|
2346
|
+
}
|
|
2347
|
+
const ids = data.map((item) => item.id);
|
|
2348
|
+
const { data: fullData, error: fetchError } = await this.supabase.from("file_references").select("*").in("id", ids);
|
|
2349
|
+
if (fetchError) {
|
|
2350
|
+
throw new Error(`Failed to fetch file references: ${fetchError.message}`);
|
|
2351
|
+
}
|
|
2352
|
+
return fullData || [];
|
|
2353
|
+
} catch (error) {
|
|
2354
|
+
console.error("Error getting files by category:", error);
|
|
2355
|
+
throw error;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
async uploadMultipleFiles(options, files) {
|
|
2359
|
+
const success = [];
|
|
2360
|
+
const failed = [];
|
|
2361
|
+
const results = [];
|
|
2362
|
+
for (const file of files) {
|
|
2363
|
+
try {
|
|
2364
|
+
const fileReference = await this.createFileReference(options, file);
|
|
2365
|
+
success.push(fileReference);
|
|
2366
|
+
results.push({
|
|
2367
|
+
file,
|
|
2368
|
+
result: {
|
|
2369
|
+
file_reference: fileReference,
|
|
2370
|
+
file_url: fileReference.is_public ? getPublicUrl(this.supabase, fileReference.file_path, true) : ""
|
|
2371
|
+
}
|
|
2372
|
+
});
|
|
2373
|
+
} catch (error) {
|
|
2374
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2375
|
+
failed.push({ file, error: message });
|
|
2376
|
+
results.push({ file, result: null, error: message });
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
return {
|
|
2380
|
+
success,
|
|
2381
|
+
failed,
|
|
2382
|
+
total: results.length,
|
|
2383
|
+
successful: success.length,
|
|
2384
|
+
results
|
|
2385
|
+
};
|
|
2386
|
+
}
|
|
2701
2387
|
};
|
|
2702
2388
|
function createFileReferenceService(supabase) {
|
|
2703
2389
|
return new FileReferenceServiceImpl(supabase);
|
|
@@ -2705,7 +2391,7 @@ function createFileReferenceService(supabase) {
|
|
|
2705
2391
|
async function uploadFileWithReference(supabase, options, file) {
|
|
2706
2392
|
const service = createFileReferenceService(supabase);
|
|
2707
2393
|
const fileReference = await service.createFileReference(options, file);
|
|
2708
|
-
const fileUrl = options.is_public ? getPublicUrl(supabase, fileReference.file_path) : await getSignedUrl(supabase, fileReference.file_path, {
|
|
2394
|
+
const fileUrl = options.is_public ? getPublicUrl(supabase, fileReference.file_path, true) : await getSignedUrl(supabase, fileReference.file_path, {
|
|
2709
2395
|
appName: "file-reference",
|
|
2710
2396
|
orgId: options.organisation_id,
|
|
2711
2397
|
expiresIn: 3600
|
|
@@ -2720,10 +2406,10 @@ async function uploadFileWithReference(supabase, options, file) {
|
|
|
2720
2406
|
|
|
2721
2407
|
// src/hooks/useFileReference.ts
|
|
2722
2408
|
function useFileReference(supabase) {
|
|
2723
|
-
const [isLoading, setIsLoading] =
|
|
2724
|
-
const [error, setError] =
|
|
2725
|
-
const service = createFileReferenceService(supabase);
|
|
2726
|
-
const uploadFile2 =
|
|
2409
|
+
const [isLoading, setIsLoading] = useState9(false);
|
|
2410
|
+
const [error, setError] = useState9(null);
|
|
2411
|
+
const service = useMemo6(() => createFileReferenceService(supabase), [supabase]);
|
|
2412
|
+
const uploadFile2 = useCallback5(async (options, file) => {
|
|
2727
2413
|
setIsLoading(true);
|
|
2728
2414
|
setError(null);
|
|
2729
2415
|
try {
|
|
@@ -2737,7 +2423,7 @@ function useFileReference(supabase) {
|
|
|
2737
2423
|
setIsLoading(false);
|
|
2738
2424
|
}
|
|
2739
2425
|
}, [supabase]);
|
|
2740
|
-
const getFileReference =
|
|
2426
|
+
const getFileReference = useCallback5(async (table_name, record_id, organisation_id) => {
|
|
2741
2427
|
setIsLoading(true);
|
|
2742
2428
|
setError(null);
|
|
2743
2429
|
try {
|
|
@@ -2750,7 +2436,7 @@ function useFileReference(supabase) {
|
|
|
2750
2436
|
setIsLoading(false);
|
|
2751
2437
|
}
|
|
2752
2438
|
}, [service]);
|
|
2753
|
-
const getFileUrl =
|
|
2439
|
+
const getFileUrl = useCallback5(async (table_name, record_id, organisation_id) => {
|
|
2754
2440
|
setIsLoading(true);
|
|
2755
2441
|
setError(null);
|
|
2756
2442
|
try {
|
|
@@ -2763,7 +2449,7 @@ function useFileReference(supabase) {
|
|
|
2763
2449
|
setIsLoading(false);
|
|
2764
2450
|
}
|
|
2765
2451
|
}, [service]);
|
|
2766
|
-
const getSignedUrl2 =
|
|
2452
|
+
const getSignedUrl2 = useCallback5(async (table_name, record_id, organisation_id, expires_in) => {
|
|
2767
2453
|
setIsLoading(true);
|
|
2768
2454
|
setError(null);
|
|
2769
2455
|
try {
|
|
@@ -2776,7 +2462,7 @@ function useFileReference(supabase) {
|
|
|
2776
2462
|
setIsLoading(false);
|
|
2777
2463
|
}
|
|
2778
2464
|
}, [service]);
|
|
2779
|
-
const updateFileReference =
|
|
2465
|
+
const updateFileReference = useCallback5(async (id, updates) => {
|
|
2780
2466
|
setIsLoading(true);
|
|
2781
2467
|
setError(null);
|
|
2782
2468
|
try {
|
|
@@ -2789,7 +2475,7 @@ function useFileReference(supabase) {
|
|
|
2789
2475
|
setIsLoading(false);
|
|
2790
2476
|
}
|
|
2791
2477
|
}, [service]);
|
|
2792
|
-
const deleteFileReference =
|
|
2478
|
+
const deleteFileReference = useCallback5(async (table_name, record_id, organisation_id, delete_file) => {
|
|
2793
2479
|
setIsLoading(true);
|
|
2794
2480
|
setError(null);
|
|
2795
2481
|
try {
|
|
@@ -2802,7 +2488,7 @@ function useFileReference(supabase) {
|
|
|
2802
2488
|
setIsLoading(false);
|
|
2803
2489
|
}
|
|
2804
2490
|
}, [service]);
|
|
2805
|
-
const listFileReferences =
|
|
2491
|
+
const listFileReferences = useCallback5(async (table_name, record_id, organisation_id) => {
|
|
2806
2492
|
setIsLoading(true);
|
|
2807
2493
|
setError(null);
|
|
2808
2494
|
try {
|
|
@@ -2815,7 +2501,7 @@ function useFileReference(supabase) {
|
|
|
2815
2501
|
setIsLoading(false);
|
|
2816
2502
|
}
|
|
2817
2503
|
}, [service]);
|
|
2818
|
-
const getFileCount =
|
|
2504
|
+
const getFileCount = useCallback5(async (table_name, record_id, organisation_id) => {
|
|
2819
2505
|
setIsLoading(true);
|
|
2820
2506
|
setError(null);
|
|
2821
2507
|
try {
|
|
@@ -2828,7 +2514,33 @@ function useFileReference(supabase) {
|
|
|
2828
2514
|
setIsLoading(false);
|
|
2829
2515
|
}
|
|
2830
2516
|
}, [service]);
|
|
2831
|
-
const
|
|
2517
|
+
const getFileReferenceById = useCallback5(async (id, organisation_id) => {
|
|
2518
|
+
setIsLoading(true);
|
|
2519
|
+
setError(null);
|
|
2520
|
+
try {
|
|
2521
|
+
return await service.getFileReferenceById(id, organisation_id);
|
|
2522
|
+
} catch (err) {
|
|
2523
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to get file reference by ID";
|
|
2524
|
+
setError(errorMessage);
|
|
2525
|
+
return null;
|
|
2526
|
+
} finally {
|
|
2527
|
+
setIsLoading(false);
|
|
2528
|
+
}
|
|
2529
|
+
}, [service]);
|
|
2530
|
+
const getFilesByCategory = useCallback5(async (table_name, record_id, category, organisation_id) => {
|
|
2531
|
+
setIsLoading(true);
|
|
2532
|
+
setError(null);
|
|
2533
|
+
try {
|
|
2534
|
+
return await service.getFilesByCategory(table_name, record_id, category, organisation_id);
|
|
2535
|
+
} catch (err) {
|
|
2536
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to get files by category";
|
|
2537
|
+
setError(errorMessage);
|
|
2538
|
+
return [];
|
|
2539
|
+
} finally {
|
|
2540
|
+
setIsLoading(false);
|
|
2541
|
+
}
|
|
2542
|
+
}, [service]);
|
|
2543
|
+
const clearError = useCallback5(() => {
|
|
2832
2544
|
setError(null);
|
|
2833
2545
|
}, []);
|
|
2834
2546
|
return {
|
|
@@ -2836,11 +2548,13 @@ function useFileReference(supabase) {
|
|
|
2836
2548
|
error,
|
|
2837
2549
|
uploadFile: uploadFile2,
|
|
2838
2550
|
getFileReference,
|
|
2551
|
+
getFileReferenceById,
|
|
2839
2552
|
getFileUrl,
|
|
2840
2553
|
getSignedUrl: getSignedUrl2,
|
|
2841
2554
|
updateFileReference,
|
|
2842
2555
|
deleteFileReference,
|
|
2843
2556
|
listFileReferences,
|
|
2557
|
+
getFilesByCategory,
|
|
2844
2558
|
getFileCount,
|
|
2845
2559
|
clearError
|
|
2846
2560
|
};
|
|
@@ -2857,31 +2571,32 @@ function useFileReferenceForRecord(supabase, table_name, record_id, organisation
|
|
|
2857
2571
|
getFileCount,
|
|
2858
2572
|
clearError
|
|
2859
2573
|
} = useFileReference(supabase);
|
|
2860
|
-
const [fileUrl, setFileUrl] =
|
|
2861
|
-
const [fileReference, setFileReference] =
|
|
2862
|
-
const [fileReferences, setFileReferences] =
|
|
2863
|
-
const [fileCount, setFileCount] =
|
|
2864
|
-
const
|
|
2574
|
+
const [fileUrl, setFileUrl] = useState9(null);
|
|
2575
|
+
const [fileReference, setFileReference] = useState9(null);
|
|
2576
|
+
const [fileReferences, setFileReferences] = useState9([]);
|
|
2577
|
+
const [fileCount, setFileCount] = useState9(0);
|
|
2578
|
+
const urlRefreshIntervalRef = useRef2(null);
|
|
2579
|
+
const loadFileReference = useCallback5(async () => {
|
|
2865
2580
|
const reference = await getFileReference(table_name, record_id, organisation_id);
|
|
2866
2581
|
setFileReference(reference);
|
|
2867
2582
|
return reference;
|
|
2868
2583
|
}, [getFileReference, table_name, record_id, organisation_id]);
|
|
2869
|
-
const loadFileUrl =
|
|
2584
|
+
const loadFileUrl = useCallback5(async () => {
|
|
2870
2585
|
const url = await getFileUrl(table_name, record_id, organisation_id);
|
|
2871
2586
|
setFileUrl(url);
|
|
2872
2587
|
return url;
|
|
2873
2588
|
}, [getFileUrl, table_name, record_id, organisation_id]);
|
|
2874
|
-
const loadFileReferences =
|
|
2589
|
+
const loadFileReferences = useCallback5(async () => {
|
|
2875
2590
|
const references = await listFileReferences(table_name, record_id, organisation_id);
|
|
2876
2591
|
setFileReferences(references);
|
|
2877
2592
|
return references;
|
|
2878
2593
|
}, [listFileReferences, table_name, record_id, organisation_id]);
|
|
2879
|
-
const loadFileCount =
|
|
2594
|
+
const loadFileCount = useCallback5(async () => {
|
|
2880
2595
|
const count = await getFileCount(table_name, record_id, organisation_id);
|
|
2881
2596
|
setFileCount(count);
|
|
2882
2597
|
return count;
|
|
2883
2598
|
}, [getFileCount, table_name, record_id, organisation_id]);
|
|
2884
|
-
const deleteFile2 =
|
|
2599
|
+
const deleteFile2 = useCallback5(async (delete_file) => {
|
|
2885
2600
|
const success = await deleteFileReference(table_name, record_id, organisation_id, delete_file);
|
|
2886
2601
|
if (success) {
|
|
2887
2602
|
setFileReference(null);
|
|
@@ -2890,6 +2605,24 @@ function useFileReferenceForRecord(supabase, table_name, record_id, organisation
|
|
|
2890
2605
|
}
|
|
2891
2606
|
return success;
|
|
2892
2607
|
}, [deleteFileReference, table_name, record_id, organisation_id, loadFileCount]);
|
|
2608
|
+
useEffect5(() => {
|
|
2609
|
+
if (!fileReference || fileReference.is_public) {
|
|
2610
|
+
if (urlRefreshIntervalRef.current) {
|
|
2611
|
+
clearInterval(urlRefreshIntervalRef.current);
|
|
2612
|
+
urlRefreshIntervalRef.current = null;
|
|
2613
|
+
}
|
|
2614
|
+
return;
|
|
2615
|
+
}
|
|
2616
|
+
urlRefreshIntervalRef.current = setInterval(() => {
|
|
2617
|
+
loadFileUrl();
|
|
2618
|
+
}, 55 * 60 * 1e3);
|
|
2619
|
+
return () => {
|
|
2620
|
+
if (urlRefreshIntervalRef.current) {
|
|
2621
|
+
clearInterval(urlRefreshIntervalRef.current);
|
|
2622
|
+
urlRefreshIntervalRef.current = null;
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
}, [fileReference, loadFileUrl]);
|
|
2893
2626
|
return {
|
|
2894
2627
|
isLoading,
|
|
2895
2628
|
error,
|
|
@@ -2906,11 +2639,579 @@ function useFileReferenceForRecord(supabase, table_name, record_id, organisation
|
|
|
2906
2639
|
clearError
|
|
2907
2640
|
};
|
|
2908
2641
|
}
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2642
|
+
function useFileReferenceById(supabase, fileReferenceId, organisationId) {
|
|
2643
|
+
const {
|
|
2644
|
+
isLoading,
|
|
2645
|
+
error,
|
|
2646
|
+
getFileReferenceById,
|
|
2647
|
+
clearError
|
|
2648
|
+
} = useFileReference(supabase);
|
|
2649
|
+
const [fileReference, setFileReference] = useState9(null);
|
|
2650
|
+
const [fileUrl, setFileUrl] = useState9(null);
|
|
2651
|
+
const loadFileReference = useCallback5(async () => {
|
|
2652
|
+
if (!fileReferenceId || !organisationId) {
|
|
2653
|
+
setFileReference(null);
|
|
2654
|
+
setFileUrl(null);
|
|
2655
|
+
return null;
|
|
2656
|
+
}
|
|
2657
|
+
const reference = await getFileReferenceById(fileReferenceId, organisationId);
|
|
2658
|
+
setFileReference(reference);
|
|
2659
|
+
return reference;
|
|
2660
|
+
}, [getFileReferenceById, fileReferenceId, organisationId]);
|
|
2661
|
+
useEffect5(() => {
|
|
2662
|
+
loadFileReference();
|
|
2663
|
+
}, [loadFileReference]);
|
|
2664
|
+
useEffect5(() => {
|
|
2665
|
+
if (!fileReference || !fileReferenceId || !organisationId) {
|
|
2666
|
+
setFileUrl(null);
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
const loadUrl = async () => {
|
|
2670
|
+
const service = createFileReferenceService(supabase);
|
|
2671
|
+
const url = await service.getFileUrl(
|
|
2672
|
+
fileReference.table_name,
|
|
2673
|
+
fileReference.record_id,
|
|
2674
|
+
organisationId
|
|
2675
|
+
);
|
|
2676
|
+
setFileUrl(url);
|
|
2677
|
+
};
|
|
2678
|
+
loadUrl();
|
|
2679
|
+
}, [fileReference, fileReferenceId, organisationId, supabase]);
|
|
2680
|
+
return {
|
|
2681
|
+
isLoading,
|
|
2682
|
+
error,
|
|
2683
|
+
fileReference,
|
|
2684
|
+
fileUrl,
|
|
2685
|
+
loadFileReference,
|
|
2686
|
+
clearError
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
function useFilesByCategory(supabase, table_name, record_id, category, organisation_id) {
|
|
2690
|
+
const {
|
|
2691
|
+
isLoading,
|
|
2692
|
+
error,
|
|
2693
|
+
getFilesByCategory,
|
|
2694
|
+
clearError
|
|
2695
|
+
} = useFileReference(supabase);
|
|
2696
|
+
const [fileReferences, setFileReferences] = useState9([]);
|
|
2697
|
+
const [fileUrls, setFileUrls] = useState9(/* @__PURE__ */ new Map());
|
|
2698
|
+
const loadFiles = useCallback5(async () => {
|
|
2699
|
+
if (!category || !organisation_id) {
|
|
2700
|
+
setFileReferences([]);
|
|
2701
|
+
setFileUrls(/* @__PURE__ */ new Map());
|
|
2702
|
+
return [];
|
|
2703
|
+
}
|
|
2704
|
+
const files = await getFilesByCategory(table_name, record_id, category, organisation_id);
|
|
2705
|
+
setFileReferences(files);
|
|
2706
|
+
const urlMap = /* @__PURE__ */ new Map();
|
|
2707
|
+
for (const fileRef of files) {
|
|
2708
|
+
try {
|
|
2709
|
+
let url = null;
|
|
2710
|
+
if (fileRef.is_public) {
|
|
2711
|
+
url = getPublicUrl(supabase, fileRef.file_path, true);
|
|
2712
|
+
} else {
|
|
2713
|
+
const signedUrlResult = await getSignedUrl(supabase, fileRef.file_path, {
|
|
2714
|
+
appName: "file-reference",
|
|
2715
|
+
orgId: organisation_id,
|
|
2716
|
+
expiresIn: 3600
|
|
2717
|
+
});
|
|
2718
|
+
url = signedUrlResult?.url || null;
|
|
2719
|
+
}
|
|
2720
|
+
if (url) {
|
|
2721
|
+
urlMap.set(fileRef.id, url);
|
|
2722
|
+
}
|
|
2723
|
+
} catch (err) {
|
|
2724
|
+
console.error(`Failed to load URL for file ${fileRef.id}:`, err);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
setFileUrls(urlMap);
|
|
2728
|
+
return files;
|
|
2729
|
+
}, [table_name, record_id, category, organisation_id, supabase, getFilesByCategory]);
|
|
2730
|
+
useEffect5(() => {
|
|
2731
|
+
loadFiles();
|
|
2732
|
+
}, [loadFiles]);
|
|
2733
|
+
return {
|
|
2734
|
+
isLoading,
|
|
2735
|
+
error,
|
|
2736
|
+
fileReferences,
|
|
2737
|
+
fileUrls,
|
|
2738
|
+
loadFiles,
|
|
2739
|
+
clearError
|
|
2740
|
+
};
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
// src/components/FileUpload/FileUpload.tsx
|
|
2744
|
+
import { useState as useState10, useCallback as useCallback6, useRef as useRef3, useEffect as useEffect6, useMemo as useMemo7 } from "react";
|
|
2745
|
+
|
|
2746
|
+
// src/utils/appIdResolver.ts
|
|
2747
|
+
async function getAppId(supabase, appName) {
|
|
2748
|
+
try {
|
|
2749
|
+
const { data, error } = await supabase.from("rbac_apps").select("id").ilike("name", appName).eq("is_active", true).single();
|
|
2750
|
+
if (error) {
|
|
2751
|
+
console.error("Failed to resolve app ID for app name:", appName, error);
|
|
2752
|
+
return null;
|
|
2753
|
+
}
|
|
2754
|
+
return data?.id || null;
|
|
2755
|
+
} catch (error) {
|
|
2756
|
+
console.error("Error resolving app ID for app name:", appName, error);
|
|
2757
|
+
return null;
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
var CachedAppIdResolver = class {
|
|
2761
|
+
constructor() {
|
|
2762
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2763
|
+
this.ttl = 5 * 60 * 1e3;
|
|
2764
|
+
}
|
|
2765
|
+
// 5 minutes
|
|
2766
|
+
async getAppId(supabase, appName) {
|
|
2767
|
+
const now = Date.now();
|
|
2768
|
+
const cached = this.cache.get(appName);
|
|
2769
|
+
if (cached && cached.expires > now) {
|
|
2770
|
+
return cached.id;
|
|
2771
|
+
}
|
|
2772
|
+
const id = await getAppId(supabase, appName);
|
|
2773
|
+
this.cache.set(appName, { id, expires: now + this.ttl });
|
|
2774
|
+
return id;
|
|
2775
|
+
}
|
|
2776
|
+
clearCache() {
|
|
2777
|
+
this.cache.clear();
|
|
2778
|
+
}
|
|
2779
|
+
clearCacheForApp(appName) {
|
|
2780
|
+
this.cache.delete(appName);
|
|
2781
|
+
}
|
|
2782
|
+
};
|
|
2783
|
+
var cachedAppIdResolver = new CachedAppIdResolver();
|
|
2784
|
+
|
|
2785
|
+
// src/components/FileUpload/FileUpload.tsx
|
|
2786
|
+
import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2787
|
+
function FileUpload({
|
|
2788
|
+
supabase,
|
|
2789
|
+
table_name,
|
|
2790
|
+
record_id,
|
|
2791
|
+
organisation_id,
|
|
2792
|
+
app_id,
|
|
2793
|
+
category,
|
|
2794
|
+
accept = "*/*",
|
|
2795
|
+
maxSize = 10 * 1024 * 1024,
|
|
2796
|
+
// 10MB default
|
|
2797
|
+
multiple = false,
|
|
2798
|
+
disabled = false,
|
|
2799
|
+
isPublic = false,
|
|
2800
|
+
className = "",
|
|
2801
|
+
showPreview = true,
|
|
2802
|
+
showProgress = true,
|
|
2803
|
+
onUploadSuccess,
|
|
2804
|
+
onUploadError,
|
|
2805
|
+
onProgress,
|
|
2806
|
+
children
|
|
2807
|
+
}) {
|
|
2808
|
+
const [isDragging, setIsDragging] = useState10(false);
|
|
2809
|
+
const [uploadStates, setUploadStates] = useState10(/* @__PURE__ */ new Map());
|
|
2810
|
+
const [resolvedAppId, setResolvedAppId] = useState10(app_id || null);
|
|
2811
|
+
const [isResolvingAppId, setIsResolvingAppId] = useState10(!app_id);
|
|
2812
|
+
const [appIdError, setAppIdError] = useState10(null);
|
|
2813
|
+
const fileInputRef = useRef3(null);
|
|
2814
|
+
const { uploadFile: uploadFile2, isLoading, error } = useFileReference(supabase);
|
|
2815
|
+
useEffect6(() => {
|
|
2816
|
+
if (app_id) {
|
|
2817
|
+
setResolvedAppId(app_id);
|
|
2818
|
+
setIsResolvingAppId(false);
|
|
2819
|
+
setAppIdError(null);
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
const resolveAppId = async () => {
|
|
2823
|
+
setIsResolvingAppId(true);
|
|
2824
|
+
setAppIdError(null);
|
|
2825
|
+
try {
|
|
2826
|
+
const appName = getCurrentAppName();
|
|
2827
|
+
if (!appName) {
|
|
2828
|
+
const errorMsg = "App ID is required. Either provide app_id prop or set app name via setRBACAppName()";
|
|
2829
|
+
setAppIdError(errorMsg);
|
|
2830
|
+
setIsResolvingAppId(false);
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
const resolvedId = await getAppId(supabase, appName);
|
|
2834
|
+
if (!resolvedId) {
|
|
2835
|
+
const errorMsg = `Failed to resolve app ID for app name "${appName}". Make sure the app is registered in rbac_apps table.`;
|
|
2836
|
+
setAppIdError(errorMsg);
|
|
2837
|
+
setIsResolvingAppId(false);
|
|
2838
|
+
return;
|
|
2839
|
+
}
|
|
2840
|
+
setResolvedAppId(resolvedId);
|
|
2841
|
+
setIsResolvingAppId(false);
|
|
2842
|
+
} catch (err) {
|
|
2843
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to resolve app ID";
|
|
2844
|
+
setAppIdError(errorMessage);
|
|
2845
|
+
setIsResolvingAppId(false);
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
resolveAppId();
|
|
2849
|
+
}, [app_id, supabase]);
|
|
2850
|
+
const isUploading = useMemo7(() => {
|
|
2851
|
+
return uploadStates.size > 0 && Array.from(uploadStates.values()).some(
|
|
2852
|
+
(state) => state.progress.status === "uploading" || state.progress.status === "processing"
|
|
2853
|
+
);
|
|
2854
|
+
}, [uploadStates]);
|
|
2855
|
+
const isDisabled = useMemo7(() => {
|
|
2856
|
+
return disabled || isUploading || isResolvingAppId || !resolvedAppId;
|
|
2857
|
+
}, [disabled, isUploading, isResolvingAppId, resolvedAppId]);
|
|
2858
|
+
const generatePreview = useCallback6((file) => {
|
|
2859
|
+
return new Promise((resolve) => {
|
|
2860
|
+
if (!file.type.startsWith("image/")) {
|
|
2861
|
+
resolve(null);
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
const reader = new FileReader();
|
|
2865
|
+
reader.onload = (e) => {
|
|
2866
|
+
resolve(e.target?.result || null);
|
|
2867
|
+
};
|
|
2868
|
+
reader.onerror = () => resolve(null);
|
|
2869
|
+
reader.readAsDataURL(file);
|
|
2870
|
+
});
|
|
2871
|
+
}, []);
|
|
2872
|
+
const validateFile = useCallback6((file) => {
|
|
2873
|
+
if (file.size > maxSize) {
|
|
2874
|
+
return `File "${file.name}" exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`;
|
|
2875
|
+
}
|
|
2876
|
+
if (accept !== "*/*") {
|
|
2877
|
+
const acceptedTypes = accept.split(",").map((type) => type.trim());
|
|
2878
|
+
const fileExtension = "." + file.name.split(".").pop()?.toLowerCase();
|
|
2879
|
+
const fileMimeType = file.type;
|
|
2880
|
+
const isAccepted = acceptedTypes.some((accepted) => {
|
|
2881
|
+
if (accepted.startsWith(".")) {
|
|
2882
|
+
return accepted === fileExtension;
|
|
2883
|
+
} else if (accepted.includes("/*")) {
|
|
2884
|
+
const baseType = accepted.split("/")[0];
|
|
2885
|
+
return fileMimeType.startsWith(baseType + "/");
|
|
2886
|
+
} else {
|
|
2887
|
+
return accepted === fileMimeType;
|
|
2888
|
+
}
|
|
2889
|
+
});
|
|
2890
|
+
if (!isAccepted) {
|
|
2891
|
+
return `File "${file.name}" is not an accepted format. Accepted: ${accept}`;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
return null;
|
|
2895
|
+
}, [accept, maxSize]);
|
|
2896
|
+
const handleFileSelect = useCallback6(async (files) => {
|
|
2897
|
+
if (!files || files.length === 0) return;
|
|
2898
|
+
const fileArray = Array.from(files);
|
|
2899
|
+
const validationErrors = [];
|
|
2900
|
+
const validFiles = [];
|
|
2901
|
+
for (const file of fileArray) {
|
|
2902
|
+
const error2 = validateFile(file);
|
|
2903
|
+
if (error2) {
|
|
2904
|
+
validationErrors.push(error2);
|
|
2905
|
+
onUploadError?.(error2, file);
|
|
2906
|
+
} else {
|
|
2907
|
+
validFiles.push(file);
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
if (validFiles.length === 0) {
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
const newUploadStates = /* @__PURE__ */ new Map();
|
|
2914
|
+
for (const file of validFiles) {
|
|
2915
|
+
const fileId = `${file.name}-${file.size}-${Date.now()}`;
|
|
2916
|
+
const preview = showPreview ? await generatePreview(file) || void 0 : void 0;
|
|
2917
|
+
const progress = {
|
|
2918
|
+
loaded: 0,
|
|
2919
|
+
total: file.size,
|
|
2920
|
+
percentage: 0,
|
|
2921
|
+
fileName: file.name,
|
|
2922
|
+
status: "idle"
|
|
2923
|
+
};
|
|
2924
|
+
newUploadStates.set(fileId, {
|
|
2925
|
+
file,
|
|
2926
|
+
progress,
|
|
2927
|
+
preview
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
setUploadStates(newUploadStates);
|
|
2931
|
+
for (const [fileId, uploadState] of newUploadStates.entries()) {
|
|
2932
|
+
const { file } = uploadState;
|
|
2933
|
+
setUploadStates((prev) => {
|
|
2934
|
+
const updated = new Map(prev);
|
|
2935
|
+
const state = updated.get(fileId);
|
|
2936
|
+
if (state) {
|
|
2937
|
+
updated.set(fileId, {
|
|
2938
|
+
...state,
|
|
2939
|
+
progress: {
|
|
2940
|
+
...state.progress,
|
|
2941
|
+
status: "uploading"
|
|
2942
|
+
}
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2945
|
+
return updated;
|
|
2946
|
+
});
|
|
2947
|
+
try {
|
|
2948
|
+
const progressInterval = setInterval(() => {
|
|
2949
|
+
setUploadStates((prev) => {
|
|
2950
|
+
const updated = new Map(prev);
|
|
2951
|
+
const state = updated.get(fileId);
|
|
2952
|
+
if (state && state.progress.status === "uploading") {
|
|
2953
|
+
const estimatedProgress = Math.min(
|
|
2954
|
+
state.progress.percentage + 10,
|
|
2955
|
+
90
|
|
2956
|
+
);
|
|
2957
|
+
const newProgress = {
|
|
2958
|
+
...state.progress,
|
|
2959
|
+
percentage: estimatedProgress,
|
|
2960
|
+
loaded: Math.floor(estimatedProgress / 100 * file.size)
|
|
2961
|
+
};
|
|
2962
|
+
onProgress?.(newProgress);
|
|
2963
|
+
updated.set(fileId, {
|
|
2964
|
+
...state,
|
|
2965
|
+
progress: newProgress
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
return updated;
|
|
2969
|
+
});
|
|
2970
|
+
}, 200);
|
|
2971
|
+
if (!resolvedAppId) {
|
|
2972
|
+
const errorMsg = appIdError || "App ID not available. Please provide app_id prop or set app name.";
|
|
2973
|
+
throw new Error(errorMsg);
|
|
2974
|
+
}
|
|
2975
|
+
const result = await uploadFile2({
|
|
2976
|
+
table_name,
|
|
2977
|
+
record_id,
|
|
2978
|
+
organisation_id,
|
|
2979
|
+
app_id: resolvedAppId,
|
|
2980
|
+
category,
|
|
2981
|
+
is_public: isPublic
|
|
2982
|
+
}, file);
|
|
2983
|
+
clearInterval(progressInterval);
|
|
2984
|
+
if (result) {
|
|
2985
|
+
setUploadStates((prev) => {
|
|
2986
|
+
const updated = new Map(prev);
|
|
2987
|
+
const state = updated.get(fileId);
|
|
2988
|
+
if (state) {
|
|
2989
|
+
updated.set(fileId, {
|
|
2990
|
+
...state,
|
|
2991
|
+
progress: {
|
|
2992
|
+
...state.progress,
|
|
2993
|
+
status: "completed",
|
|
2994
|
+
percentage: 100,
|
|
2995
|
+
loaded: file.size
|
|
2996
|
+
},
|
|
2997
|
+
result
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
return updated;
|
|
3001
|
+
});
|
|
3002
|
+
const finalProgress = {
|
|
3003
|
+
loaded: file.size,
|
|
3004
|
+
total: file.size,
|
|
3005
|
+
percentage: 100,
|
|
3006
|
+
fileName: file.name,
|
|
3007
|
+
status: "completed"
|
|
3008
|
+
};
|
|
3009
|
+
onProgress?.(finalProgress);
|
|
3010
|
+
onUploadSuccess?.(result);
|
|
3011
|
+
setTimeout(() => {
|
|
3012
|
+
setUploadStates((prev) => {
|
|
3013
|
+
const updated = new Map(prev);
|
|
3014
|
+
updated.delete(fileId);
|
|
3015
|
+
return updated;
|
|
3016
|
+
});
|
|
3017
|
+
}, 3e3);
|
|
3018
|
+
} else {
|
|
3019
|
+
setUploadStates((prev) => {
|
|
3020
|
+
const updated = new Map(prev);
|
|
3021
|
+
const state = updated.get(fileId);
|
|
3022
|
+
if (state) {
|
|
3023
|
+
updated.set(fileId, {
|
|
3024
|
+
...state,
|
|
3025
|
+
progress: {
|
|
3026
|
+
...state.progress,
|
|
3027
|
+
status: "error",
|
|
3028
|
+
error: "Upload failed"
|
|
3029
|
+
}
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
return updated;
|
|
3033
|
+
});
|
|
3034
|
+
const errorProgress = {
|
|
3035
|
+
loaded: 0,
|
|
3036
|
+
total: file.size,
|
|
3037
|
+
percentage: 0,
|
|
3038
|
+
fileName: file.name,
|
|
3039
|
+
status: "error",
|
|
3040
|
+
error: "Upload failed"
|
|
3041
|
+
};
|
|
3042
|
+
onProgress?.(errorProgress);
|
|
3043
|
+
onUploadError?.("Upload failed", file);
|
|
3044
|
+
}
|
|
3045
|
+
} catch (err) {
|
|
3046
|
+
const errorMessage = err instanceof Error ? err.message : "Upload failed";
|
|
3047
|
+
setUploadStates((prev) => {
|
|
3048
|
+
const updated = new Map(prev);
|
|
3049
|
+
const state = updated.get(fileId);
|
|
3050
|
+
if (state) {
|
|
3051
|
+
updated.set(fileId, {
|
|
3052
|
+
...state,
|
|
3053
|
+
progress: {
|
|
3054
|
+
...state.progress,
|
|
3055
|
+
status: "error",
|
|
3056
|
+
error: errorMessage
|
|
3057
|
+
}
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
return updated;
|
|
3061
|
+
});
|
|
3062
|
+
const errorProgress = {
|
|
3063
|
+
loaded: 0,
|
|
3064
|
+
total: file.size,
|
|
3065
|
+
percentage: 0,
|
|
3066
|
+
fileName: file.name,
|
|
3067
|
+
status: "error",
|
|
3068
|
+
error: errorMessage
|
|
3069
|
+
};
|
|
3070
|
+
onProgress?.(errorProgress);
|
|
3071
|
+
onUploadError?.(errorMessage, file);
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
}, [uploadFile2, table_name, record_id, organisation_id, resolvedAppId, category, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);
|
|
3075
|
+
const handleDragOver = useCallback6((e) => {
|
|
3076
|
+
e.preventDefault();
|
|
3077
|
+
e.stopPropagation();
|
|
3078
|
+
if (!isDisabled) {
|
|
3079
|
+
setIsDragging(true);
|
|
3080
|
+
}
|
|
3081
|
+
}, [isDisabled]);
|
|
3082
|
+
const handleDragLeave = useCallback6((e) => {
|
|
3083
|
+
e.preventDefault();
|
|
3084
|
+
e.stopPropagation();
|
|
3085
|
+
setIsDragging(false);
|
|
3086
|
+
}, []);
|
|
3087
|
+
const handleDrop = useCallback6((e) => {
|
|
3088
|
+
e.preventDefault();
|
|
3089
|
+
e.stopPropagation();
|
|
3090
|
+
setIsDragging(false);
|
|
3091
|
+
if (isDisabled) return;
|
|
3092
|
+
const files = e.dataTransfer.files;
|
|
3093
|
+
handleFileSelect(files);
|
|
3094
|
+
}, [isDisabled, handleFileSelect]);
|
|
3095
|
+
const handleFileInputChange = useCallback6((e) => {
|
|
3096
|
+
handleFileSelect(e.target.files);
|
|
3097
|
+
if (e.target) {
|
|
3098
|
+
e.target.value = "";
|
|
3099
|
+
}
|
|
3100
|
+
}, [handleFileSelect]);
|
|
3101
|
+
const handleClick = useCallback6(() => {
|
|
3102
|
+
if (!isDisabled && fileInputRef.current) {
|
|
3103
|
+
fileInputRef.current.click();
|
|
3104
|
+
}
|
|
3105
|
+
}, [isDisabled]);
|
|
3106
|
+
const formatFileSize = (bytes) => {
|
|
3107
|
+
if (bytes === 0) return "0 Bytes";
|
|
3108
|
+
const k = 1024;
|
|
3109
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
3110
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
3111
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
3112
|
+
};
|
|
3113
|
+
const dragClasses = isDragging ? "border-main-500 bg-main-50" : "border-sec-300 hover:border-sec-400";
|
|
3114
|
+
const disabledClasses = isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-sec-50";
|
|
3115
|
+
return /* @__PURE__ */ jsxs16("div", { className: `space-y-4 ${className}`, children: [
|
|
3116
|
+
/* @__PURE__ */ jsxs16(
|
|
3117
|
+
"div",
|
|
3118
|
+
{
|
|
3119
|
+
className: `relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${dragClasses} ${disabledClasses}`,
|
|
3120
|
+
onDragOver: handleDragOver,
|
|
3121
|
+
onDragLeave: handleDragLeave,
|
|
3122
|
+
onDrop: handleDrop,
|
|
3123
|
+
onClick: !isDisabled ? handleClick : void 0,
|
|
3124
|
+
children: [
|
|
3125
|
+
children || /* @__PURE__ */ jsxs16("div", { className: "space-y-2", children: [
|
|
3126
|
+
/* @__PURE__ */ jsx20(
|
|
3127
|
+
"input",
|
|
3128
|
+
{
|
|
3129
|
+
ref: fileInputRef,
|
|
3130
|
+
type: "file",
|
|
3131
|
+
accept,
|
|
3132
|
+
multiple,
|
|
3133
|
+
onChange: handleFileInputChange,
|
|
3134
|
+
className: "hidden",
|
|
3135
|
+
disabled: isDisabled,
|
|
3136
|
+
"data-testid": "file-input"
|
|
3137
|
+
}
|
|
3138
|
+
),
|
|
3139
|
+
/* @__PURE__ */ jsx20("div", { className: "text-sec-600", children: isResolvingAppId ? "Resolving app configuration..." : isDragging ? "Drop files here..." : /* @__PURE__ */ jsxs16(Fragment5, { children: [
|
|
3140
|
+
/* @__PURE__ */ jsx20("span", { className: "font-medium", children: "Click to upload" }),
|
|
3141
|
+
" ",
|
|
3142
|
+
"or drag and drop"
|
|
3143
|
+
] }) }),
|
|
3144
|
+
/* @__PURE__ */ jsxs16("div", { className: "text-sm text-sec-500", children: [
|
|
3145
|
+
!isResolvingAppId && accept !== "*/*" && `Accepted formats: ${accept}`,
|
|
3146
|
+
!isResolvingAppId && maxSize && ` \u2022 Max size: ${Math.round(maxSize / 1024 / 1024)}MB`,
|
|
3147
|
+
!isResolvingAppId && multiple && " \u2022 Multiple files allowed"
|
|
3148
|
+
] })
|
|
3149
|
+
] }),
|
|
3150
|
+
isUploading && !showProgress && /* @__PURE__ */ jsx20("div", { className: "absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center", children: /* @__PURE__ */ jsx20("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-main-500" }) })
|
|
3151
|
+
]
|
|
3152
|
+
}
|
|
3153
|
+
),
|
|
3154
|
+
showProgress && uploadStates.size > 0 && /* @__PURE__ */ jsx20("div", { className: "space-y-2", children: Array.from(uploadStates.entries()).map(([fileId, uploadState]) => {
|
|
3155
|
+
const { file, progress, preview, result } = uploadState;
|
|
3156
|
+
const isError = progress.status === "error";
|
|
3157
|
+
const isCompleted = progress.status === "completed";
|
|
3158
|
+
const isUploading2 = progress.status === "uploading" || progress.status === "processing";
|
|
3159
|
+
return /* @__PURE__ */ jsxs16(
|
|
3160
|
+
"div",
|
|
3161
|
+
{
|
|
3162
|
+
className: `flex items-center space-x-3 p-3 rounded-lg border ${isError ? "bg-acc-50 border-acc-200" : isCompleted ? "bg-success-50 border-success-200" : "bg-sec-50 border-sec-200"}`,
|
|
3163
|
+
children: [
|
|
3164
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-shrink-0", children: preview ? /* @__PURE__ */ jsx20(
|
|
3165
|
+
"img",
|
|
3166
|
+
{
|
|
3167
|
+
src: preview,
|
|
3168
|
+
alt: file.name,
|
|
3169
|
+
className: "w-12 h-12 object-cover rounded"
|
|
3170
|
+
}
|
|
3171
|
+
) : /* @__PURE__ */ jsx20("div", { className: "w-12 h-12 flex items-center justify-center bg-sec-200 rounded", children: /* @__PURE__ */ jsx20("span", { className: "text-2xl", children: "\u{1F4C4}" }) }) }),
|
|
3172
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex-1 min-w-0", children: [
|
|
3173
|
+
/* @__PURE__ */ jsx20("div", { className: "font-medium text-sec-900 truncate", children: file.name }),
|
|
3174
|
+
/* @__PURE__ */ jsxs16("div", { className: "text-sm text-sec-500", children: [
|
|
3175
|
+
formatFileSize(file.size),
|
|
3176
|
+
isCompleted && result && " \u2022 Uploaded",
|
|
3177
|
+
isError && progress.error && ` \u2022 ${progress.error}`
|
|
3178
|
+
] }),
|
|
3179
|
+
showProgress && (isUploading2 || isError) && /* @__PURE__ */ jsxs16("div", { className: "mt-2", children: [
|
|
3180
|
+
/* @__PURE__ */ jsx20("div", { className: "w-full bg-sec-200 rounded-full h-2", children: /* @__PURE__ */ jsx20(
|
|
3181
|
+
"div",
|
|
3182
|
+
{
|
|
3183
|
+
className: `h-2 rounded-full transition-all duration-300 ${isError ? "bg-acc-500" : "bg-main-500"}`,
|
|
3184
|
+
style: { width: `${progress.percentage}%` }
|
|
3185
|
+
}
|
|
3186
|
+
) }),
|
|
3187
|
+
isUploading2 && /* @__PURE__ */ jsxs16("div", { className: "text-xs text-sec-500 mt-1", children: [
|
|
3188
|
+
progress.percentage,
|
|
3189
|
+
"% \u2022 ",
|
|
3190
|
+
formatFileSize(progress.loaded),
|
|
3191
|
+
" / ",
|
|
3192
|
+
formatFileSize(progress.total)
|
|
3193
|
+
] })
|
|
3194
|
+
] })
|
|
3195
|
+
] }),
|
|
3196
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex-shrink-0", children: [
|
|
3197
|
+
isCompleted && /* @__PURE__ */ jsx20("span", { className: "text-success-500 text-xl", children: "\u2713" }),
|
|
3198
|
+
isError && /* @__PURE__ */ jsx20("span", { className: "text-acc-500 text-xl", children: "\u2715" }),
|
|
3199
|
+
isUploading2 && /* @__PURE__ */ jsx20("div", { className: "animate-spin rounded-full h-5 w-5 border-b-2 border-main-500" })
|
|
3200
|
+
] })
|
|
3201
|
+
]
|
|
3202
|
+
},
|
|
3203
|
+
fileId
|
|
3204
|
+
);
|
|
3205
|
+
}) }),
|
|
3206
|
+
appIdError && /* @__PURE__ */ jsx20("div", { className: "p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600", children: appIdError }),
|
|
3207
|
+
error && /* @__PURE__ */ jsx20("div", { className: "p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600", children: error })
|
|
3208
|
+
] });
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3211
|
+
// src/components/FileDisplay/FileDisplay.tsx
|
|
3212
|
+
import { useState as useState11, useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
3213
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3214
|
+
function FileDisplay({
|
|
2914
3215
|
supabase,
|
|
2915
3216
|
table_name,
|
|
2916
3217
|
record_id,
|
|
@@ -2936,7 +3237,22 @@ function FileDisplay({
|
|
|
2936
3237
|
clearError
|
|
2937
3238
|
} = useFileReferenceForRecord(supabase, table_name, record_id, organisation_id);
|
|
2938
3239
|
const [imageError, setImageError] = useState11(false);
|
|
2939
|
-
|
|
3240
|
+
const [fileUrls, setFileUrls] = useState11(/* @__PURE__ */ new Map());
|
|
3241
|
+
const [loadingUrls, setLoadingUrls] = useState11(/* @__PURE__ */ new Set());
|
|
3242
|
+
const loadedFilesRef = useRef4(/* @__PURE__ */ new Set());
|
|
3243
|
+
const loadingUrlsRef = useRef4(/* @__PURE__ */ new Set());
|
|
3244
|
+
const fileReferencesRef = useRef4([]);
|
|
3245
|
+
useEffect7(() => {
|
|
3246
|
+
const currentIds = fileReferences.map((f) => f.id).join(",");
|
|
3247
|
+
const prevIds = fileReferencesRef.current.map((f) => f.id).join(",");
|
|
3248
|
+
if (currentIds !== prevIds) {
|
|
3249
|
+
fileReferencesRef.current = fileReferences;
|
|
3250
|
+
loadedFilesRef.current.clear();
|
|
3251
|
+
setFileUrls(/* @__PURE__ */ new Map());
|
|
3252
|
+
setLoadingUrls(/* @__PURE__ */ new Set());
|
|
3253
|
+
}
|
|
3254
|
+
}, [fileReferences]);
|
|
3255
|
+
useEffect7(() => {
|
|
2940
3256
|
loadFileCount();
|
|
2941
3257
|
if (category) {
|
|
2942
3258
|
loadFileReference();
|
|
@@ -2944,11 +3260,61 @@ function FileDisplay({
|
|
|
2944
3260
|
loadFileReferences();
|
|
2945
3261
|
}
|
|
2946
3262
|
}, [loadFileCount, loadFileReference, loadFileReferences, category]);
|
|
2947
|
-
|
|
3263
|
+
useEffect7(() => {
|
|
2948
3264
|
if (fileReference) {
|
|
2949
3265
|
loadFileUrl();
|
|
2950
3266
|
}
|
|
2951
3267
|
}, [fileReference, loadFileUrl]);
|
|
3268
|
+
useEffect7(() => {
|
|
3269
|
+
if (category || fileReferences.length === 0) return;
|
|
3270
|
+
const loadFileUrls = async () => {
|
|
3271
|
+
const urlsToLoad = fileReferences.filter((fileRef) => {
|
|
3272
|
+
return !loadedFilesRef.current.has(fileRef.id) && !loadingUrlsRef.current.has(fileRef.id);
|
|
3273
|
+
});
|
|
3274
|
+
if (urlsToLoad.length === 0) return;
|
|
3275
|
+
setLoadingUrls((prev) => {
|
|
3276
|
+
const updated = new Set(prev);
|
|
3277
|
+
urlsToLoad.forEach((fileRef) => {
|
|
3278
|
+
updated.add(fileRef.id);
|
|
3279
|
+
loadingUrlsRef.current.add(fileRef.id);
|
|
3280
|
+
});
|
|
3281
|
+
return updated;
|
|
3282
|
+
});
|
|
3283
|
+
for (const fileRef of urlsToLoad) {
|
|
3284
|
+
try {
|
|
3285
|
+
let url = null;
|
|
3286
|
+
if (fileRef.is_public) {
|
|
3287
|
+
url = getPublicUrl(supabase, fileRef.file_path, true);
|
|
3288
|
+
} else {
|
|
3289
|
+
const signedUrlResult = await getSignedUrl(supabase, fileRef.file_path, {
|
|
3290
|
+
appName: "file-reference",
|
|
3291
|
+
orgId: organisation_id,
|
|
3292
|
+
expiresIn: 3600
|
|
3293
|
+
});
|
|
3294
|
+
url = signedUrlResult?.url || null;
|
|
3295
|
+
}
|
|
3296
|
+
if (url) {
|
|
3297
|
+
setFileUrls((prev) => {
|
|
3298
|
+
const updated = new Map(prev);
|
|
3299
|
+
updated.set(fileRef.id, url);
|
|
3300
|
+
return updated;
|
|
3301
|
+
});
|
|
3302
|
+
loadedFilesRef.current.add(fileRef.id);
|
|
3303
|
+
}
|
|
3304
|
+
} catch (error2) {
|
|
3305
|
+
console.error(`Failed to load URL for file ${fileRef.id}:`, error2);
|
|
3306
|
+
} finally {
|
|
3307
|
+
setLoadingUrls((prev) => {
|
|
3308
|
+
const updated = new Set(prev);
|
|
3309
|
+
updated.delete(fileRef.id);
|
|
3310
|
+
loadingUrlsRef.current.delete(fileRef.id);
|
|
3311
|
+
return updated;
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
};
|
|
3316
|
+
loadFileUrls();
|
|
3317
|
+
}, [category, fileReferences.map((f) => f.id).join(","), supabase, organisation_id]);
|
|
2952
3318
|
const handleDelete = async () => {
|
|
2953
3319
|
if (window.confirm("Are you sure you want to delete this file?")) {
|
|
2954
3320
|
const success = await deleteFile2(true);
|
|
@@ -2970,7 +3336,7 @@ function FileDisplay({
|
|
|
2970
3336
|
if (fileType.includes("powerpoint") || fileType.includes("presentation")) return "\u{1F4CA}";
|
|
2971
3337
|
return "\u{1F4C1}";
|
|
2972
3338
|
};
|
|
2973
|
-
const
|
|
3339
|
+
const formatFileSize = (bytes) => {
|
|
2974
3340
|
if (bytes === 0) return "0 Bytes";
|
|
2975
3341
|
const k = 1024;
|
|
2976
3342
|
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
@@ -2978,15 +3344,15 @@ function FileDisplay({
|
|
|
2978
3344
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
2979
3345
|
};
|
|
2980
3346
|
if (isLoading) {
|
|
2981
|
-
return /* @__PURE__ */
|
|
3347
|
+
return /* @__PURE__ */ jsx21("div", { className: `flex items-center justify-center p-4 ${className}`, children: /* @__PURE__ */ jsx21("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-main-500" }) });
|
|
2982
3348
|
}
|
|
2983
3349
|
if (error) {
|
|
2984
|
-
return /* @__PURE__ */
|
|
2985
|
-
/* @__PURE__ */
|
|
3350
|
+
return /* @__PURE__ */ jsxs17("div", { className: `p-4 bg-acc-50 border border-acc-200 rounded-lg ${className}`, children: [
|
|
3351
|
+
/* @__PURE__ */ jsxs17("div", { className: "text-acc-600", children: [
|
|
2986
3352
|
"Error loading file: ",
|
|
2987
3353
|
error
|
|
2988
3354
|
] }),
|
|
2989
|
-
/* @__PURE__ */
|
|
3355
|
+
/* @__PURE__ */ jsx21(
|
|
2990
3356
|
"button",
|
|
2991
3357
|
{
|
|
2992
3358
|
onClick: clearError,
|
|
@@ -2997,16 +3363,16 @@ function FileDisplay({
|
|
|
2997
3363
|
] });
|
|
2998
3364
|
}
|
|
2999
3365
|
if (fileCount === 0) {
|
|
3000
|
-
return /* @__PURE__ */
|
|
3366
|
+
return /* @__PURE__ */ jsxs17("div", { className: `text-sec-500 text-center p-4 ${className}`, children: [
|
|
3001
3367
|
"No files found",
|
|
3002
3368
|
children
|
|
3003
3369
|
] });
|
|
3004
3370
|
}
|
|
3005
3371
|
if (category && fileReference) {
|
|
3006
3372
|
const isImage = fileReference.file_metadata.fileType?.startsWith("image/");
|
|
3007
|
-
return /* @__PURE__ */
|
|
3008
|
-
isImage && fileUrl && !imageError ? /* @__PURE__ */
|
|
3009
|
-
/* @__PURE__ */
|
|
3373
|
+
return /* @__PURE__ */ jsxs17("div", { className: `space-y-2 ${className}`, children: [
|
|
3374
|
+
isImage && fileUrl && !imageError ? /* @__PURE__ */ jsxs17("div", { className: "relative", children: [
|
|
3375
|
+
/* @__PURE__ */ jsx21(
|
|
3010
3376
|
"img",
|
|
3011
3377
|
{
|
|
3012
3378
|
src: fileUrl,
|
|
@@ -3015,30 +3381,32 @@ function FileDisplay({
|
|
|
3015
3381
|
onError: handleImageError
|
|
3016
3382
|
}
|
|
3017
3383
|
),
|
|
3018
|
-
showDelete && /* @__PURE__ */
|
|
3384
|
+
showDelete && /* @__PURE__ */ jsx21(
|
|
3019
3385
|
"button",
|
|
3020
3386
|
{
|
|
3021
3387
|
onClick: handleDelete,
|
|
3022
3388
|
className: "absolute top-2 right-2 bg-acc-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-sm hover:bg-acc-600",
|
|
3023
3389
|
title: "Delete file",
|
|
3390
|
+
"aria-label": "Delete file",
|
|
3024
3391
|
children: "\xD7"
|
|
3025
3392
|
}
|
|
3026
3393
|
)
|
|
3027
|
-
] }) : /* @__PURE__ */
|
|
3028
|
-
/* @__PURE__ */
|
|
3029
|
-
/* @__PURE__ */
|
|
3030
|
-
/* @__PURE__ */
|
|
3031
|
-
/* @__PURE__ */
|
|
3032
|
-
fileReference.file_metadata.fileSize &&
|
|
3394
|
+
] }) : /* @__PURE__ */ jsxs17("div", { className: "flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200", children: [
|
|
3395
|
+
/* @__PURE__ */ jsx21("span", { className: "text-2xl", children: getFileIcon(fileReference.file_metadata.fileType || "") }),
|
|
3396
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex-1 min-w-0", children: [
|
|
3397
|
+
/* @__PURE__ */ jsx21("div", { className: "font-medium text-sec-900 truncate", children: fileReference.file_metadata.fileName || "Unknown file" }),
|
|
3398
|
+
/* @__PURE__ */ jsxs17("div", { className: "text-sm text-sec-500", children: [
|
|
3399
|
+
fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize),
|
|
3033
3400
|
fileReference.file_metadata.fileType && ` \u2022 ${fileReference.file_metadata.fileType}`
|
|
3034
3401
|
] })
|
|
3035
3402
|
] }),
|
|
3036
|
-
showDelete && /* @__PURE__ */
|
|
3403
|
+
showDelete && /* @__PURE__ */ jsx21(
|
|
3037
3404
|
"button",
|
|
3038
3405
|
{
|
|
3039
3406
|
onClick: handleDelete,
|
|
3040
3407
|
className: "text-acc-500 hover:text-acc-700 p-1",
|
|
3041
3408
|
title: "Delete file",
|
|
3409
|
+
"aria-label": "Delete file",
|
|
3042
3410
|
children: "\xD7"
|
|
3043
3411
|
}
|
|
3044
3412
|
)
|
|
@@ -3046,12 +3414,14 @@ function FileDisplay({
|
|
|
3046
3414
|
children
|
|
3047
3415
|
] });
|
|
3048
3416
|
}
|
|
3049
|
-
return /* @__PURE__ */
|
|
3417
|
+
return /* @__PURE__ */ jsxs17("div", { className: `space-y-2 ${className}`, children: [
|
|
3050
3418
|
fileReferences.map((fileRef) => {
|
|
3051
3419
|
const isImage = fileRef.file_metadata.fileType?.startsWith("image/");
|
|
3052
|
-
const fileUrl2 =
|
|
3053
|
-
|
|
3054
|
-
|
|
3420
|
+
const fileUrl2 = fileUrls.get(fileRef.id) || null;
|
|
3421
|
+
const isLoadingUrl = loadingUrls.has(fileRef.id);
|
|
3422
|
+
const canDownload = !isImage && fileUrl2;
|
|
3423
|
+
return /* @__PURE__ */ jsxs17("div", { className: "flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200", children: [
|
|
3424
|
+
isLoadingUrl ? /* @__PURE__ */ jsx21("div", { className: "w-12 h-12 flex items-center justify-center", children: /* @__PURE__ */ jsx21("div", { className: "animate-spin rounded-full h-6 w-6 border-b-2 border-main-500" }) }) : isImage && fileUrl2 ? /* @__PURE__ */ jsx21(
|
|
3055
3425
|
"img",
|
|
3056
3426
|
{
|
|
3057
3427
|
src: fileUrl2,
|
|
@@ -3059,34 +3429,206 @@ function FileDisplay({
|
|
|
3059
3429
|
className: "w-12 h-12 object-cover rounded",
|
|
3060
3430
|
onError: handleImageError
|
|
3061
3431
|
}
|
|
3062
|
-
) : /* @__PURE__ */
|
|
3063
|
-
/* @__PURE__ */
|
|
3064
|
-
/* @__PURE__ */
|
|
3065
|
-
/* @__PURE__ */
|
|
3066
|
-
fileRef.file_metadata.fileSize &&
|
|
3432
|
+
) : /* @__PURE__ */ jsx21("span", { className: "text-2xl", children: getFileIcon(fileRef.file_metadata.fileType || "") }),
|
|
3433
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex-1 min-w-0", children: [
|
|
3434
|
+
/* @__PURE__ */ jsx21("div", { className: "font-medium text-sec-900 truncate", children: fileRef.file_metadata.fileName || "Unknown file" }),
|
|
3435
|
+
/* @__PURE__ */ jsxs17("div", { className: "text-sm text-sec-500", children: [
|
|
3436
|
+
fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize),
|
|
3067
3437
|
fileRef.file_metadata.fileType && ` \u2022 ${fileRef.file_metadata.fileType}`,
|
|
3068
3438
|
fileRef.file_metadata.category && ` \u2022 ${fileRef.file_metadata.category}`
|
|
3069
3439
|
] })
|
|
3070
3440
|
] }),
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3441
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center space-x-2", children: [
|
|
3442
|
+
canDownload && /* @__PURE__ */ jsx21(
|
|
3443
|
+
"a",
|
|
3444
|
+
{
|
|
3445
|
+
href: fileRef.file_path,
|
|
3446
|
+
download: fileRef.file_metadata.fileName || "download",
|
|
3447
|
+
className: "text-main-500 hover:text-main-700 p-1",
|
|
3448
|
+
title: "Download file",
|
|
3449
|
+
children: "\u2193"
|
|
3450
|
+
}
|
|
3451
|
+
),
|
|
3452
|
+
showDelete && /* @__PURE__ */ jsx21(
|
|
3453
|
+
"button",
|
|
3454
|
+
{
|
|
3455
|
+
onClick: () => deleteFile2(true),
|
|
3456
|
+
className: "text-acc-500 hover:text-acc-700 p-1",
|
|
3457
|
+
title: "Delete file",
|
|
3458
|
+
children: "\xD7"
|
|
3459
|
+
}
|
|
3460
|
+
)
|
|
3461
|
+
] })
|
|
3080
3462
|
] }, fileRef.id);
|
|
3081
3463
|
}),
|
|
3082
3464
|
children
|
|
3083
3465
|
] });
|
|
3084
3466
|
}
|
|
3085
3467
|
|
|
3468
|
+
// src/hooks/useEventLogo.ts
|
|
3469
|
+
import { useState as useState12, useEffect as useEffect8, useCallback as useCallback8, useMemo as useMemo8 } from "react";
|
|
3470
|
+
function defaultGenerateFallbackText(eventName) {
|
|
3471
|
+
if (!eventName) return "EV";
|
|
3472
|
+
return eventName.split(" ").map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
|
|
3473
|
+
}
|
|
3474
|
+
var authenticatedLogoCache = /* @__PURE__ */ new Map();
|
|
3475
|
+
var MAX_CACHE_SIZE = 100;
|
|
3476
|
+
function cleanupCache() {
|
|
3477
|
+
const now = Date.now();
|
|
3478
|
+
const entries = Array.from(authenticatedLogoCache.entries());
|
|
3479
|
+
entries.forEach(([key, value]) => {
|
|
3480
|
+
if (now - value.timestamp > value.ttl) {
|
|
3481
|
+
authenticatedLogoCache.delete(key);
|
|
3482
|
+
}
|
|
3483
|
+
});
|
|
3484
|
+
if (authenticatedLogoCache.size > MAX_CACHE_SIZE) {
|
|
3485
|
+
const sortedEntries = Array.from(authenticatedLogoCache.entries()).sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
3486
|
+
const toRemove = sortedEntries.slice(0, authenticatedLogoCache.size - MAX_CACHE_SIZE);
|
|
3487
|
+
toRemove.forEach(([key]) => authenticatedLogoCache.delete(key));
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
function useEventLogo(supabase, eventId, eventName, organisationId, options = {}) {
|
|
3491
|
+
const {
|
|
3492
|
+
cacheTtl = 30 * 60 * 1e3,
|
|
3493
|
+
// 30 minutes
|
|
3494
|
+
enableCache = true,
|
|
3495
|
+
validateImage = true,
|
|
3496
|
+
generateFallbackText = defaultGenerateFallbackText
|
|
3497
|
+
} = options;
|
|
3498
|
+
const [logoUrl, setLogoUrl] = useState12(null);
|
|
3499
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
3500
|
+
const [error, setError] = useState12(null);
|
|
3501
|
+
const fallbackText = useMemo8(() => {
|
|
3502
|
+
return eventName ? generateFallbackText(eventName) : "EV";
|
|
3503
|
+
}, [eventName, generateFallbackText]);
|
|
3504
|
+
const fetchLogo = useCallback8(async () => {
|
|
3505
|
+
if (!eventId || !organisationId || !supabase) {
|
|
3506
|
+
setLogoUrl(null);
|
|
3507
|
+
setIsLoading(false);
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3511
|
+
if (!uuidRegex.test(organisationId)) {
|
|
3512
|
+
console.warn("[useEventLogo] Invalid organisationId format (not a valid UUID):", organisationId);
|
|
3513
|
+
}
|
|
3514
|
+
const cacheKey = `event_logo_${eventId}_${organisationId}`;
|
|
3515
|
+
if (enableCache) {
|
|
3516
|
+
const cached = authenticatedLogoCache.get(cacheKey);
|
|
3517
|
+
if (cached && Date.now() - cached.timestamp < cached.ttl) {
|
|
3518
|
+
setLogoUrl(cached.data);
|
|
3519
|
+
setIsLoading(false);
|
|
3520
|
+
setError(null);
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
try {
|
|
3525
|
+
setIsLoading(true);
|
|
3526
|
+
setError(null);
|
|
3527
|
+
const service = createFileReferenceService(supabase);
|
|
3528
|
+
const files = await service.getFilesByCategory(
|
|
3529
|
+
"event",
|
|
3530
|
+
eventId,
|
|
3531
|
+
"event_logos" /* EVENT_LOGOS */,
|
|
3532
|
+
organisationId
|
|
3533
|
+
);
|
|
3534
|
+
if (!files || files.length === 0) {
|
|
3535
|
+
setLogoUrl(null);
|
|
3536
|
+
return;
|
|
3537
|
+
}
|
|
3538
|
+
const logoFileRef = files[0];
|
|
3539
|
+
const logoPath = logoFileRef.file_path;
|
|
3540
|
+
const isPublic = logoFileRef.is_public ?? true;
|
|
3541
|
+
let url = null;
|
|
3542
|
+
if (isPublic) {
|
|
3543
|
+
url = getPublicUrl(supabase, logoPath, true);
|
|
3544
|
+
} else {
|
|
3545
|
+
const signedUrlResult = await getSignedUrl(supabase, logoPath, {
|
|
3546
|
+
appName: "pace-core",
|
|
3547
|
+
orgId: organisationId,
|
|
3548
|
+
expiresIn: 3600
|
|
3549
|
+
});
|
|
3550
|
+
url = signedUrlResult?.url || null;
|
|
3551
|
+
}
|
|
3552
|
+
if (!url) {
|
|
3553
|
+
setLogoUrl(null);
|
|
3554
|
+
return;
|
|
3555
|
+
}
|
|
3556
|
+
if (validateImage) {
|
|
3557
|
+
try {
|
|
3558
|
+
const response = await fetch(url, { method: "HEAD" });
|
|
3559
|
+
if (!response.ok) {
|
|
3560
|
+
console.warn("[useEventLogo] Logo URL not accessible:", url);
|
|
3561
|
+
setLogoUrl(null);
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
} catch (fetchError) {
|
|
3565
|
+
console.warn("[useEventLogo] Error validating logo URL:", fetchError);
|
|
3566
|
+
setLogoUrl(null);
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
setLogoUrl(url);
|
|
3571
|
+
if (enableCache) {
|
|
3572
|
+
authenticatedLogoCache.set(cacheKey, {
|
|
3573
|
+
data: url,
|
|
3574
|
+
timestamp: Date.now(),
|
|
3575
|
+
ttl: cacheTtl
|
|
3576
|
+
});
|
|
3577
|
+
cleanupCache();
|
|
3578
|
+
}
|
|
3579
|
+
} catch (err) {
|
|
3580
|
+
console.error("[useEventLogo] Error fetching logo:", err);
|
|
3581
|
+
const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
|
|
3582
|
+
setError(error2);
|
|
3583
|
+
setLogoUrl(null);
|
|
3584
|
+
} finally {
|
|
3585
|
+
setIsLoading(false);
|
|
3586
|
+
}
|
|
3587
|
+
}, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
|
|
3588
|
+
useEffect8(() => {
|
|
3589
|
+
if (eventId && organisationId && supabase) {
|
|
3590
|
+
fetchLogo();
|
|
3591
|
+
} else {
|
|
3592
|
+
setLogoUrl(null);
|
|
3593
|
+
setIsLoading(false);
|
|
3594
|
+
setError(null);
|
|
3595
|
+
}
|
|
3596
|
+
}, [eventId, organisationId, supabase, cacheTtl, enableCache, validateImage, generateFallbackText]);
|
|
3597
|
+
const refetch = useCallback8(async () => {
|
|
3598
|
+
if (!eventId || !organisationId || !supabase) return;
|
|
3599
|
+
if (enableCache) {
|
|
3600
|
+
const cacheKey = `event_logo_${eventId}_${organisationId}`;
|
|
3601
|
+
authenticatedLogoCache.delete(cacheKey);
|
|
3602
|
+
}
|
|
3603
|
+
await fetchLogo();
|
|
3604
|
+
}, [fetchLogo, eventId, organisationId, supabase, enableCache]);
|
|
3605
|
+
return {
|
|
3606
|
+
logoUrl,
|
|
3607
|
+
fallbackText,
|
|
3608
|
+
isLoading,
|
|
3609
|
+
error,
|
|
3610
|
+
refetch
|
|
3611
|
+
};
|
|
3612
|
+
}
|
|
3613
|
+
function clearEventLogoCache() {
|
|
3614
|
+
for (const [key] of authenticatedLogoCache) {
|
|
3615
|
+
if (key.startsWith("event_logo_")) {
|
|
3616
|
+
authenticatedLogoCache.delete(key);
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
function getEventLogoCacheStats() {
|
|
3621
|
+
const keys = Array.from(authenticatedLogoCache.keys()).filter((key) => key.startsWith("event_logo_"));
|
|
3622
|
+
return {
|
|
3623
|
+
size: keys.length,
|
|
3624
|
+
keys
|
|
3625
|
+
};
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3086
3628
|
// src/components/Table/Table.tsx
|
|
3087
|
-
import * as
|
|
3088
|
-
import { jsx as
|
|
3089
|
-
var Table =
|
|
3629
|
+
import * as React18 from "react";
|
|
3630
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
3631
|
+
var Table = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3090
3632
|
"table",
|
|
3091
3633
|
{
|
|
3092
3634
|
ref,
|
|
@@ -3095,9 +3637,9 @@ var Table = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
3095
3637
|
}
|
|
3096
3638
|
));
|
|
3097
3639
|
Table.displayName = "Table";
|
|
3098
|
-
var TableHeader =
|
|
3640
|
+
var TableHeader = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
3099
3641
|
TableHeader.displayName = "TableHeader";
|
|
3100
|
-
var TableBody =
|
|
3642
|
+
var TableBody = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3101
3643
|
"tbody",
|
|
3102
3644
|
{
|
|
3103
3645
|
ref,
|
|
@@ -3106,7 +3648,7 @@ var TableBody = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
3106
3648
|
}
|
|
3107
3649
|
));
|
|
3108
3650
|
TableBody.displayName = "TableBody";
|
|
3109
|
-
var TableFooter =
|
|
3651
|
+
var TableFooter = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3110
3652
|
"tfoot",
|
|
3111
3653
|
{
|
|
3112
3654
|
ref,
|
|
@@ -3118,7 +3660,7 @@ var TableFooter = React17.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
3118
3660
|
}
|
|
3119
3661
|
));
|
|
3120
3662
|
TableFooter.displayName = "TableFooter";
|
|
3121
|
-
var TableRow =
|
|
3663
|
+
var TableRow = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3122
3664
|
"tr",
|
|
3123
3665
|
{
|
|
3124
3666
|
ref,
|
|
@@ -3130,7 +3672,7 @@ var TableRow = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
3130
3672
|
}
|
|
3131
3673
|
));
|
|
3132
3674
|
TableRow.displayName = "TableRow";
|
|
3133
|
-
var TableHead =
|
|
3675
|
+
var TableHead = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3134
3676
|
"th",
|
|
3135
3677
|
{
|
|
3136
3678
|
ref,
|
|
@@ -3142,7 +3684,7 @@ var TableHead = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
3142
3684
|
}
|
|
3143
3685
|
));
|
|
3144
3686
|
TableHead.displayName = "TableHead";
|
|
3145
|
-
var TableCell =
|
|
3687
|
+
var TableCell = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3146
3688
|
"td",
|
|
3147
3689
|
{
|
|
3148
3690
|
ref,
|
|
@@ -3151,7 +3693,7 @@ var TableCell = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
3151
3693
|
}
|
|
3152
3694
|
));
|
|
3153
3695
|
TableCell.displayName = "TableCell";
|
|
3154
|
-
var TableCaption =
|
|
3696
|
+
var TableCaption = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
3155
3697
|
"caption",
|
|
3156
3698
|
{
|
|
3157
3699
|
ref,
|
|
@@ -3162,9 +3704,9 @@ var TableCaption = React17.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
3162
3704
|
TableCaption.displayName = "TableCaption";
|
|
3163
3705
|
|
|
3164
3706
|
// src/components/PublicLayout/EventLogo.tsx
|
|
3165
|
-
import { useMemo as
|
|
3707
|
+
import { useMemo as useMemo9, useContext } from "react";
|
|
3166
3708
|
init_UnifiedAuthProvider();
|
|
3167
|
-
import { jsx as
|
|
3709
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
3168
3710
|
var sizeClasses = {
|
|
3169
3711
|
xs: "h-4 w-4 text-xs",
|
|
3170
3712
|
sm: "h-6 w-6 text-sm",
|
|
@@ -3173,7 +3715,7 @@ var sizeClasses = {
|
|
|
3173
3715
|
xl: "h-16 w-16 text-xl",
|
|
3174
3716
|
"2xl": "h-20 w-20 text-2xl"
|
|
3175
3717
|
};
|
|
3176
|
-
function
|
|
3718
|
+
function defaultGenerateFallbackText2(eventName) {
|
|
3177
3719
|
if (!eventName) return "EV";
|
|
3178
3720
|
return eventName.split(" ").map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
|
|
3179
3721
|
}
|
|
@@ -3195,7 +3737,7 @@ function EventLogoPublic({
|
|
|
3195
3737
|
const hasValidOrganisationId = organisationId && uuidRegex.test(organisationId);
|
|
3196
3738
|
if (!supabase) {
|
|
3197
3739
|
const effectiveSize = size || "md";
|
|
3198
|
-
return /* @__PURE__ */
|
|
3740
|
+
return /* @__PURE__ */ jsx23("div", { className: `${sizeClasses[effectiveSize]} ${className}`.trim(), title: `${eventName} logo (Supabase not configured)`, children: eventName ? defaultGenerateFallbackText2(eventName) : "EV" });
|
|
3199
3741
|
}
|
|
3200
3742
|
const {
|
|
3201
3743
|
logoUrl,
|
|
@@ -3213,36 +3755,36 @@ function EventLogoPublic({
|
|
|
3213
3755
|
supabase
|
|
3214
3756
|
}
|
|
3215
3757
|
);
|
|
3216
|
-
const sizeClass =
|
|
3217
|
-
const combinedClasses =
|
|
3758
|
+
const sizeClass = useMemo9(() => sizeClasses[size || "md"], [size]);
|
|
3759
|
+
const combinedClasses = useMemo9(() => {
|
|
3218
3760
|
const baseClasses = "flex items-center justify-center bg-gray-100 text-gray-600 font-semibold rounded";
|
|
3219
3761
|
return `${baseClasses} ${sizeClass} ${className}`.trim();
|
|
3220
3762
|
}, [sizeClass, className]);
|
|
3221
3763
|
if (!hasValidOrganisationId && !isLoading && !logoUrl && showFallback) {
|
|
3222
|
-
return /* @__PURE__ */
|
|
3764
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} logo (invalid organisation ID)`, children: fallbackText });
|
|
3223
3765
|
}
|
|
3224
3766
|
if (isLoading) {
|
|
3225
3767
|
if (LoadingComponent) {
|
|
3226
|
-
return /* @__PURE__ */
|
|
3768
|
+
return /* @__PURE__ */ jsx23(LoadingComponent, {});
|
|
3227
3769
|
}
|
|
3228
|
-
return /* @__PURE__ */
|
|
3770
|
+
return /* @__PURE__ */ jsx23("div", { className: `${combinedClasses} animate-pulse`, children: /* @__PURE__ */ jsx23("div", { className: "w-3/4 h-3/4 bg-gray-300 rounded" }) });
|
|
3229
3771
|
}
|
|
3230
3772
|
if (error) {
|
|
3231
3773
|
if (ErrorComponent) {
|
|
3232
|
-
return /* @__PURE__ */
|
|
3774
|
+
return /* @__PURE__ */ jsx23(ErrorComponent, { error });
|
|
3233
3775
|
}
|
|
3234
3776
|
if (showFallback) {
|
|
3235
|
-
return /* @__PURE__ */
|
|
3777
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} (logo unavailable)`, children: fallbackText });
|
|
3236
3778
|
}
|
|
3237
3779
|
return null;
|
|
3238
3780
|
}
|
|
3239
3781
|
if (!logoUrl) {
|
|
3240
3782
|
if (showFallback) {
|
|
3241
|
-
return /* @__PURE__ */
|
|
3783
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} logo`, children: fallbackText });
|
|
3242
3784
|
}
|
|
3243
3785
|
return null;
|
|
3244
3786
|
}
|
|
3245
|
-
return /* @__PURE__ */
|
|
3787
|
+
return /* @__PURE__ */ jsx23(
|
|
3246
3788
|
"img",
|
|
3247
3789
|
{
|
|
3248
3790
|
src: logoUrl,
|
|
@@ -3277,54 +3819,53 @@ function EventLogoAuthenticated({
|
|
|
3277
3819
|
const hasValidOrganisationId = organisationId && uuidRegex.test(organisationId);
|
|
3278
3820
|
if (!supabase) {
|
|
3279
3821
|
const effectiveSize = size || "md";
|
|
3280
|
-
return /* @__PURE__ */
|
|
3822
|
+
return /* @__PURE__ */ jsx23("div", { className: `${sizeClasses[effectiveSize]} ${className}`.trim(), title: `${eventName} logo (Supabase not configured)`, children: eventName ? defaultGenerateFallbackText2(eventName) : "EV" });
|
|
3281
3823
|
}
|
|
3282
3824
|
const {
|
|
3283
3825
|
logoUrl,
|
|
3284
3826
|
fallbackText,
|
|
3285
3827
|
isLoading,
|
|
3286
3828
|
error
|
|
3287
|
-
} =
|
|
3829
|
+
} = useEventLogo(
|
|
3830
|
+
supabase,
|
|
3288
3831
|
eventId,
|
|
3289
3832
|
eventName,
|
|
3290
3833
|
organisationId,
|
|
3291
|
-
// Always pass organisationId, let the hook handle validation
|
|
3292
3834
|
{
|
|
3293
3835
|
validateImage,
|
|
3294
|
-
generateFallbackText
|
|
3295
|
-
supabase
|
|
3836
|
+
generateFallbackText
|
|
3296
3837
|
}
|
|
3297
3838
|
);
|
|
3298
|
-
const sizeClass =
|
|
3299
|
-
const combinedClasses =
|
|
3839
|
+
const sizeClass = useMemo9(() => sizeClasses[size || "md"], [size]);
|
|
3840
|
+
const combinedClasses = useMemo9(() => {
|
|
3300
3841
|
const baseClasses = "flex items-center justify-center bg-gray-100 text-gray-600 font-semibold rounded";
|
|
3301
3842
|
return `${baseClasses} ${sizeClass} ${className}`.trim();
|
|
3302
3843
|
}, [sizeClass, className]);
|
|
3303
3844
|
if (!hasValidOrganisationId && !isLoading && !logoUrl && showFallback) {
|
|
3304
|
-
return /* @__PURE__ */
|
|
3845
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} logo (invalid organisation ID)`, children: fallbackText });
|
|
3305
3846
|
}
|
|
3306
3847
|
if (isLoading) {
|
|
3307
3848
|
if (LoadingComponent) {
|
|
3308
|
-
return /* @__PURE__ */
|
|
3849
|
+
return /* @__PURE__ */ jsx23(LoadingComponent, {});
|
|
3309
3850
|
}
|
|
3310
|
-
return /* @__PURE__ */
|
|
3851
|
+
return /* @__PURE__ */ jsx23("div", { className: `${combinedClasses} animate-pulse`, children: /* @__PURE__ */ jsx23("div", { className: "w-3/4 h-3/4 bg-gray-300 rounded" }) });
|
|
3311
3852
|
}
|
|
3312
3853
|
if (error) {
|
|
3313
3854
|
if (ErrorComponent) {
|
|
3314
|
-
return /* @__PURE__ */
|
|
3855
|
+
return /* @__PURE__ */ jsx23(ErrorComponent, { error });
|
|
3315
3856
|
}
|
|
3316
3857
|
if (showFallback) {
|
|
3317
|
-
return /* @__PURE__ */
|
|
3858
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} (logo unavailable)`, children: fallbackText });
|
|
3318
3859
|
}
|
|
3319
3860
|
return null;
|
|
3320
3861
|
}
|
|
3321
3862
|
if (!logoUrl) {
|
|
3322
3863
|
if (showFallback) {
|
|
3323
|
-
return /* @__PURE__ */
|
|
3864
|
+
return /* @__PURE__ */ jsx23("div", { className: combinedClasses, title: `${eventName} logo`, children: fallbackText });
|
|
3324
3865
|
}
|
|
3325
3866
|
return null;
|
|
3326
3867
|
}
|
|
3327
|
-
return /* @__PURE__ */
|
|
3868
|
+
return /* @__PURE__ */ jsx23(
|
|
3328
3869
|
"img",
|
|
3329
3870
|
{
|
|
3330
3871
|
src: logoUrl,
|
|
@@ -3349,14 +3890,14 @@ function EventLogo({
|
|
|
3349
3890
|
size = "md",
|
|
3350
3891
|
className = "",
|
|
3351
3892
|
showFallback = true,
|
|
3352
|
-
generateFallbackText =
|
|
3893
|
+
generateFallbackText = defaultGenerateFallbackText2,
|
|
3353
3894
|
validateImage = true,
|
|
3354
3895
|
loadingComponent: LoadingComponent,
|
|
3355
3896
|
errorComponent: ErrorComponent
|
|
3356
3897
|
}) {
|
|
3357
3898
|
const isPublicPage = useIsPublicPage();
|
|
3358
3899
|
if (isPublicPage) {
|
|
3359
|
-
return /* @__PURE__ */
|
|
3900
|
+
return /* @__PURE__ */ jsx23(
|
|
3360
3901
|
EventLogoPublic,
|
|
3361
3902
|
{
|
|
3362
3903
|
eventId,
|
|
@@ -3372,7 +3913,7 @@ function EventLogo({
|
|
|
3372
3913
|
}
|
|
3373
3914
|
);
|
|
3374
3915
|
}
|
|
3375
|
-
return /* @__PURE__ */
|
|
3916
|
+
return /* @__PURE__ */ jsx23(
|
|
3376
3917
|
EventLogoAuthenticated,
|
|
3377
3918
|
{
|
|
3378
3919
|
eventId,
|
|
@@ -3389,7 +3930,7 @@ function EventLogo({
|
|
|
3389
3930
|
);
|
|
3390
3931
|
}
|
|
3391
3932
|
function EventLogoCompact(props) {
|
|
3392
|
-
return /* @__PURE__ */
|
|
3933
|
+
return /* @__PURE__ */ jsx23(
|
|
3393
3934
|
EventLogo,
|
|
3394
3935
|
{
|
|
3395
3936
|
...props,
|
|
@@ -3399,7 +3940,7 @@ function EventLogoCompact(props) {
|
|
|
3399
3940
|
);
|
|
3400
3941
|
}
|
|
3401
3942
|
function EventLogoLarge(props) {
|
|
3402
|
-
return /* @__PURE__ */
|
|
3943
|
+
return /* @__PURE__ */ jsx23(
|
|
3403
3944
|
EventLogo,
|
|
3404
3945
|
{
|
|
3405
3946
|
...props,
|
|
@@ -3410,7 +3951,7 @@ function EventLogoLarge(props) {
|
|
|
3410
3951
|
}
|
|
3411
3952
|
|
|
3412
3953
|
// src/components/PublicLayout/PublicPageHeader.tsx
|
|
3413
|
-
import { Fragment as
|
|
3954
|
+
import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
3414
3955
|
function PublicPageHeader({
|
|
3415
3956
|
event,
|
|
3416
3957
|
eventCode,
|
|
@@ -3425,10 +3966,10 @@ function PublicPageHeader({
|
|
|
3425
3966
|
}) {
|
|
3426
3967
|
const { appName } = useAppConfig();
|
|
3427
3968
|
const headerClasses = `bg-white border-b border-gray-200 ${className}`.trim();
|
|
3428
|
-
return /* @__PURE__ */
|
|
3429
|
-
/* @__PURE__ */
|
|
3430
|
-
showAppLogo && /* @__PURE__ */
|
|
3431
|
-
/* @__PURE__ */
|
|
3969
|
+
return /* @__PURE__ */ jsx24("header", { className: headerClasses, children: /* @__PURE__ */ jsxs18("div", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto", children: [
|
|
3970
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between py-4", children: [
|
|
3971
|
+
showAppLogo && /* @__PURE__ */ jsx24("div", { className: "flex-shrink-0", children: customAppLogo || /* @__PURE__ */ jsxs18("div", { className: "flex items-center", children: [
|
|
3972
|
+
/* @__PURE__ */ jsx24(
|
|
3432
3973
|
"img",
|
|
3433
3974
|
{
|
|
3434
3975
|
className: "h-8 w-auto",
|
|
@@ -3436,9 +3977,9 @@ function PublicPageHeader({
|
|
|
3436
3977
|
alt: appName
|
|
3437
3978
|
}
|
|
3438
3979
|
),
|
|
3439
|
-
/* @__PURE__ */
|
|
3980
|
+
/* @__PURE__ */ jsx24("span", { className: "ml-2 text-lg font-semibold text-gray-900", children: appName })
|
|
3440
3981
|
] }) }),
|
|
3441
|
-
showEventLogo && event && /* @__PURE__ */
|
|
3982
|
+
showEventLogo && event && /* @__PURE__ */ jsx24("div", { className: "flex-shrink-0", children: customEventLogo || /* @__PURE__ */ jsx24(
|
|
3442
3983
|
EventLogo,
|
|
3443
3984
|
{
|
|
3444
3985
|
eventId: event.event_id,
|
|
@@ -3449,22 +3990,22 @@ function PublicPageHeader({
|
|
|
3449
3990
|
}
|
|
3450
3991
|
) })
|
|
3451
3992
|
] }),
|
|
3452
|
-
/* @__PURE__ */
|
|
3453
|
-
event && /* @__PURE__ */
|
|
3454
|
-
/* @__PURE__ */
|
|
3455
|
-
event.event_venue && /* @__PURE__ */
|
|
3993
|
+
/* @__PURE__ */ jsx24("div", { className: "pb-4", children: /* @__PURE__ */ jsxs18("div", { className: "text-center", children: [
|
|
3994
|
+
event && /* @__PURE__ */ jsxs18(Fragment6, { children: [
|
|
3995
|
+
/* @__PURE__ */ jsx24("h1", { className: "text-3xl font-bold text-gray-900 mb-2", children: event.event_name }),
|
|
3996
|
+
event.event_venue && /* @__PURE__ */ jsx24("p", { className: "text-md text-gray-500 mb-4", children: event.event_venue })
|
|
3456
3997
|
] }),
|
|
3457
|
-
title && /* @__PURE__ */
|
|
3458
|
-
/* @__PURE__ */
|
|
3459
|
-
description && /* @__PURE__ */
|
|
3998
|
+
title && /* @__PURE__ */ jsxs18("div", { className: "mt-6", children: [
|
|
3999
|
+
/* @__PURE__ */ jsx24("h2", { className: "text-2xl font-semibold text-gray-800 mb-2", children: title }),
|
|
4000
|
+
description && /* @__PURE__ */ jsx24("p", { className: "text-lg text-gray-600 max-w-3xl mx-auto", children: description })
|
|
3460
4001
|
] }),
|
|
3461
|
-
children && /* @__PURE__ */
|
|
4002
|
+
children && /* @__PURE__ */ jsx24("div", { className: "mt-4", children })
|
|
3462
4003
|
] }) })
|
|
3463
4004
|
] }) });
|
|
3464
4005
|
}
|
|
3465
4006
|
|
|
3466
4007
|
// src/components/PublicLayout/PublicPageFooter.tsx
|
|
3467
|
-
import { Fragment as
|
|
4008
|
+
import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3468
4009
|
function PublicPageFooter({
|
|
3469
4010
|
event,
|
|
3470
4011
|
companyName = "Solvera Solutions Pty Ltd",
|
|
@@ -3476,16 +4017,16 @@ function PublicPageFooter({
|
|
|
3476
4017
|
children
|
|
3477
4018
|
}) {
|
|
3478
4019
|
const copyrightText = copyright || `\xA9 Copyright 2022\u2013${year} all rights reserved, ${companyName}.`;
|
|
3479
|
-
return /* @__PURE__ */
|
|
3480
|
-
logo && /* @__PURE__ */
|
|
3481
|
-
children && /* @__PURE__ */
|
|
3482
|
-
/* @__PURE__ */
|
|
3483
|
-
links && links.length > 0 && /* @__PURE__ */
|
|
4020
|
+
return /* @__PURE__ */ jsx25("footer", { className: cn("mt-8 py-6 flex justify-center border-t border-border bg-main-100", className), children: /* @__PURE__ */ jsxs19("section", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto text-center", children: [
|
|
4021
|
+
logo && /* @__PURE__ */ jsx25("img", { src: logo, alt: "Logo", className: "h-8 w-auto" }),
|
|
4022
|
+
children && /* @__PURE__ */ jsx25(Fragment7, { children }),
|
|
4023
|
+
/* @__PURE__ */ jsx25("span", { className: "text-muted-foreground", children: copyrightText }),
|
|
4024
|
+
links && links.length > 0 && /* @__PURE__ */ jsx25("ul", { className: "flex gap-4 mt-2 md:mt-0", children: links.map((link, index) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25("a", { href: link.href, className: "text-muted-foreground hover:text-foreground", children: link.label }) }, index)) })
|
|
3484
4025
|
] }) });
|
|
3485
4026
|
}
|
|
3486
4027
|
|
|
3487
4028
|
// src/components/PublicLayout/PublicLoadingSpinner.tsx
|
|
3488
|
-
import { jsx as
|
|
4029
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3489
4030
|
var sizeClasses2 = {
|
|
3490
4031
|
sm: "h-4 w-4",
|
|
3491
4032
|
md: "h-8 w-8",
|
|
@@ -3502,8 +4043,8 @@ function PublicLoadingSpinner({
|
|
|
3502
4043
|
}) {
|
|
3503
4044
|
const sizeClass = sizeClasses2[size];
|
|
3504
4045
|
const displayMessage = customMessage || message;
|
|
3505
|
-
const content = /* @__PURE__ */
|
|
3506
|
-
showLogo && /* @__PURE__ */
|
|
4046
|
+
const content = /* @__PURE__ */ jsxs20("div", { className: `flex flex-col items-center ${className}`, children: [
|
|
4047
|
+
showLogo && /* @__PURE__ */ jsx26("div", { className: "mb-4", children: /* @__PURE__ */ jsx26(
|
|
3507
4048
|
"img",
|
|
3508
4049
|
{
|
|
3509
4050
|
className: "h-8 w-auto",
|
|
@@ -3511,8 +4052,8 @@ function PublicLoadingSpinner({
|
|
|
3511
4052
|
alt: "PACE Core"
|
|
3512
4053
|
}
|
|
3513
4054
|
) }),
|
|
3514
|
-
/* @__PURE__ */
|
|
3515
|
-
/* @__PURE__ */
|
|
4055
|
+
/* @__PURE__ */ jsxs20("div", { className: "relative", children: [
|
|
4056
|
+
/* @__PURE__ */ jsx26(
|
|
3516
4057
|
"div",
|
|
3517
4058
|
{
|
|
3518
4059
|
className: `${sizeClass} border-2 border-gray-200 border-t-blue-600 rounded-full animate-spin`,
|
|
@@ -3520,12 +4061,12 @@ function PublicLoadingSpinner({
|
|
|
3520
4061
|
"aria-label": "Loading"
|
|
3521
4062
|
}
|
|
3522
4063
|
),
|
|
3523
|
-
/* @__PURE__ */
|
|
4064
|
+
/* @__PURE__ */ jsx26("span", { className: "sr-only", children: displayMessage })
|
|
3524
4065
|
] }),
|
|
3525
|
-
displayMessage && /* @__PURE__ */
|
|
4066
|
+
displayMessage && /* @__PURE__ */ jsx26("p", { className: "mt-4 text-sm text-gray-600 text-center", children: displayMessage })
|
|
3526
4067
|
] });
|
|
3527
4068
|
if (centered) {
|
|
3528
|
-
return /* @__PURE__ */
|
|
4069
|
+
return /* @__PURE__ */ jsx26("div", { className: "min-h-screen bg-white flex items-center justify-center", children: /* @__PURE__ */ jsx26("div", { className: "max-w-md mx-auto px-4", children: content }) });
|
|
3529
4070
|
}
|
|
3530
4071
|
return content;
|
|
3531
4072
|
}
|
|
@@ -3534,8 +4075,8 @@ function PublicLoadingSpinnerFullPage({
|
|
|
3534
4075
|
eventName,
|
|
3535
4076
|
className = ""
|
|
3536
4077
|
}) {
|
|
3537
|
-
return /* @__PURE__ */
|
|
3538
|
-
/* @__PURE__ */
|
|
4078
|
+
return /* @__PURE__ */ jsx26("div", { className: `min-h-screen bg-white flex items-center justify-center ${className}`, children: /* @__PURE__ */ jsxs20("div", { className: "max-w-md mx-auto text-center px-4", children: [
|
|
4079
|
+
/* @__PURE__ */ jsx26("div", { className: "mb-8", children: /* @__PURE__ */ jsx26(
|
|
3539
4080
|
"img",
|
|
3540
4081
|
{
|
|
3541
4082
|
className: "h-12 w-auto mx-auto",
|
|
@@ -3543,8 +4084,8 @@ function PublicLoadingSpinnerFullPage({
|
|
|
3543
4084
|
alt: "PACE Core"
|
|
3544
4085
|
}
|
|
3545
4086
|
) }),
|
|
3546
|
-
eventName && /* @__PURE__ */
|
|
3547
|
-
/* @__PURE__ */
|
|
4087
|
+
eventName && /* @__PURE__ */ jsx26("h1", { className: "text-2xl font-bold text-gray-900 mb-4", children: eventName }),
|
|
4088
|
+
/* @__PURE__ */ jsx26("div", { className: "relative mb-6", children: /* @__PURE__ */ jsx26(
|
|
3548
4089
|
"div",
|
|
3549
4090
|
{
|
|
3550
4091
|
className: "h-12 w-12 border-4 border-gray-200 border-t-blue-600 rounded-full animate-spin mx-auto",
|
|
@@ -3552,11 +4093,11 @@ function PublicLoadingSpinnerFullPage({
|
|
|
3552
4093
|
"aria-label": "Loading"
|
|
3553
4094
|
}
|
|
3554
4095
|
) }),
|
|
3555
|
-
/* @__PURE__ */
|
|
3556
|
-
/* @__PURE__ */
|
|
3557
|
-
/* @__PURE__ */
|
|
3558
|
-
/* @__PURE__ */
|
|
3559
|
-
/* @__PURE__ */
|
|
4096
|
+
/* @__PURE__ */ jsx26("p", { className: "text-lg text-gray-600", children: message }),
|
|
4097
|
+
/* @__PURE__ */ jsxs20("div", { className: "mt-4 flex justify-center space-x-1", children: [
|
|
4098
|
+
/* @__PURE__ */ jsx26("div", { className: "h-2 w-2 bg-blue-600 rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
|
|
4099
|
+
/* @__PURE__ */ jsx26("div", { className: "h-2 w-2 bg-blue-600 rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
|
|
4100
|
+
/* @__PURE__ */ jsx26("div", { className: "h-2 w-2 bg-blue-600 rounded-full animate-bounce", style: { animationDelay: "300ms" } })
|
|
3560
4101
|
] })
|
|
3561
4102
|
] }) });
|
|
3562
4103
|
}
|
|
@@ -3564,7 +4105,7 @@ function PublicLoadingSkeleton({
|
|
|
3564
4105
|
lines = 3,
|
|
3565
4106
|
className = ""
|
|
3566
4107
|
}) {
|
|
3567
|
-
return /* @__PURE__ */
|
|
4108
|
+
return /* @__PURE__ */ jsx26("div", { className: `animate-pulse ${className}`, children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ jsx26(
|
|
3568
4109
|
"div",
|
|
3569
4110
|
{
|
|
3570
4111
|
className: `h-4 bg-gray-200 rounded mb-2 ${index === lines - 1 ? "w-3/4" : "w-full"}`
|
|
@@ -3574,8 +4115,8 @@ function PublicLoadingSkeleton({
|
|
|
3574
4115
|
}
|
|
3575
4116
|
|
|
3576
4117
|
// src/components/PublicLayout/PublicPageLayout.tsx
|
|
3577
|
-
import { useMemo as
|
|
3578
|
-
import { jsx as
|
|
4118
|
+
import { useMemo as useMemo10 } from "react";
|
|
4119
|
+
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3579
4120
|
function PublicPageLayout({
|
|
3580
4121
|
eventCode,
|
|
3581
4122
|
children,
|
|
@@ -3592,22 +4133,22 @@ function PublicPageLayout({
|
|
|
3592
4133
|
const error = null;
|
|
3593
4134
|
const refetch = async () => {
|
|
3594
4135
|
};
|
|
3595
|
-
const layoutClasses =
|
|
4136
|
+
const layoutClasses = useMemo10(() => {
|
|
3596
4137
|
const baseClasses = "min-h-screen bg-white flex flex-col";
|
|
3597
4138
|
return `${baseClasses} ${className}`.trim();
|
|
3598
4139
|
}, [className]);
|
|
3599
4140
|
if (isLoading) {
|
|
3600
|
-
return /* @__PURE__ */
|
|
4141
|
+
return /* @__PURE__ */ jsx27("div", { className: layoutClasses, children: /* @__PURE__ */ jsx27("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsx27(LoadingFallback, {}) }) });
|
|
3601
4142
|
}
|
|
3602
4143
|
if (error && showValidationErrors) {
|
|
3603
|
-
return /* @__PURE__ */
|
|
3604
|
-
/* @__PURE__ */
|
|
3605
|
-
/* @__PURE__ */
|
|
4144
|
+
return /* @__PURE__ */ jsx27("div", { className: layoutClasses, children: /* @__PURE__ */ jsx27("div", { className: "flex-1 flex items-center justify-center", children: ErrorFallback ? /* @__PURE__ */ jsx27(ErrorFallback, { error, retry: refetch }) : /* @__PURE__ */ jsxs21("div", { className: "text-center p-8", children: [
|
|
4145
|
+
/* @__PURE__ */ jsx27("h1", { className: "text-2xl font-bold text-gray-900 mb-4", children: "Event Not Found" }),
|
|
4146
|
+
/* @__PURE__ */ jsxs21("p", { className: "text-gray-600 mb-6", children: [
|
|
3606
4147
|
'The event code "',
|
|
3607
4148
|
eventCode,
|
|
3608
4149
|
'" is invalid or the event is not available for public viewing.'
|
|
3609
4150
|
] }),
|
|
3610
|
-
/* @__PURE__ */
|
|
4151
|
+
/* @__PURE__ */ jsx27(
|
|
3611
4152
|
"button",
|
|
3612
4153
|
{
|
|
3613
4154
|
onClick: refetch,
|
|
@@ -3618,10 +4159,10 @@ function PublicPageLayout({
|
|
|
3618
4159
|
] }) }) });
|
|
3619
4160
|
}
|
|
3620
4161
|
if (!event) {
|
|
3621
|
-
return /* @__PURE__ */
|
|
3622
|
-
/* @__PURE__ */
|
|
3623
|
-
/* @__PURE__ */
|
|
3624
|
-
/* @__PURE__ */
|
|
4162
|
+
return /* @__PURE__ */ jsx27("div", { className: layoutClasses, children: /* @__PURE__ */ jsx27("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs21("div", { className: "text-center p-8", children: [
|
|
4163
|
+
/* @__PURE__ */ jsx27("h1", { className: "text-2xl font-bold text-gray-900 mb-4", children: "Event Not Available" }),
|
|
4164
|
+
/* @__PURE__ */ jsx27("p", { className: "text-gray-600 mb-6", children: "This event is not available for public viewing." }),
|
|
4165
|
+
/* @__PURE__ */ jsx27(
|
|
3625
4166
|
"button",
|
|
3626
4167
|
{
|
|
3627
4168
|
onClick: refetch,
|
|
@@ -3631,16 +4172,16 @@ function PublicPageLayout({
|
|
|
3631
4172
|
)
|
|
3632
4173
|
] }) }) });
|
|
3633
4174
|
}
|
|
3634
|
-
return /* @__PURE__ */
|
|
3635
|
-
customHeader || /* @__PURE__ */
|
|
4175
|
+
return /* @__PURE__ */ jsx27(PublicErrorBoundary, { children: /* @__PURE__ */ jsxs21("div", { className: layoutClasses, children: [
|
|
4176
|
+
customHeader || /* @__PURE__ */ jsx27(
|
|
3636
4177
|
PublicPageHeader,
|
|
3637
4178
|
{
|
|
3638
4179
|
event,
|
|
3639
4180
|
eventCode
|
|
3640
4181
|
}
|
|
3641
4182
|
),
|
|
3642
|
-
/* @__PURE__ */
|
|
3643
|
-
showFooter && (customFooter || /* @__PURE__ */
|
|
4183
|
+
/* @__PURE__ */ jsx27("main", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto py-8", children }),
|
|
4184
|
+
showFooter && (customFooter || /* @__PURE__ */ jsx27(PublicPageFooter, { event }))
|
|
3644
4185
|
] }) });
|
|
3645
4186
|
}
|
|
3646
4187
|
function usePublicPageContext2() {
|
|
@@ -3657,10 +4198,10 @@ function usePublicPageContext2() {
|
|
|
3657
4198
|
}
|
|
3658
4199
|
|
|
3659
4200
|
// src/components/PublicLayout/PublicPageDebugger.tsx
|
|
3660
|
-
import { useEffect as
|
|
3661
|
-
import { jsx as
|
|
4201
|
+
import { useEffect as useEffect9 } from "react";
|
|
4202
|
+
import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3662
4203
|
function PublicPageDebugger({ enabled = true, label = "PublicPage" }) {
|
|
3663
|
-
|
|
4204
|
+
useEffect9(() => {
|
|
3664
4205
|
if (!enabled) return;
|
|
3665
4206
|
console.log(`[${label}] Component mounted`);
|
|
3666
4207
|
try {
|
|
@@ -3701,7 +4242,7 @@ function PublicPageDebugger({ enabled = true, label = "PublicPage" }) {
|
|
|
3701
4242
|
};
|
|
3702
4243
|
}, [enabled, label]);
|
|
3703
4244
|
if (!enabled) return null;
|
|
3704
|
-
return /* @__PURE__ */
|
|
4245
|
+
return /* @__PURE__ */ jsxs22("div", { style: {
|
|
3705
4246
|
position: "fixed",
|
|
3706
4247
|
top: 0,
|
|
3707
4248
|
right: 0,
|
|
@@ -3712,16 +4253,16 @@ function PublicPageDebugger({ enabled = true, label = "PublicPage" }) {
|
|
|
3712
4253
|
zIndex: 9999,
|
|
3713
4254
|
fontFamily: "monospace"
|
|
3714
4255
|
}, children: [
|
|
3715
|
-
/* @__PURE__ */
|
|
3716
|
-
/* @__PURE__ */
|
|
4256
|
+
/* @__PURE__ */ jsx28("div", { children: "Public Page Debugger" }),
|
|
4257
|
+
/* @__PURE__ */ jsx28("div", { children: "Check console for context analysis" })
|
|
3717
4258
|
] });
|
|
3718
4259
|
}
|
|
3719
4260
|
|
|
3720
4261
|
// src/components/PublicLayout/PublicPageDiagnostic.tsx
|
|
3721
|
-
import { useEffect as
|
|
3722
|
-
import { jsx as
|
|
4262
|
+
import { useEffect as useEffect10, useState as useState13 } from "react";
|
|
4263
|
+
import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3723
4264
|
function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
|
|
3724
|
-
const [diagnostics, setDiagnostics] =
|
|
4265
|
+
const [diagnostics, setDiagnostics] = useState13({
|
|
3725
4266
|
hasPublicPageContext: false,
|
|
3726
4267
|
hasAuthContext: false,
|
|
3727
4268
|
hasOrgContext: false,
|
|
@@ -3729,7 +4270,7 @@ function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
|
|
|
3729
4270
|
hasEnvironmentVars: false,
|
|
3730
4271
|
routeParams: null
|
|
3731
4272
|
});
|
|
3732
|
-
|
|
4273
|
+
useEffect10(() => {
|
|
3733
4274
|
if (!enabled) return;
|
|
3734
4275
|
const runDiagnostics = () => {
|
|
3735
4276
|
const newDiagnostics = {
|
|
@@ -3800,7 +4341,7 @@ function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
|
|
|
3800
4341
|
runDiagnostics();
|
|
3801
4342
|
}, [enabled, label]);
|
|
3802
4343
|
if (!enabled) return null;
|
|
3803
|
-
return /* @__PURE__ */
|
|
4344
|
+
return /* @__PURE__ */ jsxs23("div", { style: {
|
|
3804
4345
|
position: "fixed",
|
|
3805
4346
|
top: 0,
|
|
3806
4347
|
left: 0,
|
|
@@ -3813,40 +4354,40 @@ function PublicPageDiagnostic({ enabled = true, label = "PublicPage" }) {
|
|
|
3813
4354
|
maxWidth: "300px",
|
|
3814
4355
|
borderRadius: "0 0 8px 0"
|
|
3815
4356
|
}, children: [
|
|
3816
|
-
/* @__PURE__ */
|
|
3817
|
-
/* @__PURE__ */
|
|
4357
|
+
/* @__PURE__ */ jsx29("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "\u{1F50D} Public Page Diagnostics" }),
|
|
4358
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3818
4359
|
"Public Context: ",
|
|
3819
4360
|
diagnostics.hasPublicPageContext ? "\u2705" : "\u274C"
|
|
3820
4361
|
] }),
|
|
3821
|
-
/* @__PURE__ */
|
|
4362
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3822
4363
|
"Auth Context: ",
|
|
3823
4364
|
diagnostics.hasAuthContext ? "\u274C BAD" : "\u2705 GOOD"
|
|
3824
4365
|
] }),
|
|
3825
|
-
/* @__PURE__ */
|
|
4366
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3826
4367
|
"Org Context: ",
|
|
3827
4368
|
diagnostics.hasOrgContext ? "\u274C BAD" : "\u2705 GOOD"
|
|
3828
4369
|
] }),
|
|
3829
|
-
/* @__PURE__ */
|
|
4370
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3830
4371
|
"Event Context: ",
|
|
3831
4372
|
diagnostics.hasEventContext ? "\u274C BAD" : "\u2705 GOOD"
|
|
3832
4373
|
] }),
|
|
3833
|
-
/* @__PURE__ */
|
|
4374
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3834
4375
|
"Env Vars: ",
|
|
3835
4376
|
diagnostics.hasEnvironmentVars ? "\u2705" : "\u274C"
|
|
3836
4377
|
] }),
|
|
3837
|
-
/* @__PURE__ */
|
|
4378
|
+
/* @__PURE__ */ jsxs23("div", { children: [
|
|
3838
4379
|
"Route Params: ",
|
|
3839
4380
|
diagnostics.routeParams ? "\u2705" : "\u274C"
|
|
3840
4381
|
] }),
|
|
3841
|
-
/* @__PURE__ */
|
|
4382
|
+
/* @__PURE__ */ jsx29("div", { style: { marginTop: "8px", fontSize: "10px", opacity: 0.8 }, children: "Check console for detailed analysis" })
|
|
3842
4383
|
] });
|
|
3843
4384
|
}
|
|
3844
4385
|
|
|
3845
4386
|
// src/components/PublicLayout/PublicPageContextChecker.tsx
|
|
3846
|
-
import { useEffect as
|
|
3847
|
-
import { jsx as
|
|
4387
|
+
import { useEffect as useEffect11 } from "react";
|
|
4388
|
+
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
3848
4389
|
function PublicPageContextChecker({ enabled = true, label = "PublicPage" }) {
|
|
3849
|
-
|
|
4390
|
+
useEffect11(() => {
|
|
3850
4391
|
if (!enabled) return;
|
|
3851
4392
|
console.group(`\u{1F6A8} [${label}] PUBLIC PAGE CONTEXT CHECK`);
|
|
3852
4393
|
try {
|
|
@@ -3908,7 +4449,7 @@ function PublicPageContextChecker({ enabled = true, label = "PublicPage" }) {
|
|
|
3908
4449
|
console.groupEnd();
|
|
3909
4450
|
}, [enabled, label]);
|
|
3910
4451
|
if (!enabled) return null;
|
|
3911
|
-
return /* @__PURE__ */
|
|
4452
|
+
return /* @__PURE__ */ jsxs24("div", { style: {
|
|
3912
4453
|
position: "fixed",
|
|
3913
4454
|
top: 0,
|
|
3914
4455
|
left: 0,
|
|
@@ -3922,9 +4463,9 @@ function PublicPageContextChecker({ enabled = true, label = "PublicPage" }) {
|
|
|
3922
4463
|
borderRadius: "0 0 8px 0",
|
|
3923
4464
|
border: "2px solid #dc2626"
|
|
3924
4465
|
}, children: [
|
|
3925
|
-
/* @__PURE__ */
|
|
3926
|
-
/* @__PURE__ */
|
|
3927
|
-
/* @__PURE__ */
|
|
4466
|
+
/* @__PURE__ */ jsx30("div", { style: { fontWeight: "bold", marginBottom: "8px" }, children: "\u{1F6A8} PUBLIC PAGE CONTEXT CHECK" }),
|
|
4467
|
+
/* @__PURE__ */ jsx30("div", { children: "Check console for authentication context analysis" }),
|
|
4468
|
+
/* @__PURE__ */ jsx30("div", { style: { marginTop: "8px", fontSize: "10px", opacity: 0.9 }, children: "If you see \u274C errors in console, your public page is inside auth context!" })
|
|
3928
4469
|
] });
|
|
3929
4470
|
}
|
|
3930
4471
|
|
|
@@ -3955,30 +4496,18 @@ export {
|
|
|
3955
4496
|
PaceAppLayout,
|
|
3956
4497
|
PaceLoginPage,
|
|
3957
4498
|
ErrorBoundary,
|
|
4499
|
+
SessionRestorationLoader,
|
|
3958
4500
|
OrganisationSelector,
|
|
3959
4501
|
PasswordResetForm,
|
|
3960
|
-
FILE_SIZE_LIMITS,
|
|
3961
|
-
DEFAULT_FILE_SIZE_LIMIT,
|
|
3962
|
-
APP_PATH_MAPPING,
|
|
3963
|
-
STORAGE_CONFIG,
|
|
3964
|
-
getFileSizeLimit,
|
|
3965
|
-
validateFileSize,
|
|
3966
|
-
formatFileSize,
|
|
3967
|
-
generateFilePath,
|
|
3968
|
-
generateUniqueFileName,
|
|
3969
|
-
extractFileMetadata,
|
|
3970
|
-
uploadFile,
|
|
3971
|
-
getPublicUrl,
|
|
3972
|
-
getSignedUrl,
|
|
3973
|
-
deleteFile,
|
|
3974
|
-
listFiles,
|
|
3975
|
-
archiveFile,
|
|
3976
|
-
StorageUtils,
|
|
3977
|
-
useStorage,
|
|
3978
|
-
useFileUpload,
|
|
3979
4502
|
useFileReference,
|
|
3980
4503
|
useFileReferenceForRecord,
|
|
4504
|
+
useFileReferenceById,
|
|
4505
|
+
useFilesByCategory,
|
|
4506
|
+
FileUpload,
|
|
3981
4507
|
FileDisplay,
|
|
4508
|
+
useEventLogo,
|
|
4509
|
+
clearEventLogoCache,
|
|
4510
|
+
getEventLogoCacheStats,
|
|
3982
4511
|
Table,
|
|
3983
4512
|
TableHeader,
|
|
3984
4513
|
TableBody,
|
|
@@ -4001,4 +4530,4 @@ export {
|
|
|
4001
4530
|
PublicPageDiagnostic,
|
|
4002
4531
|
PublicPageContextChecker
|
|
4003
4532
|
};
|
|
4004
|
-
//# sourceMappingURL=chunk-
|
|
4533
|
+
//# sourceMappingURL=chunk-YWAFPVJA.js.map
|