import { useLocation } from "wouter"; import { useForm, useFieldArray } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod"; import { useCreateTool, getListToolsQueryKey } 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 { useToast } from "@/hooks/use-toast"; import { Wrench, Plus, X, ArrowLeft, LogIn } from "lucide-react"; import { Link } from "wouter"; import { CategoryCombobox } from "@/components/category-combobox"; import { FeatureInput } from "@/components/feature-input"; import { useAuth } from "@/hooks/use-auth"; 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 ToolNew() { const [location, setLocation] = useLocation(); const { toast } = useToast(); const queryClient = useQueryClient(); const createTool = useCreateTool(); const { isAuthenticated, isLoading: authLoading, login } = useAuth(); const form = useForm({ resolver: zodResolver(toolSchema), defaultValues: { name: "", description: "", category: "", websiteUrl: "", iconUrl: "", features: [{ value: "" }], tags: [{ value: "" }], }, }); 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 || undefined, iconUrl: data.iconUrl || undefined, features: data.features?.map((f) => f.value).filter((v) => v.trim() !== ""), tags: data.tags?.map((t) => t.value).filter((v) => v.trim() !== ""), }; createTool.mutate( { data: payload }, { onSuccess: (newTool) => { toast({ title: "Tool added successfully", description: "Your tool is now available for review." }); queryClient.invalidateQueries({ queryKey: getListToolsQueryKey() }); setLocation(`/tools/${newTool.id}`); }, onError: () => { toast({ title: "Failed to add tool", description: "An unexpected error occurred.", variant: "destructive" }); }, }, ); }; return (

Add a New Tool

Submit a tool you use to let the community rate and review it.

{!authLoading && !isAuthenticated && (

Sign in required

You must be signed in to submit a tool.

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