diff --git a/web/src/components/submission-details.tsx b/web/src/components/submission-details.tsx new file mode 100644 index 00000000..d6b153af --- /dev/null +++ b/web/src/components/submission-details.tsx @@ -0,0 +1,403 @@ +"use client" + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Separator } from "@/components/ui/separator" +import { Button } from "@/components/ui/button" +import { Calendar, User as UserIcon, FileType, Tag, FolderOpen, Palette, ExternalLink, Download, Check, X } from "lucide-react" +import { MagicCard } from "@/components/magicui/magic-card" +import { IconCard } from "@/components/icon-card" +import { formatIconName } from "@/lib/utils" +import type { Icon } from "@/types/icons" +import { pb, type Submission, type User } from "@/lib/pb" +import Link from "next/link" +import Image from "next/image" +import { UserDisplay } from "@/components/user-display" + +// Utility function to get display name with priority: username > email > created_by field +const getDisplayName = (submission: Submission, expandedData?: { created_by: User, approved_by: User }): string => { + // Check if we have expanded user data + if (expandedData && expandedData.created_by) { + const user = expandedData.created_by + + // Priority: username > email + if (user.username) { + return user.username + } + if (user.email) { + return user.email + } + } + + // Fallback to created_by field (could be user ID or username) + return submission.created_by +} + +interface SubmissionDetailsProps { + submission: Submission + isAdmin: boolean + onUserClick?: (userId: string, displayName: string) => void + onApprove?: () => void + onReject?: () => void + isApproving?: boolean + isRejecting?: boolean +} + +export function SubmissionDetails({ submission, isAdmin, onUserClick, onApprove, onReject, isApproving, isRejecting }: SubmissionDetailsProps) { + const expandedData = submission.expand + const displayName = getDisplayName(submission, expandedData) + + // Sanitize extras to ensure we have safe defaults + const sanitizedExtras = { + base: submission.extras?.base || "svg", + aliases: submission.extras?.aliases || [], + categories: submission.extras?.categories || [], + colors: submission.extras?.colors || null, + wordmark: submission.extras?.wordmark || null + } + + const formattedCreated = new Date(submission.created).toLocaleDateString("en-GB", { + day: "numeric", + month: "long", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + }) + + const formattedUpdated = new Date(submission.updated).toLocaleDateString("en-GB", { + day: "numeric", + month: "long", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + }) + + // Create a mock Icon object for the IconCard component + const mockIconData: Icon = { + base: sanitizedExtras.base, + aliases: sanitizedExtras.aliases, + categories: sanitizedExtras.categories, + update: { + timestamp: submission.updated, + author: { + id: 1, + name: displayName + } + }, + colors: sanitizedExtras.colors ? { + dark: sanitizedExtras.colors.dark, + light: sanitizedExtras.colors.light + } : undefined, + wordmark: sanitizedExtras.wordmark ? { + dark: sanitizedExtras.wordmark.dark, + light: sanitizedExtras.wordmark.light + } : undefined + } + + const handleDownload = async (url: string, filename: string) => { + try { + const response = await fetch(url) + const blob = await response.blob() + const blobUrl = URL.createObjectURL(blob) + const link = document.createElement("a") + link.href = blobUrl + link.download = filename + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + setTimeout(() => URL.revokeObjectURL(blobUrl), 100) + } catch (error) { + console.error("Download error:", error) + } + } + + return ( +
{formatIconName(submission.name)}
+Filename: {submission.name}
+
+ {sanitizedExtras.colors.dark}
+
+
+ {sanitizedExtras.colors.light}
+
+
+ {sanitizedExtras.wordmark.dark}
+
+
+ {sanitizedExtras.wordmark.light}
+
+ {formattedCreated}
+{formattedUpdated}
+No categories assigned
+ )} +No aliases assigned
+ )} +
+ {submission.id}
+
+