@jmruthers/pace-core 0.5.107 → 0.5.109
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/CHANGELOG.md +75 -177
- package/dist/{AuthService-1D2ifNfa.d.ts → AuthService-DrHrvXNZ.d.ts} +8 -1
- package/dist/{DataTable-H2WIR2DN.js → DataTable-5HITILXS.js} +7 -7
- package/dist/{PublicLoadingSpinner-48ewSMKK.d.ts → PublicLoadingSpinner-DgDWTFqn.d.ts} +4 -2
- package/dist/{UnifiedAuthProvider-XU4BHFXZ.js → UnifiedAuthProvider-A7I23UCN.js} +3 -3
- package/dist/{api-KG4A2X7P.js → api-5I3E47G2.js} +2 -2
- package/dist/{chunk-DMNMZKWS.js → chunk-2W4WKJVF.js} +4 -4
- package/dist/{chunk-MOMYOQMC.js → chunk-3TKTL5AZ.js} +13 -13
- package/dist/{chunk-X4FRXJV6.js → chunk-AUXS7XSO.js} +57 -6
- package/dist/{chunk-X4FRXJV6.js.map → chunk-AUXS7XSO.js.map} +1 -1
- package/dist/{chunk-LT6RKRA7.js → chunk-D6MEKC27.js} +2 -2
- package/dist/{chunk-KBG34SVL.js → chunk-EYSXQ756.js} +2 -2
- package/dist/{chunk-ZXY5NTJB.js → chunk-EZ64QG2I.js} +2 -2
- package/dist/{chunk-S63MFSY6.js → chunk-F6TSYCKP.js} +4 -2
- package/dist/{chunk-S63MFSY6.js.map → chunk-F6TSYCKP.js.map} +1 -1
- package/dist/chunk-GZRXOUBE.js +176 -0
- package/dist/chunk-GZRXOUBE.js.map +1 -0
- package/dist/{chunk-EWKCROSF.js → chunk-P72NKAT5.js} +84 -28
- package/dist/chunk-P72NKAT5.js.map +1 -0
- package/dist/{chunk-VJ7MPS2K.js → chunk-S4D3Z723.js} +6 -6
- package/dist/{chunk-5JJCXTVE.js → chunk-UW2DE6JX.js} +108 -86
- package/dist/{chunk-5JJCXTVE.js.map → chunk-UW2DE6JX.js.map} +1 -1
- package/dist/{chunk-QDDUU625.js → chunk-WWNOVFDC.js} +4 -4
- package/dist/{chunk-GVRSXXAA.js → chunk-YFMENCR4.js} +3 -3
- package/dist/components.d.ts +1 -1
- package/dist/components.js +9 -9
- package/dist/{database-BXAfr2Y_.d.ts → database-C6jy7EOu.d.ts} +21 -9
- package/dist/{formatting-BiEv5oEk.d.ts → formatting-B1jSqgl-.d.ts} +16 -1
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +4 -3
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +1 -1
- package/dist/rbac/index.js +8 -8
- package/dist/types.d.ts +2 -2
- package/dist/{usePublicRouteParams-CnM-IK2I.d.ts → usePublicRouteParams-BdF8bZgs.d.ts} +1 -1
- package/dist/utils.d.ts +2 -15
- package/dist/utils.js +4 -145
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +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 +1 -1
- package/docs/api/enums/FileCategory.md +1 -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 +3 -3
- 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/FileDisplayProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- 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/ProtectedRouteProps.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 +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.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 +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +42 -6
- package/docs/api-reference/hooks.md +53 -0
- package/docs/api-reference/providers.md +60 -0
- package/docs/core-concepts/authentication.md +2 -0
- package/docs/implementation-guides/authentication.md +1 -0
- package/docs/security/README.md +59 -0
- package/package.json +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +2 -1
- package/src/components/DataTable/components/EditableRow.tsx +7 -2
- package/src/components/DataTable/components/FilterRow.tsx +22 -11
- package/src/components/DataTable/components/PaginationControls.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +39 -10
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +2 -2
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +126 -25
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +2 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +9 -9
- package/src/index.ts +3 -0
- package/src/providers/services/AuthServiceProvider.tsx +4 -3
- package/src/providers/services/UnifiedAuthProvider.tsx +1 -1
- package/src/rbac/engine.ts +2 -0
- package/src/services/AuthService.ts +79 -1
- package/src/services/__tests__/AuthService.test.ts +184 -0
- package/src/types/database.ts +21 -9
- package/src/types/rbac-functions.ts +2 -1
- package/src/utils/__tests__/sessionTracking.unit.test.ts +6 -171
- package/src/utils/sessionTracking.ts +7 -81
- package/dist/chunk-EWKCROSF.js.map +0 -1
- package/dist/chunk-NFPV7MRN.js +0 -94
- package/dist/chunk-NFPV7MRN.js.map +0 -1
- package/src/providers/AuthProvider.simplified.tsx +0 -974
- package/dist/{DataTable-H2WIR2DN.js.map → DataTable-5HITILXS.js.map} +0 -0
- package/dist/{UnifiedAuthProvider-XU4BHFXZ.js.map → UnifiedAuthProvider-A7I23UCN.js.map} +0 -0
- package/dist/{api-KG4A2X7P.js.map → api-5I3E47G2.js.map} +0 -0
- package/dist/{chunk-DMNMZKWS.js.map → chunk-2W4WKJVF.js.map} +0 -0
- package/dist/{chunk-MOMYOQMC.js.map → chunk-3TKTL5AZ.js.map} +0 -0
- package/dist/{chunk-LT6RKRA7.js.map → chunk-D6MEKC27.js.map} +0 -0
- package/dist/{chunk-KBG34SVL.js.map → chunk-EYSXQ756.js.map} +0 -0
- package/dist/{chunk-ZXY5NTJB.js.map → chunk-EZ64QG2I.js.map} +0 -0
- package/dist/{chunk-VJ7MPS2K.js.map → chunk-S4D3Z723.js.map} +0 -0
- package/dist/{chunk-QDDUU625.js.map → chunk-WWNOVFDC.js.map} +0 -0
- package/dist/{chunk-GVRSXXAA.js.map → chunk-YFMENCR4.js.map} +0 -0
- package/dist/{validation-D8VcbTzC.d.ts → validation-DnhrNMju.d.ts} +2 -2
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// src/utils/sessionTracking.ts
|
|
2
|
+
function useSessionTracking(supabaseClient, appName) {
|
|
3
|
+
const resolveAppId = async () => {
|
|
4
|
+
if (!appName) return void 0;
|
|
5
|
+
try {
|
|
6
|
+
const { data, error } = await supabaseClient.from("rbac_apps").select("id").eq("name", appName).eq("is_active", true).single();
|
|
7
|
+
if (error || !data) {
|
|
8
|
+
console.warn("App not found or inactive:", appName);
|
|
9
|
+
return void 0;
|
|
10
|
+
}
|
|
11
|
+
return data.id;
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.error("Failed to resolve app ID:", error);
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const trackEventSwitch = async (eventId) => {
|
|
18
|
+
try {
|
|
19
|
+
const { data: { user } } = await supabaseClient.auth.getUser();
|
|
20
|
+
if (!user) {
|
|
21
|
+
console.warn("No authenticated user found for session tracking");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const appId = await resolveAppId();
|
|
25
|
+
const params = {
|
|
26
|
+
p_session_type: "event_switch",
|
|
27
|
+
p_event_id: eventId,
|
|
28
|
+
p_app_id: appId
|
|
29
|
+
};
|
|
30
|
+
const { error } = await supabaseClient.rpc("rbac_session_track", {
|
|
31
|
+
p_user_id: user?.id,
|
|
32
|
+
p_session_type: params.p_session_type,
|
|
33
|
+
p_event_id: params.p_event_id,
|
|
34
|
+
p_app_id: params.p_app_id,
|
|
35
|
+
p_ip_address: params.ip_address,
|
|
36
|
+
p_user_agent: params.user_agent
|
|
37
|
+
});
|
|
38
|
+
if (error) {
|
|
39
|
+
console.error("Failed to track event switch session:", error);
|
|
40
|
+
} else {
|
|
41
|
+
console.log("Event switch session tracked successfully");
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("Failed to track event switch:", error);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const trackSessionExpired = async () => {
|
|
48
|
+
try {
|
|
49
|
+
const { data: { user } } = await supabaseClient.auth.getUser();
|
|
50
|
+
if (!user) {
|
|
51
|
+
console.warn("No authenticated user found for session tracking");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const appId = await resolveAppId();
|
|
55
|
+
const params = {
|
|
56
|
+
p_session_type: "session_expired",
|
|
57
|
+
p_app_id: appId
|
|
58
|
+
};
|
|
59
|
+
const { error } = await supabaseClient.rpc("rbac_session_track", {
|
|
60
|
+
p_user_id: user?.id,
|
|
61
|
+
p_session_type: params.p_session_type,
|
|
62
|
+
p_event_id: params.p_event_id,
|
|
63
|
+
p_app_id: params.p_app_id,
|
|
64
|
+
p_ip_address: params.ip_address,
|
|
65
|
+
p_user_agent: params.user_agent
|
|
66
|
+
});
|
|
67
|
+
if (error) {
|
|
68
|
+
console.error("Failed to track session expiration:", error);
|
|
69
|
+
} else {
|
|
70
|
+
console.log("Session expiration tracked successfully");
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error("Failed to track session expiration:", error);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
trackEventSwitch,
|
|
78
|
+
trackSessionExpired
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/utils/appConfig.ts
|
|
83
|
+
var currentAppConfig = null;
|
|
84
|
+
function setAppConfig(config) {
|
|
85
|
+
currentAppConfig = config;
|
|
86
|
+
}
|
|
87
|
+
function getAppConfig() {
|
|
88
|
+
if (!currentAppConfig) {
|
|
89
|
+
const appName = import.meta.env.REACT_APP_NAME || "PACE";
|
|
90
|
+
return {
|
|
91
|
+
appName,
|
|
92
|
+
appId: appName
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return currentAppConfig;
|
|
96
|
+
}
|
|
97
|
+
function getCurrentAppName() {
|
|
98
|
+
return getAppConfig().appName;
|
|
99
|
+
}
|
|
100
|
+
function getCurrentAppId() {
|
|
101
|
+
return getAppConfig().appId;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/utils/formatting.ts
|
|
105
|
+
function formatDate(date) {
|
|
106
|
+
const dateObj = typeof date === "string" || typeof date === "number" ? new Date(date) : date;
|
|
107
|
+
return dateObj.toLocaleDateString(void 0, {
|
|
108
|
+
year: "numeric",
|
|
109
|
+
month: "short",
|
|
110
|
+
day: "numeric"
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function formatCurrency(value, currencyCode = "USD", locale = "en-US") {
|
|
114
|
+
return new Intl.NumberFormat(locale, {
|
|
115
|
+
style: "currency",
|
|
116
|
+
currency: currencyCode
|
|
117
|
+
}).format(value);
|
|
118
|
+
}
|
|
119
|
+
function formatNumber(value, options = {}, locale = "en-US") {
|
|
120
|
+
return new Intl.NumberFormat(locale, options).format(value);
|
|
121
|
+
}
|
|
122
|
+
function formatPercent(value, locale = "en-US", decimalsOrOptions) {
|
|
123
|
+
let decimals;
|
|
124
|
+
if (typeof decimalsOrOptions === "number") {
|
|
125
|
+
decimals = decimalsOrOptions;
|
|
126
|
+
} else if (decimalsOrOptions && typeof decimalsOrOptions === "object") {
|
|
127
|
+
if (decimalsOrOptions.preserveDecimals) {
|
|
128
|
+
const valueStr = value.toString();
|
|
129
|
+
const decimalIndex = valueStr.indexOf(".");
|
|
130
|
+
if (decimalIndex !== -1) {
|
|
131
|
+
const detectedDecimals = valueStr.length - decimalIndex - 1;
|
|
132
|
+
const maxDecimals = decimalsOrOptions.maxDecimals ?? 10;
|
|
133
|
+
decimals = Math.min(detectedDecimals, maxDecimals);
|
|
134
|
+
} else {
|
|
135
|
+
decimals = 0;
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
decimals = decimalsOrOptions.decimals ?? 1;
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
decimals = 1;
|
|
142
|
+
}
|
|
143
|
+
return new Intl.NumberFormat(locale, {
|
|
144
|
+
style: "percent",
|
|
145
|
+
minimumFractionDigits: decimals,
|
|
146
|
+
maximumFractionDigits: decimals
|
|
147
|
+
}).format(value / 100);
|
|
148
|
+
}
|
|
149
|
+
function formatCompactNumber(value, locale = "en-US") {
|
|
150
|
+
return new Intl.NumberFormat(locale, {
|
|
151
|
+
notation: "compact",
|
|
152
|
+
compactDisplay: "short"
|
|
153
|
+
}).format(value);
|
|
154
|
+
}
|
|
155
|
+
function formatFileSize(bytes) {
|
|
156
|
+
if (bytes === 0) return "0 Bytes";
|
|
157
|
+
const k = 1024;
|
|
158
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
|
|
159
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
160
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export {
|
|
164
|
+
useSessionTracking,
|
|
165
|
+
setAppConfig,
|
|
166
|
+
getAppConfig,
|
|
167
|
+
getCurrentAppName,
|
|
168
|
+
getCurrentAppId,
|
|
169
|
+
formatDate,
|
|
170
|
+
formatCurrency,
|
|
171
|
+
formatNumber,
|
|
172
|
+
formatPercent,
|
|
173
|
+
formatCompactNumber,
|
|
174
|
+
formatFileSize
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=chunk-GZRXOUBE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/sessionTracking.ts","../src/utils/appConfig.ts","../src/utils/formatting.ts"],"sourcesContent":["import type { SupabaseClient } from '@supabase/supabase-js';\n\n// Define the tracking parameters locally since old RBAC types are removed\ninterface TrackUserSessionParams {\n p_session_type: 'event_switch' | 'session_expired';\n p_event_id?: string;\n p_app_id?: string;\n ip_address?: string;\n user_agent?: string;\n}\n\n/**\n * Hook for manual session tracking (event switches and session expiration).\n * \n * Note: Login and logout tracking is automatically handled by UnifiedAuthProvider.\n * You should only use this hook for tracking event switches or session expirations.\n * \n * @param supabaseClient - Supabase client instance\n * @param appName - Optional application name for tracking\n * @returns Object containing tracking functions for event switches and session expiration\n */\nexport function useSessionTracking(supabaseClient: SupabaseClient, appName?: string) {\n // Resolve app name to app_id\n const resolveAppId = async (): Promise<string | undefined> => {\n if (!appName) return undefined;\n \n try {\n const { data, error } = await supabaseClient\n .from('rbac_apps')\n .select('id')\n .eq('name', appName)\n .eq('is_active', true)\n .single();\n \n if (error || !data) {\n console.warn('App not found or inactive:', appName);\n return undefined;\n }\n \n return data.id;\n } catch (error) {\n console.error('Failed to resolve app ID:', error);\n return undefined;\n }\n };\n /**\n * Track an event switch\n * @param eventId - ID of the event being switched to\n */\n const trackEventSwitch = async (eventId: string) => {\n try {\n const { data: { user } } = await supabaseClient.auth.getUser();\n if (!user) {\n console.warn('No authenticated user found for session tracking');\n return;\n }\n\n const appId = await resolveAppId();\n\n const params: TrackUserSessionParams = {\n p_session_type: 'event_switch',\n p_event_id: eventId,\n p_app_id: appId\n };\n\n const { error } = await supabaseClient.rpc('rbac_session_track', {\n p_user_id: user?.id,\n p_session_type: params.p_session_type,\n p_event_id: params.p_event_id,\n p_app_id: params.p_app_id,\n p_ip_address: params.ip_address,\n p_user_agent: params.user_agent\n });\n \n if (error) {\n console.error('Failed to track event switch session:', error);\n } else {\n console.log('Event switch session tracked successfully');\n }\n } catch (error) {\n console.error('Failed to track event switch:', error);\n }\n };\n\n /**\n * Track a session expiration\n */\n const trackSessionExpired = async () => {\n try {\n const { data: { user } } = await supabaseClient.auth.getUser();\n if (!user) {\n console.warn('No authenticated user found for session tracking');\n return;\n }\n\n const appId = await resolveAppId();\n\n const params: TrackUserSessionParams = {\n p_session_type: 'session_expired',\n p_app_id: appId\n };\n\n const { error } = await supabaseClient.rpc('rbac_session_track', {\n p_user_id: user?.id,\n p_session_type: params.p_session_type,\n p_event_id: params.p_event_id,\n p_app_id: params.p_app_id,\n p_ip_address: params.ip_address,\n p_user_agent: params.user_agent\n });\n \n if (error) {\n console.error('Failed to track session expiration:', error);\n } else {\n console.log('Session expiration tracked successfully');\n }\n } catch (error) {\n console.error('Failed to track session expiration:', error);\n }\n };\n\n return {\n trackEventSwitch,\n trackSessionExpired\n };\n} ","\n/**\n * Application configuration utilities\n */\n\nexport interface AppConfig {\n appName: string;\n appId: string;\n}\n\nlet currentAppConfig: AppConfig | null = null;\n\n/**\n * Set the current application configuration\n */\nexport function setAppConfig(config: AppConfig) {\n currentAppConfig = config;\n}\n\n/**\n * Get the current application configuration\n */\nexport function getAppConfig(): AppConfig {\n if (!currentAppConfig) {\n // Fallback to environment or default\n const appName = import.meta.env.REACT_APP_NAME || 'PACE';\n return {\n appName,\n appId: appName\n };\n }\n return currentAppConfig;\n}\n\n/**\n * Get the current app name\n */\nexport function getCurrentAppName(): string {\n return getAppConfig().appName;\n}\n\n/**\n * Get the current app ID\n */\nexport function getCurrentAppId(): string {\n return getAppConfig().appId;\n}\n","/**\n * Utility functions for formatting data in the application\n */\n\n/**\n * Format a date as a readable string\n */\nexport function formatDate(date: Date | string | number): string {\n const dateObj = typeof date === 'string' || typeof date === 'number' \n ? new Date(date) \n : date;\n \n return dateObj.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric'\n });\n}\n\n/**\n * Format a number as a currency\n */\nexport function formatCurrency(value: number, currencyCode = 'USD', locale = 'en-US'): string {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: currencyCode,\n }).format(value);\n}\n\n/**\n * Format a number with custom options\n */\nexport function formatNumber(\n value: number,\n options: Intl.NumberFormatOptions = {},\n locale = 'en-US'\n): string {\n return new Intl.NumberFormat(locale, options).format(value);\n}\n\n/**\n * Format a number as a percentage.\n * \n * The third parameter can be either:\n * - A number for fixed decimal places (backward compatible): `formatPercent(0.81, 'en-US', 2)`\n * - An options object with:\n * - `decimals`: Fixed number of decimal places (default: 1)\n * - `preserveDecimals`: Auto-detect and preserve decimal places from the input value\n * - `maxDecimals`: Maximum decimal places when preserving (default: 10)\n * \n * @param value - The percentage value as a decimal (e.g., 0.81 for 0.81%)\n * @param locale - The locale string (default: 'en-US')\n * @param decimalsOrOptions - Either a number for fixed decimals, or an options object with:\n * - `decimals` - Fixed number of decimal places (default: 1)\n * - `preserveDecimals` - Auto-detect and preserve decimal places from the input value\n * - `maxDecimals` - Maximum decimal places when preserving (default: 10)\n * @returns Formatted percentage string (e.g., \"0.81%\", \"81%\")\n * \n * @example\n * ```ts\n * // Fixed decimals (default behavior)\n * formatPercent(0.5) // '0.5%'\n * formatPercent(0.81, 'en-US', 1) // '0.8%' (loses precision)\n * \n * // Preserve decimal places dynamically\n * formatPercent(0.81, 'en-US', { preserveDecimals: true }) // '0.81%'\n * formatPercent(0.8123, 'en-US', { preserveDecimals: true, maxDecimals: 2 }) // '0.81%'\n * ```\n */\nexport function formatPercent(\n value: number,\n locale: string = 'en-US',\n decimalsOrOptions?: number | {\n decimals?: number;\n preserveDecimals?: boolean;\n maxDecimals?: number;\n }\n): string {\n let decimals: number;\n\n // Backward compatibility: if decimalsOrOptions is a number, use it directly\n if (typeof decimalsOrOptions === 'number') {\n decimals = decimalsOrOptions;\n } else if (decimalsOrOptions && typeof decimalsOrOptions === 'object') {\n // New options object: check if we should preserve decimals\n if (decimalsOrOptions.preserveDecimals) {\n const valueStr = value.toString();\n const decimalIndex = valueStr.indexOf('.');\n \n if (decimalIndex !== -1) {\n const detectedDecimals = valueStr.length - decimalIndex - 1;\n const maxDecimals = decimalsOrOptions.maxDecimals ?? 10;\n decimals = Math.min(detectedDecimals, maxDecimals);\n } else {\n decimals = 0;\n }\n } else {\n decimals = decimalsOrOptions.decimals ?? 1;\n }\n } else {\n decimals = 1;\n }\n\n return new Intl.NumberFormat(locale, {\n style: 'percent',\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(value / 100);\n}\n\n/**\n * Format a large number with abbreviations (K, M, B)\n */\nexport function formatCompactNumber(value: number, locale = 'en-US'): string {\n return new Intl.NumberFormat(locale, {\n notation: 'compact',\n compactDisplay: 'short'\n }).format(value);\n}\n\n/**\n * Format a file size in bytes to a human-readable string\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes';\n \n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n \n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -25,16 +25,16 @@ import {
|
|
|
25
25
|
SelectSeparator,
|
|
26
26
|
SelectTrigger,
|
|
27
27
|
SelectValue
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-UW2DE6JX.js";
|
|
29
29
|
import {
|
|
30
30
|
usePermissions,
|
|
31
31
|
useRBAC,
|
|
32
32
|
useResolvedScope
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-WWNOVFDC.js";
|
|
34
34
|
import {
|
|
35
35
|
isPermitted,
|
|
36
36
|
isSuperAdmin
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-F6TSYCKP.js";
|
|
38
38
|
import {
|
|
39
39
|
OrganisationProvider_exports,
|
|
40
40
|
PublicErrorBoundary,
|
|
@@ -49,18 +49,18 @@ import {
|
|
|
49
49
|
useIsPublicPage,
|
|
50
50
|
usePublicFileDisplay,
|
|
51
51
|
usePublicPageContext
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-2W4WKJVF.js";
|
|
53
53
|
import {
|
|
54
54
|
useToast
|
|
55
55
|
} from "./chunk-4OX5PXHX.js";
|
|
56
56
|
import {
|
|
57
57
|
useEvents,
|
|
58
58
|
useOrganisations
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-EZ64QG2I.js";
|
|
60
60
|
import {
|
|
61
61
|
UnifiedAuthProvider_exports,
|
|
62
62
|
init_UnifiedAuthProvider as init_UnifiedAuthProvider2
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-EYSXQ756.js";
|
|
64
64
|
import {
|
|
65
65
|
EventServiceContext,
|
|
66
66
|
EventServiceProvider,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
useEventService,
|
|
71
71
|
useSessionRestoration,
|
|
72
72
|
useUnifiedAuth
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-AUXS7XSO.js";
|
|
74
74
|
import {
|
|
75
75
|
LoadingSpinner
|
|
76
76
|
} from "./chunk-CDQ3PX7L.js";
|
|
@@ -1378,19 +1378,27 @@ function PaceAppLayout({
|
|
|
1378
1378
|
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
1379
1379
|
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1380
1380
|
};
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1381
|
+
try {
|
|
1382
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-5I3E47G2.js");
|
|
1383
|
+
const isSuper = await isSuperAdmin2(user.id);
|
|
1384
|
+
if (isSuper) {
|
|
1385
|
+
return true;
|
|
1386
|
+
}
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
|
|
1389
|
+
} else {
|
|
1390
|
+
throw error;
|
|
1391
|
+
}
|
|
1385
1392
|
}
|
|
1386
1393
|
if (!scope.organisationId) {
|
|
1387
1394
|
console.warn("No organisation context available for permission check, denying access");
|
|
1388
1395
|
return false;
|
|
1389
1396
|
}
|
|
1397
|
+
const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
|
|
1390
1398
|
return await isPermitted({
|
|
1391
1399
|
userId: user.id,
|
|
1392
1400
|
scope,
|
|
1393
|
-
permission,
|
|
1401
|
+
permission: fullPermission,
|
|
1394
1402
|
pageId
|
|
1395
1403
|
});
|
|
1396
1404
|
} catch (error) {
|
|
@@ -1473,34 +1481,82 @@ function PaceAppLayout({
|
|
|
1473
1481
|
}, [enforcePermissions, currentRoutePermission, currentPageId, strictMode, user?.id]);
|
|
1474
1482
|
const [filteredMenuItems, setFilteredMenuItems] = useState5(baseMenuItems);
|
|
1475
1483
|
useEffect3(() => {
|
|
1476
|
-
if (!filterNavigationByPermissions
|
|
1484
|
+
if (!filterNavigationByPermissions) {
|
|
1477
1485
|
setFilteredMenuItems(baseMenuItems);
|
|
1478
1486
|
return;
|
|
1479
1487
|
}
|
|
1480
1488
|
let isMounted = true;
|
|
1481
1489
|
const filterItems = async () => {
|
|
1482
|
-
|
|
1483
|
-
|
|
1490
|
+
if (!user?.id) {
|
|
1491
|
+
if (isMounted) {
|
|
1492
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1493
|
+
}
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const scope = {
|
|
1497
|
+
organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
|
|
1498
|
+
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
1499
|
+
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1500
|
+
};
|
|
1501
|
+
try {
|
|
1502
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-5I3E47G2.js");
|
|
1503
|
+
const isSuper = await isSuperAdmin2(user.id);
|
|
1504
|
+
if (isSuper) {
|
|
1505
|
+
if (isMounted) {
|
|
1506
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1507
|
+
}
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
|
|
1512
|
+
} else {
|
|
1513
|
+
throw error;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
if (!scope.organisationId) {
|
|
1517
|
+
if (isMounted) {
|
|
1518
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1519
|
+
}
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
try {
|
|
1523
|
+
const { getPermissionMap } = await import("./api-5I3E47G2.js");
|
|
1524
|
+
const permissionMap = await getPermissionMap({
|
|
1525
|
+
userId: user.id,
|
|
1526
|
+
scope
|
|
1527
|
+
});
|
|
1528
|
+
const filtered = baseMenuItems.map((item) => {
|
|
1484
1529
|
if (!item.href) return { item, hasAccess: true };
|
|
1485
1530
|
const pageId = pageIdMapping[item.href] || item.href.slice(1) || "home";
|
|
1486
1531
|
const permission = routePermissions[item.href] || defaultPermission;
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1532
|
+
const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
|
|
1533
|
+
const hasAccess = permissionMap["*"] === true || permissionMap[fullPermission] === true;
|
|
1534
|
+
if (auditLog) {
|
|
1535
|
+
console.log(`[PaceAppLayout] Navigation filtering:`, {
|
|
1536
|
+
item: item.label,
|
|
1537
|
+
href: item.href,
|
|
1538
|
+
pageId,
|
|
1539
|
+
permission: fullPermission,
|
|
1540
|
+
hasAccess
|
|
1541
|
+
});
|
|
1492
1542
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1543
|
+
return { item, hasAccess };
|
|
1544
|
+
});
|
|
1545
|
+
if (!isMounted) return;
|
|
1546
|
+
const accessibleItems = filtered.filter(({ hasAccess }) => hasAccess).map(({ item }) => item);
|
|
1547
|
+
setFilteredMenuItems(accessibleItems);
|
|
1548
|
+
} catch (error) {
|
|
1549
|
+
console.error("[PaceAppLayout] Failed to load permission map for navigation filtering:", error);
|
|
1550
|
+
if (isMounted) {
|
|
1551
|
+
setFilteredMenuItems(baseMenuItems);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1498
1554
|
};
|
|
1499
1555
|
filterItems();
|
|
1500
1556
|
return () => {
|
|
1501
1557
|
isMounted = false;
|
|
1502
1558
|
};
|
|
1503
|
-
}, [baseMenuItems, filterNavigationByPermissions,
|
|
1559
|
+
}, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, checkPermission, user?.id, user?.user_metadata, user?.app_metadata]);
|
|
1504
1560
|
useEffect3(() => {
|
|
1505
1561
|
if (!roleBasedRouting || routeConfig.length === 0) return;
|
|
1506
1562
|
let isMounted = true;
|
|
@@ -1533,7 +1589,7 @@ function PaceAppLayout({
|
|
|
1533
1589
|
}
|
|
1534
1590
|
}
|
|
1535
1591
|
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
1536
|
-
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-
|
|
1592
|
+
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-A7I23UCN.js");
|
|
1537
1593
|
hasAccess = true;
|
|
1538
1594
|
}
|
|
1539
1595
|
if (!isMounted) return;
|
|
@@ -4357,4 +4413,4 @@ export {
|
|
|
4357
4413
|
PublicPageDiagnostic,
|
|
4358
4414
|
PublicPageContextChecker
|
|
4359
4415
|
};
|
|
4360
|
-
//# sourceMappingURL=chunk-
|
|
4416
|
+
//# sourceMappingURL=chunk-P72NKAT5.js.map
|