feat(archive): archived card list with unarchive
This commit is contained in:
parent
7ec075567b
commit
6112db1bb6
3 changed files with 99 additions and 1 deletions
|
|
@ -203,3 +203,27 @@ export async function archiveCard(input: {
|
||||||
|
|
||||||
revalidatePath(boardPath(input.clientSlug, input.projectSlug));
|
revalidatePath(boardPath(input.clientSlug, input.projectSlug));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function unarchiveCard(input: {
|
||||||
|
cardId: string;
|
||||||
|
clientSlug: string;
|
||||||
|
projectSlug: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
const session = await requireOwner();
|
||||||
|
const pb = await getServerPb();
|
||||||
|
|
||||||
|
const card = await pb.collection("cards").getOne<CardRecord>(input.cardId);
|
||||||
|
|
||||||
|
await pb.collection("cards").update(input.cardId, { archived: false });
|
||||||
|
|
||||||
|
await logActivity({
|
||||||
|
project: card.project,
|
||||||
|
card: card.id,
|
||||||
|
actor: session.userId,
|
||||||
|
action: "card_updated",
|
||||||
|
field: "archived",
|
||||||
|
});
|
||||||
|
|
||||||
|
revalidatePath(boardPath(input.clientSlug, input.projectSlug));
|
||||||
|
revalidatePath(`${boardPath(input.clientSlug, input.projectSlug)}/archive`);
|
||||||
|
}
|
||||||
66
src/app/p/[clientSlug]/[projectSlug]/archive/page.tsx
Normal file
66
src/app/p/[clientSlug]/[projectSlug]/archive/page.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import Link from "next/link";
|
||||||
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
import { ArrowLeft } from "lucide-react";
|
||||||
|
|
||||||
|
import { AppShell } from "@/components/shell/app-shell";
|
||||||
|
import { TopBar } from "@/components/shell/top-bar";
|
||||||
|
import { AdminTable, AdminCell } from "@/components/admin/admin-table";
|
||||||
|
import { getSession } from "@/lib/auth/session";
|
||||||
|
import { getServerPb } from "@/lib/pb/server";
|
||||||
|
import { loadBoard } from "@/lib/data/board";
|
||||||
|
import { relativeTime } from "@/lib/time/relative";
|
||||||
|
import type { CardRecord } from "@/lib/pb/types";
|
||||||
|
|
||||||
|
export default async function ArchivePage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ clientSlug: string; projectSlug: string }>;
|
||||||
|
}) {
|
||||||
|
const session = await getSession();
|
||||||
|
if (!session) redirect("/login");
|
||||||
|
|
||||||
|
const { clientSlug, projectSlug } = await params;
|
||||||
|
const board = await loadBoard(clientSlug, projectSlug);
|
||||||
|
if (!board) notFound();
|
||||||
|
|
||||||
|
const pb = await getServerPb();
|
||||||
|
const cards = await pb.collection("cards").getFullList<CardRecord>({
|
||||||
|
filter: `project = "${board.project.id}" && archived = true`,
|
||||||
|
sort: "-updated",
|
||||||
|
});
|
||||||
|
|
||||||
|
const boardHref = `/p/${clientSlug}/${projectSlug}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppShell role={session.role} currentPath={boardHref}>
|
||||||
|
<TopBar title="Archive" subtitle={board.project.name} />
|
||||||
|
|
||||||
|
<div className="flex-1 space-y-4 overflow-y-auto p-6">
|
||||||
|
<Link
|
||||||
|
href={boardHref}
|
||||||
|
className="inline-flex items-center gap-1.5 text-xs text-text-muted hover:text-text-secondary"
|
||||||
|
>
|
||||||
|
<ArrowLeft size={13} strokeWidth={2} />
|
||||||
|
Back to board
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<AdminTable
|
||||||
|
headers={["Card", "Archived", ""]}
|
||||||
|
empty="Nothing has been archived on this project."
|
||||||
|
>
|
||||||
|
{cards.map((card) => (
|
||||||
|
<tr key={card.id}>
|
||||||
|
<AdminCell className="font-medium text-text-primary">
|
||||||
|
<Link href={`${boardHref}/c/${card.id}`} className="hover:text-brand">
|
||||||
|
{card.title}
|
||||||
|
</Link>
|
||||||
|
</AdminCell>
|
||||||
|
<AdminCell>{relativeTime(card.updated)}</AdminCell>
|
||||||
|
<AdminCell align="right">{""}</AdminCell>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</AdminTable>
|
||||||
|
</div>
|
||||||
|
</AppShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Link from "next/link";
|
||||||
import { notFound, redirect } from "next/navigation";
|
import { notFound, redirect } from "next/navigation";
|
||||||
|
|
||||||
import { AppShell } from "@/components/shell/app-shell";
|
import { AppShell } from "@/components/shell/app-shell";
|
||||||
|
|
@ -27,7 +28,14 @@ export default async function BoardPage({
|
||||||
role={session.role}
|
role={session.role}
|
||||||
currentPath={`/p/${clientSlug}/${projectSlug}`}
|
currentPath={`/p/${clientSlug}/${projectSlug}`}
|
||||||
>
|
>
|
||||||
<TopBar title={board.project.name} subtitle={board.client.name} />
|
<TopBar title={board.project.name} subtitle={board.client.name}>
|
||||||
|
<Link
|
||||||
|
href={`/p/${clientSlug}/${projectSlug}/archive`}
|
||||||
|
className="text-xs text-text-muted hover:text-text-secondary"
|
||||||
|
>
|
||||||
|
Archive
|
||||||
|
</Link>
|
||||||
|
</TopBar>
|
||||||
<Board
|
<Board
|
||||||
role={session.role}
|
role={session.role}
|
||||||
projectId={board.project.id}
|
projectId={board.project.id}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue