diff --git a/app/(dashboard)/[tenant]/projects/[projectId]/layout.tsx b/app/(dashboard)/[tenant]/projects/[projectId]/layout.tsx
index f557082..eaac17f 100644
--- a/app/(dashboard)/[tenant]/projects/[projectId]/layout.tsx
+++ b/app/(dashboard)/[tenant]/projects/[projectId]/layout.tsx
@@ -1,12 +1,16 @@
"use client";
import { TaskListsProvider } from "@/hooks/use-tasklist";
+import { useProjectPrefetch } from "@/hooks/use-project-prefetch";
import { useParams } from "next/navigation";
export default function Layout({ children }: { children: React.ReactNode }) {
- const { projectId } = useParams();
+ const params = useParams();
+ const projectId = +params.projectId!;
+
+ useProjectPrefetch(projectId);
return (
- {children}
+ {children}
);
}
diff --git a/bun.lock b/bun.lock
index 8592883..f0fb952 100644
--- a/bun.lock
+++ b/bun.lock
@@ -41,7 +41,7 @@
"@upstash/search": "^0.1.5",
"@upstash/workflow": "^0.2.16",
"autoprefixer": "10.4.14",
- "caniuse-lite": "^1.0.30001735",
+ "caniuse-lite": "^1.0.30001737",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
@@ -1218,7 +1218,7 @@
"camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="],
- "caniuse-lite": ["caniuse-lite@1.0.30001735", "", {}, "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w=="],
+ "caniuse-lite": ["caniuse-lite@1.0.30001737", "", {}, "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
diff --git a/components/form/task.tsx b/components/form/task.tsx
index 4768345..2dc7bbc 100644
--- a/components/form/task.tsx
+++ b/components/form/task.tsx
@@ -18,8 +18,7 @@ export default function InlineTaskForm({
const [value, setValue] = useState("");
const inputRef = useRef(null);
- const openCreate = useCallback(() => setIsCreating(true), []);
- useKeyboardShortcut("n", () => openCreate, !isCreating);
+ useKeyboardShortcut("n", () => setIsCreating(true));
const handleSubmit = useCallback(async () => {
await action(value);
diff --git a/components/project/events/full-calendar.tsx b/components/project/events/full-calendar.tsx
index 6d1d698..800b409 100644
--- a/components/project/events/full-calendar.tsx
+++ b/components/project/events/full-calendar.tsx
@@ -74,8 +74,7 @@ export function FullCalendar({
parseAsBoolean.withDefault(false),
);
- const openCreate = useCallback(() => setCreate(true), [setCreate]);
- useKeyboardShortcut("n", () => openCreate);
+ useKeyboardShortcut("n", () => setCreate(true));
const [selectedDay, setSelectedDay] = useState(today);
const [currentMonth, setCurrentMonth] = useState(format(today, "MMM-yyyy"));
diff --git a/hooks/use-project-prefetch.ts b/hooks/use-project-prefetch.ts
new file mode 100644
index 0000000..4fcc863
--- /dev/null
+++ b/hooks/use-project-prefetch.ts
@@ -0,0 +1,59 @@
+"use client";
+
+import { useTRPC } from "@/trpc/client";
+import { useQueryClient } from "@tanstack/react-query";
+import { useEffect } from "react";
+
+export function useProjectPrefetch(projectId: number) {
+ const trpc = useTRPC();
+ const queryClient = useQueryClient();
+
+ useEffect(() => {
+ if (!projectId) return;
+
+ const prefetchData = async () => {
+ const baseQueries = [
+ queryClient.prefetchQuery(
+ trpc.events.getByMonth.queryOptions({
+ projectId,
+ date: new Date(),
+ }),
+ ),
+ queryClient.prefetchQuery(
+ trpc.projects.getProjectById.queryOptions({
+ id: projectId,
+ }),
+ ),
+ ];
+
+ const taskListsQuery = queryClient.prefetchQuery(
+ trpc.tasks.getTaskLists.queryOptions({
+ projectId,
+ }),
+ );
+
+ await Promise.allSettled([...baseQueries, taskListsQuery]);
+
+ const taskListsData = queryClient.getQueryData(
+ trpc.tasks.getTaskLists.queryKey({
+ projectId,
+ }),
+ );
+
+ if (taskListsData) {
+ const individualTaskListQueries = taskListsData.map((taskList) =>
+ queryClient.prefetchQuery(
+ trpc.tasks.getListById.queryOptions({
+ id: taskList.id,
+ }),
+ ),
+ );
+
+ await Promise.allSettled(individualTaskListQueries);
+ }
+ };
+
+ prefetchData();
+ }, [projectId, queryClient, trpc]);
+}
+
diff --git a/package.json b/package.json
index bbeb017..bd7bc2e 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
"@upstash/search": "^0.1.5",
"@upstash/workflow": "^0.2.16",
"autoprefixer": "10.4.14",
- "caniuse-lite": "^1.0.30001735",
+ "caniuse-lite": "^1.0.30001737",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
diff --git a/trpc/routers/tasks.ts b/trpc/routers/tasks.ts
index 817029c..d0cf863 100644
--- a/trpc/routers/tasks.ts
+++ b/trpc/routers/tasks.ts
@@ -31,9 +31,9 @@ export const tasksRouter = createTRPCRouter({
const hasAccess = await canViewProject(ctx, input.projectId);
if (!hasAccess) {
throw new TRPCError({
- code: "FORBIDDEN",
- message: "Project access denied",
- });
+ code: "FORBIDDEN",
+ message: "Project access denied",
+ });
}
const data = await ctx.db.query.taskList