import { useEffect } from "react"; import { useRoute, useLocation } from "wouter"; import { useForm, useFieldArray } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import { useGetTool, useUpdateTool, getGetToolQueryKey, getListToolsQueryKey, getListCategoriesQueryKey, getListAllFeaturesQueryKey, getListAllTagsQueryKey, getGetTopToolsQueryKey, getGetAnalyticsSummaryQueryKey, } from "@workspace/api-client-react"; import { useQueryClient } from "@tanstack/react-query"; import { Layout } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { useToast } from "@/hooks/use-toast"; import { Pencil, Plus, X, ArrowLeft } from "lucide-react"; import { Link } from "wouter"; import { CategoryCombobox } from "@/components/category-combobox"; import { FeatureInput } from "@/components/feature-input"; import { TagInput } from "@/components/tag-input"; import { useAuth } from "@/hooks/use-auth"; import { FieldHelp } from "@/components/field-help"; import { GuideHelp } from "@/components/guide-help"; const toolSchema = z.object({ name: z.string().min(2, "Name must be at least 2 characters"), description: z.string().min(10, "Description must be at least 10 characters"), category: z.string().min(2, "Category is required"), websiteUrl: z.string().url("Must be a valid URL").optional().or(z.literal("")), iconUrl: z.string().url("Must be a valid URL").optional().or(z.literal("")), features: z.array(z.object({ value: z.string() })).optional(), tags: z.array(z.object({ value: z.string() })).optional(), }); type ToolFormValues = z.infer; export default function ToolEdit() { const [match, params] = useRoute("/tools/:id/edit"); const [, setLocation] = useLocation(); const id = parseInt(params?.id || "0", 10); const { toast } = useToast(); const queryClient = useQueryClient(); const updateTool = useUpdateTool(); const { isAuthenticated, isAdmin } = useAuth(); const { data: tool, isLoading } = useGetTool(id, { query: { enabled: !!id, queryKey: getGetToolQueryKey(id) }, }); const form = useForm({ resolver: zodResolver(toolSchema), defaultValues: { name: "", description: "", category: "", websiteUrl: "", iconUrl: "", features: [], tags: [], }, }); useEffect(() => { if (tool) { form.reset({ name: tool.name, description: tool.description, category: tool.category, websiteUrl: tool.websiteUrl || "", iconUrl: tool.iconUrl || "", features: (tool.features || []).map((v) => ({ value: v })), tags: (tool.tags || []).map((v) => ({ value: v })), }); } }, [tool, form]); const { fields: featureFields, append: appendFeature, remove: removeFeature } = useFieldArray({ control: form.control, name: "features", }); const { fields: tagFields, append: appendTag, remove: removeTag } = useFieldArray({ control: form.control, name: "tags", }); const onSubmit = (data: ToolFormValues) => { const payload = { ...data, websiteUrl: data.websiteUrl?.trim() ? data.websiteUrl : null, iconUrl: data.iconUrl?.trim() ? data.iconUrl : null, features: data.features?.map((f) => f.value).filter((v) => v.trim() !== ""), tags: data.tags?.map((t) => t.value).filter((v) => v.trim() !== ""), }; updateTool.mutate( { id, data: payload }, { onSuccess: () => { toast({ title: "Tool updated", description: "Changes saved successfully." }); queryClient.invalidateQueries({ queryKey: getGetToolQueryKey(id) }); queryClient.invalidateQueries({ queryKey: getListToolsQueryKey() }); queryClient.invalidateQueries({ queryKey: getListCategoriesQueryKey() }); queryClient.invalidateQueries({ queryKey: getListAllFeaturesQueryKey() }); queryClient.invalidateQueries({ queryKey: getListAllTagsQueryKey() }); queryClient.invalidateQueries({ queryKey: getGetTopToolsQueryKey() }); queryClient.invalidateQueries({ queryKey: getGetAnalyticsSummaryQueryKey() }); setLocation(`/tools/${id}`); }, onError: (err) => { toast({ title: "Failed to update tool", description: err.data?.error || err.message || "An unexpected error occurred.", variant: "destructive", }); }, }, ); }; if (!match || isNaN(id)) { return null; } return (

Edit Tool

Update tool details and metadata.

{isLoading ? ( ) : ( Tool Details Modify the tool information below.
( Name Name )} /> ( Category Category )} />
( Website URL (Optional) Website URL )} /> ( Icon / Logo URL (Optional) Icon / Logo URL
{field.value ? ( icon preview { (e.target as HTMLImageElement).style.display = "none"; }} /> ) : ( img )}
)} /> ( Description Description