"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, Check, Copy, Package, Plus, Save, Trash2, X, } from "lucide-react"; import { useParams, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import * as z from "zod"; import { Badge } from "@/components/ui/badge"; 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 { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { apiClient } from "@/lib/api-client"; import { parseMetadata } from "@/lib/utils"; import { useCopyToClipboard } from "react-use"; import { toast } from "sonner"; const productSchema = z.object({ name: z.string().min(1, "Product name is required"), code: z.string().optional(), url: z.string().optional(), distributionStrategy: z .string() .min(1, "Distribution strategy is required") .optional(), platforms: z.array(z.string()).optional(), metadata: z.string().optional(), }); const DISTRIBUTION_STRATEGIES = ["LICENSED", "OPEN", "CLOSED"]; const COMMON_PLATFORMS = ["windows", "macos", "linux", "ios", "android", "web"]; type ProductFormData = z.infer; export default function ProductDetailPage() { const [, copyToClipboard] = useCopyToClipboard(); const [copiedField, setCopiedField] = useState(null); const [newPlatform, setNewPlatform] = useState(""); const params = useParams(); const router = useRouter(); const queryClient = useQueryClient(); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const productId = params.id as string; const isNew = productId === "new"; const form = useForm({ resolver: zodResolver(productSchema), defaultValues: { distributionStrategy: "LICENSED", }, }); const { data: product, isLoading } = useQuery({ queryKey: ["product", productId], queryFn: () => apiClient.getProduct(productId), enabled: !isNew, }); useEffect(() => { if (product && !isNew) { form.reset({ name: product.data.attributes.name, code: product.data.attributes.code || '', url: product.data.attributes.url || '', distributionStrategy: product.data.attributes.distributionStrategy || 'LICENSED', platforms: product.data.attributes.platforms || [], metadata: product.data.attributes.metadata ? JSON.stringify(product.data.attributes.metadata, null, 2) : "", }); } }, [product, form, isNew]); const createMutation = useMutation({ mutationFn: (productData: ProductFormData) => apiClient.createProduct({ ...productData, metadata: parseMetadata(productData.metadata || ""), }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["products"] }); toast.success("Product created successfully"); router.push("/dashboard/products"); }, onError: (error) => { toast.error(error.message); }, }); const updateMutation = useMutation({ mutationFn: async (productData: ProductFormData) => await apiClient.updateProduct(productId, { ...productData, metadata: parseMetadata(productData.metadata || ""), }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["products"] }); await queryClient.invalidateQueries({ queryKey: ["product", productId] }); toast.success("Product updated successfully"); }, onError: (error) => { console.error(error); toast.error(error.message); }, }); const deleteMutation = useMutation({ mutationFn: async () => await apiClient.deleteProduct(productId), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["products"] }); setIsDeleteDialogOpen(false); toast.success("Product deleted successfully"); router.push("/dashboard/products"); }, onError: (error) => { console.error(error); toast.error(error.message); }, }); const onSubmit = async (data: ProductFormData) => { if (isNew) { await createMutation.mutateAsync({ ...data, code: data.code?.length ? data.code : undefined, url: data.url?.length ? data.url : undefined, distributionStrategy: data.distributionStrategy, platforms: data.platforms, }); } else { console.log('update mutation') await updateMutation.mutateAsync({ ...data, code: data.code?.length ? data.code : undefined, url: data.url?.length ? data.url : undefined, distributionStrategy: data.distributionStrategy, platforms: data.platforms, }); } }; const handleDelete = async () => { if (productId) { await deleteMutation.mutateAsync(); } }; const handleCopy = (text: string, field: string) => { copyToClipboard(text); setCopiedField(field); setTimeout(() => setCopiedField(null), 2000); }; if (isLoading && !isNew) { return ( <>

Loading product...

); } return ( <>

{isNew ? "Create Product" : "Edit Product"}

{isNew ? "Add a new product to your system" : "Update product information and settings"}

{!isNew && ( )}
Product Information {isNew ? "Enter the details for the new product" : "Update the product information below"}
( Product Name
{field.value && ( )}
)} /> ( URL (Optional) )} /> ( Distribution Strategy )} /> ( Platforms
{/* existing platforms */}
{(Array.isArray(field.value) ? field.value : [] ).map((platform: string, idx: number) => ( {platform} {/* use a real button and onMouseDown to avoid blur/click race */} ))}
{/* add new platform input */}
setNewPlatform(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); const v = newPlatform.trim(); if (!v) return; const curr = Array.isArray(field.value) ? field.value : []; if (!curr.includes(v)) { field.onChange([...curr, v]); } setNewPlatform(""); } }} />
{/* quick add common platforms */}
{COMMON_PLATFORMS.filter( (p) => !( Array.isArray(field.value) ? field.value : [] ).includes(p) ).map((platform) => ( ))}
)} /> ( Metadata (JSON)