"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Separator } from "@/components/ui/separator"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { updateProject } from "@/actions/projects"; import { useToast } from "@/components/ui/use-toast"; import { Settings, Building2, Users, Webhook } from "lucide-react"; const settingsSchema = z.object({ name: z.string().min(1, "Name is required").max(100), code: z.string().min(1, "Code is required").max(20).regex(/^[A-Z0-9_\-]+$/i, "Alphanumeric, dash, underscore"), showId: z.string().min(1, "Show ID is required").max(10).regex(/^[A-Z0-9_]+$/i, "Letters, numbers, underscore only"), projectType: z.enum(["STANDARD", "EPISODIC"]), description: z.string().optional(), status: z.enum(["ACTIVE", "ON_HOLD", "COMPLETED", "ARCHIVED"]), clientId: z.string().optional(), producerId: z.string().optional(), supervisorId: z.string().optional(), dueDate: z.string().optional(), startDate: z.string().optional(), slackWebhook: z.string().optional(), slackChannel: z.string().optional(), }); type SettingsFormValues = z.infer; interface Client { id: string; company: string; } interface TeamMember { id: string; name: string | null; email: string; role: string; } interface ProjectSettingsTabProps { project: { id: string; name: string; code: string; showId: string; projectType: "STANDARD" | "EPISODIC"; description: string | null; status: string; clientId: string | null; producerId: string | null; supervisorId: string | null; dueDate: Date | null; startDate: Date | null; slackWebhook: string | null; slackChannel: string | null; }; clients: Client[]; teamMembers: TeamMember[]; } const NONE = "__none__"; function toDateInput(d: Date | null | undefined) { if (!d) return ""; return new Date(d).toISOString().substring(0, 10); } export function ProjectSettingsTab({ project, clients, teamMembers }: ProjectSettingsTabProps) { const { toast } = useToast(); const router = useRouter(); const [isSubmitting, setIsSubmitting] = useState(false); const producers = teamMembers.filter((m) => ["ADMIN", "PRODUCER"].includes(m.role)); const supervisors = teamMembers.filter((m) => ["ADMIN", "PRODUCER", "SUPERVISOR"].includes(m.role)); const { register, handleSubmit, setValue, watch, formState: { errors, isDirty }, } = useForm({ resolver: zodResolver(settingsSchema), defaultValues: { name: project.name, code: project.code, showId: project.showId, projectType: project.projectType, description: project.description ?? "", status: project.status as SettingsFormValues["status"], clientId: project.clientId ?? NONE, producerId: project.producerId ?? NONE, supervisorId: project.supervisorId ?? NONE, dueDate: toDateInput(project.dueDate), startDate: toDateInput(project.startDate), slackWebhook: project.slackWebhook ?? "", slackChannel: project.slackChannel ?? "", }, }); const onSubmit = async (data: SettingsFormValues) => { setIsSubmitting(true); try { await updateProject({ id: project.id, name: data.name, code: data.code, showId: data.showId, projectType: data.projectType, description: data.description || null, status: data.status as any, clientId: data.clientId === NONE ? null : data.clientId || null, producerId: data.producerId === NONE ? null : data.producerId || null, supervisorId: data.supervisorId === NONE ? null : data.supervisorId || null, dueDate: data.dueDate || null, startDate: data.startDate || null, slackWebhook: data.slackWebhook || null, slackChannel: data.slackChannel || null, }); toast({ title: "Project settings saved" }); router.refresh(); } catch (err) { toast({ title: "Failed to save settings", description: (err as Error).message, variant: "destructive", }); } finally { setIsSubmitting(false); } }; return (
{/* ── General ── */}

General

{errors.name &&

{errors.name.message}

}
{errors.code &&

{errors.code.message}

}