add the ability to add an admin comment

This commit is contained in:
Thomas Camlong
2025-11-23 09:20:11 +01:00
parent b741808457
commit cc72ef3e27
4 changed files with 120 additions and 26 deletions

View File

@@ -1,12 +1,23 @@
"use client"
import { AlertCircle, RefreshCw } from "lucide-react"
import * as React from "react"
import { ExperimentalWarning } from "@/components/experimental-warning"
import { SubmissionsDataTable } from "@/components/submissions-data-table"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
import { Skeleton } from "@/components/ui/skeleton"
import { Textarea } from "@/components/ui/textarea"
import { useApproveSubmission, useAuth, useRejectSubmission, useSubmissions } from "@/hooks/use-submissions"
export default function DashboardPage() {
@@ -20,6 +31,11 @@ export default function DashboardPage() {
const approveMutation = useApproveSubmission()
const rejectMutation = useRejectSubmission()
// Rejection dialog state
const [rejectDialogOpen, setRejectDialogOpen] = React.useState(false)
const [rejectingSubmissionId, setRejectingSubmissionId] = React.useState<string | null>(null)
const [adminComment, setAdminComment] = React.useState("")
const isLoading = authLoading || submissionsLoading
const isAuthenticated = auth?.isAuthenticated ?? false
const isAdmin = auth?.isAdmin ?? false
@@ -30,7 +46,33 @@ export default function DashboardPage() {
}
const handleReject = (submissionId: string) => {
rejectMutation.mutate(submissionId)
setRejectingSubmissionId(submissionId)
setAdminComment("")
setRejectDialogOpen(true)
}
const handleRejectSubmit = () => {
if (rejectingSubmissionId) {
rejectMutation.mutate(
{
submissionId: rejectingSubmissionId,
adminComment: adminComment.trim() || undefined,
},
{
onSuccess: () => {
setRejectDialogOpen(false)
setRejectingSubmissionId(null)
setAdminComment("")
},
},
)
}
}
const handleRejectDialogClose = () => {
setRejectDialogOpen(false)
setRejectingSubmissionId(null)
setAdminComment("")
}
// Not authenticated
@@ -104,29 +146,62 @@ export default function DashboardPage() {
// Success state
return (
<main className="container mx-auto pt-12 pb-14 px-4 sm:px-6 lg:px-8">
<ExperimentalWarning message="The submissions dashboard is currently in an experimentation phase. Submissions will not be reviewed or processed at this time. We're gathering feedback to improve the experience." />
<Card className="bg-background/50 border-none shadow-lg">
<CardHeader>
<CardTitle>Submissions Dashboard</CardTitle>
<CardDescription>
{isAdmin
? "Review and manage all icon submissions. Click on a row to see details."
: "View your icon submissions and track their status."}
</CardDescription>
</CardHeader>
<CardContent>
<SubmissionsDataTable
data={submissions}
isAdmin={isAdmin}
currentUserId={currentUserId}
onApprove={handleApprove}
onReject={handleReject}
isApproving={approveMutation.isPending}
isRejecting={rejectMutation.isPending}
/>
</CardContent>
</Card>
</main>
<>
<main className="container mx-auto pt-12 pb-14 px-4 sm:px-6 lg:px-8">
<ExperimentalWarning message="The submissions dashboard is currently in an experimentation phase. Submissions will not be reviewed or processed at this time. We're gathering feedback to improve the experience." />
<Card className="bg-background/50 border-none shadow-lg">
<CardHeader>
<CardTitle>Submissions Dashboard</CardTitle>
<CardDescription>
{isAdmin
? "Review and manage all icon submissions. Click on a row to see details."
: "View your icon submissions and track their status."}
</CardDescription>
</CardHeader>
<CardContent>
<SubmissionsDataTable
data={submissions}
isAdmin={isAdmin}
currentUserId={currentUserId}
onApprove={handleApprove}
onReject={handleReject}
isApproving={approveMutation.isPending}
isRejecting={rejectMutation.isPending}
/>
</CardContent>
</Card>
</main>
<Dialog open={rejectDialogOpen} onOpenChange={handleRejectDialogClose}>
<DialogContent>
<DialogHeader>
<DialogTitle>Reject Submission</DialogTitle>
<DialogDescription>
Please provide a reason for rejecting this submission. This comment will be visible to the submitter.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="admin-comment">Admin Comment</Label>
<Textarea
id="admin-comment"
placeholder="Enter rejection reason..."
value={adminComment}
onChange={(e) => setAdminComment(e.target.value)}
rows={4}
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={handleRejectDialogClose} disabled={rejectMutation.isPending}>
Cancel
</Button>
<Button variant="destructive" onClick={handleRejectSubmit} disabled={rejectMutation.isPending}>
{rejectMutation.isPending ? "Rejecting..." : "Reject Submission"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)
}

View File

@@ -8,6 +8,7 @@ import {
Eye,
FileType,
FolderOpen,
MessageSquare,
Palette,
Tag,
User as UserIcon,
@@ -17,6 +18,7 @@ import Image from "next/image";
import Link from "next/link";
import { IconCard } from "@/components/icon-card";
import { MagicCard } from "@/components/magicui/magic-card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -409,6 +411,20 @@ export function SubmissionDetails({
</div>
</div>
{submission.admin_comment?.trim() && (
<Alert
variant={
submission.status === "rejected" ? "destructive" : "default"
}
>
<MessageSquare className="h-4 w-4" />
<AlertTitle>Admin Comment</AlertTitle>
<AlertDescription className="mt-2 whitespace-pre-wrap">
{submission.admin_comment}
</AlertDescription>
</Alert>
)}
<Separator />
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">

View File

@@ -74,12 +74,13 @@ export function useRejectSubmission() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async (submissionId: string) => {
mutationFn: async ({ submissionId, adminComment }: { submissionId: string; adminComment?: string }) => {
return await pb.collection("submissions").update(
submissionId,
{
status: "rejected",
approved_by: pb.authStore.record?.id || "",
admin_comment: adminComment || "",
},
{
requestKey: null,

View File

@@ -36,6 +36,8 @@ export interface Submission {
}
created: string
updated: string
admin_comment: string,
description: string,
}
export interface CommunityGallery {