mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-12 18:22:16 +01:00
upgrade inertia v2; add prefetching; migrate queries to tanstack query
vue
This commit is contained in:
283
resources/js/utils/prefetch.ts
Normal file
283
resources/js/utils/prefetch.ts
Normal file
@@ -0,0 +1,283 @@
|
||||
import type { QueryClient } from '@tanstack/vue-query';
|
||||
import { api } from '@/packages/api/src';
|
||||
import { getCurrentOrganizationId } from '@/utils/useUser';
|
||||
import { canViewClients, canViewMembers } from '@/utils/permissions';
|
||||
|
||||
/**
|
||||
* Route patterns mapped to their prefetch functions.
|
||||
* Each function receives the QueryClient and prefetches relevant data.
|
||||
*/
|
||||
const routePrefetchers: Record<string, (queryClient: QueryClient) => void> = {
|
||||
'/': (queryClient) => {
|
||||
prefetchDashboard(queryClient);
|
||||
},
|
||||
|
||||
'/dashboard': (queryClient) => {
|
||||
prefetchDashboard(queryClient);
|
||||
},
|
||||
|
||||
'/time': (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchTasks(queryClient);
|
||||
prefetchTags(queryClient);
|
||||
prefetchClients(queryClient);
|
||||
},
|
||||
|
||||
'/calendar': (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchTasks(queryClient);
|
||||
prefetchTags(queryClient);
|
||||
prefetchClients(queryClient);
|
||||
},
|
||||
|
||||
'/projects': (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchClients(queryClient);
|
||||
},
|
||||
|
||||
'/clients': (queryClient) => {
|
||||
prefetchClients(queryClient);
|
||||
},
|
||||
|
||||
'/tags': (queryClient) => {
|
||||
prefetchTags(queryClient);
|
||||
},
|
||||
|
||||
'/members': (queryClient) => {
|
||||
prefetchMembers(queryClient);
|
||||
},
|
||||
|
||||
'/reporting': (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchTags(queryClient);
|
||||
prefetchClients(queryClient);
|
||||
prefetchMembers(queryClient);
|
||||
},
|
||||
|
||||
'/reporting/detailed': (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchTasks(queryClient);
|
||||
prefetchTags(queryClient);
|
||||
prefetchClients(queryClient);
|
||||
prefetchMembers(queryClient);
|
||||
},
|
||||
|
||||
'/reporting/shared': (queryClient) => {
|
||||
prefetchReports(queryClient);
|
||||
},
|
||||
};
|
||||
|
||||
function prefetchDashboard(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId) return;
|
||||
|
||||
// Prefetch all dashboard card data
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['timeEntries', organizationId],
|
||||
queryFn: () =>
|
||||
api.getTimeEntries({
|
||||
params: { organization: organizationId },
|
||||
queries: { limit: 10, offset: 0, only_full_dates: 'true' },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['lastSevenDays', organizationId],
|
||||
queryFn: () => api.lastSevenDays({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['dailyTrackedHours', organizationId],
|
||||
queryFn: () => api.dailyTrackedHours({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['weeklyProjectOverview', organizationId],
|
||||
queryFn: () => api.weeklyProjectOverview({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['totalWeeklyTime', organizationId],
|
||||
queryFn: () => api.totalWeeklyTime({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['totalWeeklyBillableTime', organizationId],
|
||||
queryFn: () => api.totalWeeklyBillableTime({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['totalWeeklyBillableAmount', organizationId],
|
||||
queryFn: () => api.totalWeeklyBillableAmount({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['weeklyHistory', organizationId],
|
||||
queryFn: () => api.weeklyHistory({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
|
||||
// Prefetch team activity only if user has permission
|
||||
if (canViewMembers()) {
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['latestTeamActivity', organizationId],
|
||||
queryFn: () => api.latestTeamActivity({ params: { organization: organizationId } }),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function prefetchProjects(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['projects'],
|
||||
queryFn: () =>
|
||||
api.getProjects({
|
||||
params: { organization: organizationId },
|
||||
queries: { archived: 'all' },
|
||||
}),
|
||||
staleTime: 30000, // Consider fresh for 30 seconds
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchTasks(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['tasks'],
|
||||
queryFn: () =>
|
||||
api.getTasks({
|
||||
params: { organization: organizationId },
|
||||
queries: { done: 'all' },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchTags(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['tags'],
|
||||
queryFn: () =>
|
||||
api.getTags({
|
||||
params: { organization: organizationId },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchClients(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId || !canViewClients()) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['clients'],
|
||||
queryFn: () =>
|
||||
api.getClients({
|
||||
params: { organization: organizationId },
|
||||
queries: { archived: 'all' },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchMembers(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId || !canViewMembers()) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['members'],
|
||||
queryFn: () =>
|
||||
api.getMembers({
|
||||
params: { organization: organizationId },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchReports(queryClient: QueryClient) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['reports', 1],
|
||||
queryFn: () =>
|
||||
api.getReports({
|
||||
params: { organization: organizationId },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchProjectMembers(queryClient: QueryClient, projectId: string) {
|
||||
const organizationId = getCurrentOrganizationId();
|
||||
if (!organizationId || !canViewMembers()) return;
|
||||
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['projectMembers', projectId],
|
||||
queryFn: () =>
|
||||
api.getProjectMembers({
|
||||
params: { organization: organizationId, project: projectId },
|
||||
}),
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a URL to find the appropriate prefetcher.
|
||||
* Handles both exact matches and pattern matching for dynamic routes.
|
||||
*/
|
||||
function findPrefetcher(url: string): ((queryClient: QueryClient) => void) | undefined {
|
||||
// Extract pathname from URL
|
||||
const pathname = url.startsWith('http') ? new URL(url).pathname : url.split('?')[0];
|
||||
|
||||
// Try exact match first
|
||||
if (routePrefetchers[pathname]) {
|
||||
return routePrefetchers[pathname];
|
||||
}
|
||||
|
||||
// Try pattern matching for dynamic routes like /projects/{id}
|
||||
const projectMatch = pathname.match(/^\/projects\/([^/]+)$/);
|
||||
if (projectMatch) {
|
||||
const projectId = projectMatch[1];
|
||||
return (queryClient) => {
|
||||
prefetchProjects(queryClient);
|
||||
prefetchTasks(queryClient);
|
||||
prefetchProjectMembers(queryClient, projectId);
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up Inertia prefetch event listener to warm TanStack Query cache.
|
||||
* Call this once during app initialization.
|
||||
*/
|
||||
export function setupPrefetching(queryClient: QueryClient) {
|
||||
// Listen for the 'prefetching' event which fires when Inertia starts prefetching a page
|
||||
// The event detail contains the visit object with the URL being prefetched
|
||||
document.addEventListener('inertia:prefetching', ((event: CustomEvent) => {
|
||||
const visit = event.detail?.visit;
|
||||
if (!visit?.url) return;
|
||||
|
||||
const url = visit.url.href || visit.url.toString();
|
||||
const prefetcher = findPrefetcher(url);
|
||||
|
||||
if (prefetcher) {
|
||||
prefetcher(queryClient);
|
||||
}
|
||||
}) as EventListener);
|
||||
}
|
||||
Reference in New Issue
Block a user