feat: enhance BoardApprovalsPanel with detailed approval views and chart integration

This commit is contained in:
Abhimanyu Saharan
2026-02-06 02:17:32 +05:30
parent fe3bfade92
commit 574800e5a9
6 changed files with 1038 additions and 301 deletions

View File

@@ -0,0 +1,45 @@
"use client";
import { useParams } from "next/navigation";
import { SignInButton, SignedIn, SignedOut } from "@clerk/nextjs";
import { BoardApprovalsPanel } from "@/components/BoardApprovalsPanel";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
import { Button } from "@/components/ui/button";
export default function BoardApprovalsPage() {
const params = useParams();
const boardIdParam = params?.boardId;
const boardId = Array.isArray(boardIdParam) ? boardIdParam[0] : boardIdParam;
return (
<DashboardShell>
<SignedOut>
<div className="flex h-full flex-col items-center justify-center gap-4 rounded-2xl surface-panel p-10 text-center">
<p className="text-sm text-muted">Sign in to view approvals.</p>
<SignInButton
mode="modal"
forceRedirectUrl="/boards"
signUpForceRedirectUrl="/boards"
>
<Button>Sign in</Button>
</SignInButton>
</div>
</SignedOut>
<SignedIn>
<DashboardSidebar />
<main className="flex-1 overflow-y-auto bg-gradient-to-br from-slate-50 to-slate-100">
<div className="p-6">
{boardId ? (
<div className="h-[calc(100vh-160px)] min-h-[520px]">
<BoardApprovalsPanel boardId={boardId} scrollable />
</div>
) : null}
</div>
</main>
</SignedIn>
</DashboardShell>
);
}

View File

@@ -7,7 +7,6 @@ import { SignInButton, SignedIn, SignedOut, useAuth } from "@clerk/nextjs";
import { MessageSquare, Pencil, Settings, X } from "lucide-react";
import ReactMarkdown from "react-markdown";
import { BoardApprovalsPanel } from "@/components/BoardApprovalsPanel";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { TaskBoard } from "@/components/organisms/TaskBoard";
import { DashboardShell } from "@/components/templates/DashboardShell";
@@ -157,7 +156,6 @@ export default function BoardDetailPage() {
const approvalsRef = useRef<Approval[]>([]);
const agentsRef = useRef<Agent[]>([]);
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [isApprovalsOpen, setIsApprovalsOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [approvals, setApprovals] = useState<Approval[]>([]);
@@ -172,6 +170,7 @@ export default function BoardDetailPage() {
const [isChatSending, setIsChatSending] = useState(false);
const [chatError, setChatError] = useState<string | null>(null);
const chatMessagesRef = useRef<BoardChatMessage[]>([]);
const chatEndRef = useRef<HTMLDivElement | null>(null);
const [isDeletingTask, setIsDeletingTask] = useState(false);
const [deleteTaskError, setDeleteTaskError] = useState<string | null>(null);
const [viewMode, setViewMode] = useState<"board" | "list">("board");
@@ -303,6 +302,14 @@ export default function BoardDetailPage() {
chatMessagesRef.current = chatMessages;
}, [chatMessages]);
useEffect(() => {
if (!isChatOpen) return;
const timeout = window.setTimeout(() => {
chatEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
}, 50);
return () => window.clearTimeout(timeout);
}, [chatMessages, isChatOpen]);
const loadApprovals = useCallback(async () => {
if (!isSignedIn || !boardId) return;
setIsApprovalsLoading(true);
@@ -1433,7 +1440,7 @@ export default function BoardDetailPage() {
</Button>
<Button
variant="outline"
onClick={() => setIsApprovalsOpen(true)}
onClick={() => router.push(`/boards/${boardId}/approvals`)}
className="relative"
>
Approvals
@@ -1545,8 +1552,6 @@ export default function BoardDetailPage() {
{viewMode === "board" ? (
<TaskBoard
tasks={displayTasks}
onCreateTask={() => setIsDialogOpen(true)}
isCreateDisabled={isCreating}
onTaskSelect={openComments}
onTaskMove={handleTaskMove}
/>
@@ -1746,7 +1751,7 @@ export default function BoardDetailPage() {
<Button
variant="outline"
size="sm"
onClick={() => setIsApprovalsOpen(true)}
onClick={() => router.push(`/boards/${boardId}/approvals`)}
>
View all
</Button>
@@ -1926,33 +1931,6 @@ export default function BoardDetailPage() {
</div>
</aside>
<Dialog open={isApprovalsOpen} onOpenChange={setIsApprovalsOpen}>
<DialogContent
aria-label="Approvals"
className="flex h-[85vh] max-w-3xl flex-col overflow-hidden"
>
<DialogHeader>
<DialogTitle>Approvals</DialogTitle>
<DialogDescription>
Review pending decisions from your lead agent.
</DialogDescription>
</DialogHeader>
{boardId ? (
<div className="flex-1 overflow-hidden">
<BoardApprovalsPanel
boardId={boardId}
approvals={approvals}
isLoading={isApprovalsLoading}
error={approvalsError}
onDecision={handleApprovalDecision}
onRefresh={loadApprovals}
scrollable
/>
</div>
) : null}
</DialogContent>
</Dialog>
<aside
className={cn(
"fixed right-0 top-0 z-50 h-full w-[560px] max-w-[96vw] transform border-l border-slate-200 bg-white shadow-2xl transition-transform",
@@ -2026,6 +2004,7 @@ export default function BoardDetailPage() {
</div>
))
)}
<div ref={chatEndRef} />
</div>
<div className="mt-4 space-y-2">
<Textarea