From 12ddcb6f5ab64efd1e738d83556a3995a77c01f2 Mon Sep 17 00:00:00 2001 From: JM-Flores Date: Tue, 19 Aug 2025 00:41:56 +0800 Subject: [PATCH 1/3] use loading.tsx during loading state --- .../home/kanban/[projectId]/[id]/loading.tsx | 88 +++++++++++-------- .../app/home/kanban/[projectId]/[id]/page.tsx | 20 +++-- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/apps/codebility/app/home/kanban/[projectId]/[id]/loading.tsx b/apps/codebility/app/home/kanban/[projectId]/[id]/loading.tsx index afceb4bb4..58946ae79 100644 --- a/apps/codebility/app/home/kanban/[projectId]/[id]/loading.tsx +++ b/apps/codebility/app/home/kanban/[projectId]/[id]/loading.tsx @@ -1,11 +1,11 @@ - import { Card, CardContent } from "@/components/ui/card"; +import { IconSearch } from "@/public/assets/svgs"; +import { Plus, Users } from "lucide-react"; + import { Button } from "@codevs/ui/button"; import { CardHeader } from "@codevs/ui/card"; import { Input } from "@codevs/ui/input"; import { Skeleton } from "@codevs/ui/skeleton"; -import { IconSearch } from "@/public/assets/svgs"; -import { Plus, Users } from "lucide-react" export default function KanbanLoadingSkeleton() { return ( @@ -32,9 +32,9 @@ export default function KanbanLoadingSkeleton() {
{Array.from({ length: 6 }).map((_, i) => ( - ))} @@ -51,13 +51,19 @@ export default function KanbanLoadingSkeleton() { {/* Action buttons */}
- -
@@ -67,7 +73,7 @@ export default function KanbanLoadingSkeleton() { {/* Kanban Columns */}
-
+
{/* Column 1 */} @@ -85,20 +91,28 @@ export default function KanbanLoadingSkeleton() {
- ) + ); } -function KanbanColumnSkeleton({ title, cardCount }: { title: string; cardCount: number }) { +function KanbanColumnSkeleton({ + title, + cardCount, +}: { + title: string; + cardCount: number; +}) { return ( -
+ bg-[#FCFCFC] dark:border-zinc-700 + dark:bg-[#2C303A] md:w-[350px] + md:min-w-[350px] lg:w-[400px] lg:min-w-[400px] + " + > {/* Column Header */}
@@ -120,33 +134,35 @@ function KanbanColumnSkeleton({ title, cardCount }: { title: string; cardCount: ))} {/* Add card button skeleton */} -
- +
+ Add a card
- ) + ); } function KanbanCardSkeleton() { return ( -
+ " + > {/* Priority Indicator Bar */} -
+
{/* Task Header */} -
+
- + {/* Primary Avatar */}
@@ -157,7 +173,9 @@ function KanbanCardSkeleton() { {/* Priority and Status */}
- Medium + + Medium +
@@ -170,13 +188,13 @@ function KanbanCardSkeleton() { {/* Sidekick avatars */}
{Array.from({ length: 3 }).map((_, i) => ( - ))}
- ) + ); } diff --git a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx index 33fe07efa..4efc43c02 100644 --- a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx +++ b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx @@ -5,13 +5,14 @@ import { useKanbanStore } from "@/store/kanban-store"; import { KanbanBoardType, KanbanColumnType, Task } from "@/types/home/codev"; import KanbanBoard from "./_components/KanbanBoard"; +import KanbanLoadingSkeleton from "./loading"; interface KanbanBoardPageProps { params: { id: string; projectId: string }; searchParams?: { query?: string }; } -// Mapping functions to convert raw data into our expected types. +// Mapping functions const mapTask = (task: any): Task => ({ id: String(task.id), title: task.title, @@ -51,19 +52,18 @@ export default function KanbanBoardPage({ searchParams, }: KanbanBoardPageProps) { const { boardData, fetchBoardData, setBoardId } = useKanbanStore(); - const [loading, setLoading] = useState(true); + const [loaded, setLoaded] = useState(false); const query = searchParams?.query?.toLowerCase() || ""; useEffect(() => { const loadData = async () => { - setLoading(true); await setBoardId(params.id); await fetchBoardData(); - setLoading(false); + setLoaded(true); }; loadData(); - }, [params.id, fetchBoardData]); + }, [params.id, fetchBoardData, setBoardId]); const processedBoardData = useMemo(() => { if (!boardData) return null; @@ -95,15 +95,17 @@ export default function KanbanBoardPage({ } as KanbanBoardType & { kanban_columns: KanbanColumnType[] }; }, [boardData, query]); - if (loading) { - return
Loading board...
; + // Show skeleton while loading + if (!processedBoardData && !loaded) { + return ; } - if (!processedBoardData) { + // After load but still no board + if (!processedBoardData && loaded) { return
Board not found
; } return ( - + ); } From 998c003acbb245961ec9ff63af4e041cb7fad575 Mon Sep 17 00:00:00 2001 From: JM-Flores Date: Tue, 19 Aug 2025 00:52:37 +0800 Subject: [PATCH 2/3] minor code fix --- .../app/home/kanban/[projectId]/[id]/page.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx index 4efc43c02..7bb916a6b 100644 --- a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx +++ b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx @@ -12,7 +12,7 @@ interface KanbanBoardPageProps { searchParams?: { query?: string }; } -// Mapping functions +// Mapping functions to convert raw data into our expected types. const mapTask = (task: any): Task => ({ id: String(task.id), title: task.title, @@ -52,15 +52,21 @@ export default function KanbanBoardPage({ searchParams, }: KanbanBoardPageProps) { const { boardData, fetchBoardData, setBoardId } = useKanbanStore(); - const [loaded, setLoaded] = useState(false); + const [loading, setLoading] = useState(true); const query = searchParams?.query?.toLowerCase() || ""; useEffect(() => { const loadData = async () => { - await setBoardId(params.id); - await fetchBoardData(); - setLoaded(true); + setLoading(true); + try { + setBoardId(params.id); // no need to await if this is a Zustand setter + await fetchBoardData(); + } catch (err) { + console.error("Failed to load board data:", err); + } finally { + setLoading(false); + } }; loadData(); }, [params.id, fetchBoardData, setBoardId]); @@ -95,17 +101,15 @@ export default function KanbanBoardPage({ } as KanbanBoardType & { kanban_columns: KanbanColumnType[] }; }, [boardData, query]); - // Show skeleton while loading - if (!processedBoardData && !loaded) { + if (loading) { return ; } - // After load but still no board - if (!processedBoardData && loaded) { + if (!processedBoardData) { return
Board not found
; } return ( - + ); } From 2ca503168063d96097761036d6617b82b3b408fd Mon Sep 17 00:00:00 2001 From: JM-Flores Date: Tue, 19 Aug 2025 00:55:59 +0800 Subject: [PATCH 3/3] fix params issue --- .../app/home/kanban/[projectId]/[id]/page.tsx | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx index 7bb916a6b..8d570d098 100644 --- a/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx +++ b/apps/codebility/app/home/kanban/[projectId]/[id]/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { use, useEffect, useMemo, useState } from "react"; import { useKanbanStore } from "@/store/kanban-store"; import { KanbanBoardType, KanbanColumnType, Task } from "@/types/home/codev"; @@ -8,8 +8,8 @@ import KanbanBoard from "./_components/KanbanBoard"; import KanbanLoadingSkeleton from "./loading"; interface KanbanBoardPageProps { - params: { id: string; projectId: string }; - searchParams?: { query?: string }; + params: Promise<{ id: string; projectId: string }>; + searchParams?: Promise<{ query?: string }>; } // Mapping functions to convert raw data into our expected types. @@ -47,20 +47,20 @@ const mapColumn = (column: any): KanbanColumnType => ({ : [], }); -export default function KanbanBoardPage({ - params, - searchParams, -}: KanbanBoardPageProps) { +export default function KanbanBoardPage(props: KanbanBoardPageProps) { const { boardData, fetchBoardData, setBoardId } = useKanbanStore(); const [loading, setLoading] = useState(true); + // ✅ unwrap params and searchParams + const { id, projectId } = use(props.params); + const searchParams = props.searchParams ? use(props.searchParams) : {}; const query = searchParams?.query?.toLowerCase() || ""; useEffect(() => { const loadData = async () => { setLoading(true); try { - setBoardId(params.id); // no need to await if this is a Zustand setter + setBoardId(id); await fetchBoardData(); } catch (err) { console.error("Failed to load board data:", err); @@ -69,7 +69,7 @@ export default function KanbanBoardPage({ } }; loadData(); - }, [params.id, fetchBoardData, setBoardId]); + }, [id, fetchBoardData, setBoardId]); const processedBoardData = useMemo(() => { if (!boardData) return null; @@ -109,7 +109,5 @@ export default function KanbanBoardPage({ return
Board not found
; } - return ( - - ); + return ; }