"use client"; import { Download, ExternalLink } from "lucide-react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import * as React from "react"; import { toast } from "sonner"; import type { CommissionStatus } from "@/schemas/commissions/tableSchema"; import { deleteCommissionRequest } from "@/actions/commissions/requests/deleteCommissionRequest"; import { updateCommissionRequest } from "@/actions/commissions/requests/updateCommissionRequest"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; type RequestFile = { id: string; createdAt: Date; originalFile: string; fileType: string; fileSize: number; }; type RequestShape = { id: string; createdAt: Date; updatedAt: Date; status: CommissionStatus; customerName: string; customerEmail: string; customerSocials: string | null; message: string; type: { id: string; name: string } | null; option: { id: string; name: string } | null; extras: { id: string; name: string }[]; priceEstimate?: { min: number; max: number }; files: RequestFile[]; }; const STATUS_OPTIONS: CommissionStatus[] = [ "NEW", "REVIEWING", "ACCEPTED", "REJECTED", "COMPLETED", "SPAM", ]; function isImage(mime: string) { return !!mime && mime.startsWith("image/"); } function formatBytes(bytes: number) { if (!Number.isFinite(bytes)) return "—"; if (bytes < 1024) return `${bytes} B`; const kb = bytes / 1024; if (kb < 1024) return `${kb.toFixed(1)} KB`; const mb = kb / 1024; return `${mb.toFixed(1)} MB`; } function displayUrl(fileId: string) { return `/api/requests/image?mode=display&fileId=${encodeURIComponent(fileId)}`; } function downloadUrl(fileId: string) { return `/api/requests/image?mode=download&fileId=${encodeURIComponent(fileId)}`; } function bulkUrl(requestId: string) { return `/api/requests/image?mode=bulk&requestId=${encodeURIComponent(requestId)}`; } export function CommissionRequestEditor({ request }: { request: RequestShape }) { const router = useRouter(); const [status, setStatus] = React.useState(request.status); const [customerName, setCustomerName] = React.useState(request.customerName); const [customerEmail, setCustomerEmail] = React.useState(request.customerEmail); const [customerSocials, setCustomerSocials] = React.useState(request.customerSocials ?? ""); const [message, setMessage] = React.useState(request.message); const [isSaving, startSaving] = React.useTransition(); const [deleteOpen, setDeleteOpen] = React.useState(false); const dirty = status !== request.status || customerName !== request.customerName || customerEmail !== request.customerEmail || (customerSocials || "") !== (request.customerSocials || "") || message !== request.message; return (
{/* Top bar */}
{request.files.length} file{request.files.length === 1 ? "" : "s"} Status: {request.status} Updated: {new Date(request.updatedAt).toLocaleString()}
{request.files.length > 1 ? ( ) : null}
{/* Request details (artist-facing) */}
Status
Submitted: {new Date(request.createdAt).toLocaleString()}
Selection
Type
{request.type?.name ?? "—"}
Base option
{request.option?.name ?? "—"}
Extras
{request.extras?.length ? (
{request.extras.map((e) => ( {e.name} ))}
) : (
)}
Estimated price
{request.priceEstimate ? request.priceEstimate.min === request.priceEstimate.max ? `€${request.priceEstimate.min.toFixed(2)}` : `€${request.priceEstimate.min.toFixed(2)} – €${request.priceEstimate.max.toFixed(2)}` : "—"}
Customer
setCustomerName(e.target.value)} /> setCustomerEmail(e.target.value)} /> setCustomerSocials(e.target.value)} />
{/* Images / files */}
Reference Images
{request.files.length > 1 ? ( ) : null}
{request.files.length === 0 ? (
No files uploaded.
) : (
{request.files.map((f) => { const preview = displayUrl(f.id); const dl = downloadUrl(f.id); return (
{isImage(f.fileType) ? ( {f.originalFile} ) : (
No preview
)}
{f.originalFile}
{f.fileType} · {formatBytes(f.fileSize)}
{isImage(f.fileType) ? ( ) : null}
); })}
)}
{/* Message */}
Message