diff --git a/app/panel/cases/[id]/page.tsx b/app/panel/cases/[id]/page.tsx new file mode 100644 index 0000000..267e32e --- /dev/null +++ b/app/panel/cases/[id]/page.tsx @@ -0,0 +1,41 @@ +import { ReportCard } from "@/components/cards/ReportCard"; +import { CardLink } from "@/components/common/CardLink"; +import { NavigationToolbar } from "@/components/common/NavigationToolbar"; +import { CaseActions } from "@/components/pages/inspector/CaseActions"; +import { fetchCaseById, fetchReportsByCase } from "@/lib/db"; +import { PizzaIcon } from "lucide-react"; +import { notFound } from "next/navigation"; + +export default async function Reports({ params }: { params: { id: string } }) { + const Case = await fetchCaseById(params.id); + if (!Case) return notFound(); + + const reports = await fetchReportsByCase(params.id); + + return ( +
+ Viewing Case + + +
+

Reports

+ {reports.length ? ( + reports.map((report) => ( + + + + )) + ) : ( + <> +

+ +

+

+ No reports added yet. +

+ + )} +
+
+ ); +} diff --git a/app/panel/cases/page.tsx b/app/panel/cases/page.tsx new file mode 100644 index 0000000..818077a --- /dev/null +++ b/app/panel/cases/page.tsx @@ -0,0 +1,37 @@ +import { CaseCard } from "@/components/cards/CaseCard"; +import { CardLink } from "@/components/common/CardLink"; +import { CreateCase } from "@/components/common/CreateCase"; +import { fetchOpenCases } from "@/lib/db"; +import { PizzaIcon } from "lucide-react"; + +export default async function Reports() { + const cases = (await fetchOpenCases()).reverse(); + + return ( +
+
+
+ +

Open Cases

+
+ + {cases.length ? ( + cases.map((entry) => ( + + + + )) + ) : ( + <> +

+ +

+

+ No cases currently open. +

+ + )} +
+
+ ); +} diff --git a/app/panel/reports/page.tsx b/app/panel/reports/page.tsx index 9ffd39c..ba6bc48 100644 --- a/app/panel/reports/page.tsx +++ b/app/panel/reports/page.tsx @@ -13,12 +13,15 @@ export default async function Reports() { const byCategory: Record = { Urgent: [], All: [], + AssignedToCase: [], }; const keyOrder = ["Urgent", "All"]; const countsByAuthor: Record = {}; for (const report of reports) { - if (report.content.report_reason.includes("Illegal")) { + if (report.case_id) { + byCategory.AssignedToCase.push(report); + } else if (report.content.report_reason.includes("Illegal")) { byCategory.Urgent.push(report); } else { countsByAuthor[report.author_id] = @@ -50,21 +53,23 @@ export default async function Reports() {
{/**/} {reports.length ? ( - keyOrder.map((key) => { - return ( -
-

{authorNames[key] ?? key}

- {byCategory[key].map((report) => ( - - - - ))}{" "} -
- ); - }) + keyOrder + .filter((key) => byCategory[key].length) + .map((key) => { + return ( +
+

{authorNames[key] ?? key}

+ {byCategory[key].map((report) => ( + + + + ))}{" "} +
+ ); + }) ) : ( <>

@@ -75,6 +80,20 @@ export default async function Reports() {

)} + {byCategory["AssignedToCase"].length && ( +
+ +

Reports assigned to cases

+
+
+ {byCategory["AssignedToCase"].map((report) => ( + + + + ))} +
+
+ )}
); } diff --git a/components/cards/CaseCard.tsx b/components/cards/CaseCard.tsx new file mode 100644 index 0000000..0310f53 --- /dev/null +++ b/components/cards/CaseCard.tsx @@ -0,0 +1,32 @@ +import { Report } from "revolt-api"; +import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; +import { Badge } from "../ui/badge"; +import dayjs from "dayjs"; +import { decodeTime } from "ulid"; + +import relativeTime from "dayjs/plugin/relativeTime"; +import { CaseDocument } from "@/lib/db"; +dayjs.extend(relativeTime); + +export function CaseCard({ entry: entry }: { entry: CaseDocument }) { + return ( + + + + {entry.title || "No reason specified"} + + + {entry._id.toString().substring(20, 26)} ·{" "} + {dayjs(decodeTime(entry._id)).fromNow()} · {entry.author}{" "} + {entry.status !== "Open" && entry.closed_at && ( + <>· Closed {dayjs(entry.closed_at).fromNow()} + )} + + + + ); +} diff --git a/components/common/CreateCase.tsx b/components/common/CreateCase.tsx new file mode 100644 index 0000000..75f2c5b --- /dev/null +++ b/components/common/CreateCase.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { Plus } from "lucide-react"; +import { Button } from "../ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; +import { Label } from "../ui/label"; +import { Input } from "../ui/input"; +import { useState } from "react"; +import { createCase } from "@/lib/db"; +import { useRouter } from "next/navigation"; + +export function CreateCase() { + const [title, setTitle] = useState(""); + const router = useRouter(); + + return ( + + + + + +
+
+

Create Case

+
+
+
+ + setTitle(e.currentTarget.value)} + /> +
+ +
+
+
+
+ ); +} diff --git a/components/common/NavigationLinks.tsx b/components/common/NavigationLinks.tsx index 1a147c9..a51e1a8 100644 --- a/components/common/NavigationLinks.tsx +++ b/components/common/NavigationLinks.tsx @@ -11,6 +11,7 @@ import { Siren, Sparkles, TrendingUp, + BookCopy, } from "lucide-react"; export function NavigationLinks() { @@ -34,6 +35,12 @@ export function NavigationLinks() { > + + + router.back()}> - + {/*