"use client"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { SignInButton, SignedIn, SignedOut, useAuth } from "@clerk/nextjs"; import { type ColumnDef, flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; import { getApiBaseUrl } from "@/lib/api-base"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; type Board = { id: string; name: string; slug: string; }; const apiBase = getApiBaseUrl(); export default function BoardsPage() { const { getToken, isSignedIn } = useAuth(); const router = useRouter(); const [boards, setBoards] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [isDeleting, setIsDeleting] = useState(false); const [deleteError, setDeleteError] = useState(null); const sortedBoards = useMemo( () => [...boards].sort((a, b) => a.name.localeCompare(b.name)), [boards] ); const loadBoards = async () => { if (!isSignedIn) return; setIsLoading(true); setError(null); try { const token = await getToken(); const response = await fetch(`${apiBase}/api/v1/boards`, { headers: { Authorization: token ? `Bearer ${token}` : "", }, }); if (!response.ok) { throw new Error("Unable to load boards."); } const data = (await response.json()) as Board[]; setBoards(data); } catch (err) { setError(err instanceof Error ? err.message : "Something went wrong."); } finally { setIsLoading(false); } }; useEffect(() => { loadBoards(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isSignedIn]); const handleDelete = async () => { if (!deleteTarget || !isSignedIn) return; setIsDeleting(true); setDeleteError(null); try { const token = await getToken(); const response = await fetch(`${apiBase}/api/v1/boards/${deleteTarget.id}`, { method: "DELETE", headers: { Authorization: token ? `Bearer ${token}` : "", }, }); if (!response.ok) { throw new Error("Unable to delete board."); } setBoards((prev) => prev.filter((board) => board.id !== deleteTarget.id)); setDeleteTarget(null); } catch (err) { setDeleteError(err instanceof Error ? err.message : "Something went wrong."); } finally { setIsDeleting(false); } }; const columns = useMemo[]>( () => [ { accessorKey: "name", header: "Board", cell: ({ row }) => (

{row.original.name}

{row.original.slug}

), }, { id: "actions", header: "", cell: ({ row }) => (
event.stopPropagation()} > Open Edit
), }, ], [] ); const table = useReactTable({ data: sortedBoards, columns, getCoreRowModel: getCoreRowModel(), }); return (

Sign in to view boards.

Boards

{sortedBoards.length} board {sortedBoards.length === 1 ? "" : "s"} total.

{error && (
{error}
)} {sortedBoards.length === 0 && !isLoading ? (
No boards yet. Create your first board to get started.
) : (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} {table.getRowModel().rows.map((row) => ( router.push(`/boards/${row.original.id}`)} > {row.getVisibleCells().map((cell) => ( ))} ))}
{header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )}
{flexRender( cell.column.columnDef.cell, cell.getContext() )}
)}
{ if (!nextOpen) { setDeleteTarget(null); setDeleteError(null); } }} > Delete board This will remove {deleteTarget?.name}. This action cannot be undone. {deleteError ? (
{deleteError}
) : null}
); }