import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, FormControl, Input, TextArea } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useUpdateProject } from "@app/hooks/api"; const baseFormSchema = z.object({ name: z.string().min(1, "Required").max(64, "Too long, maximum length is 64 characters"), description: z .string() .trim() .max(256, "Description too long, max length is 256 characters") .optional() }); const formSchemaWithSlug = baseFormSchema.extend({ slug: z .string() .min(1, "Required") .max(64, "Too long, maximum length is 64 characters") .regex( /^[a-z0-9]+(?:[_-][a-z0-9]+)*$/, "Project slug can only contain lowercase letters and numbers, with optional single hyphens (-) or underscores (_) between words. Cannot start or end with a hyphen or underscore." ) }); type BaseFormData = z.infer; type FormDataWithSlug = z.infer; type Props = { showSlugField?: boolean; }; export const ProjectOverviewChangeSection = ({ showSlugField = false }: Props) => { const { currentProject } = useProject(); const { mutateAsync, isPending } = useUpdateProject(); const { handleSubmit, control, reset, watch } = useForm({ resolver: zodResolver(showSlugField ? formSchemaWithSlug : baseFormSchema) }); const currentSlug = showSlugField ? watch("slug") : currentProject?.slug; useEffect(() => { if (currentProject) { reset({ name: currentProject.name, description: currentProject.description ?? "", ...(showSlugField && { slug: currentProject.slug }) }); } }, [currentProject, showSlugField]); const onFormSubmit = async (data: BaseFormData | FormDataWithSlug) => { try { if (!currentProject?.id) return; await mutateAsync({ projectId: currentProject.id, newProjectName: data.name, newProjectDescription: data.description, ...(showSlugField && "slug" in data && { newSlug: data.slug !== currentProject.slug ? data.slug : undefined }) }); createNotification({ text: "Successfully updated project overview", type: "success" }); } catch (err) { console.error(err); createNotification({ text: "Failed to update project overview", type: "error" }); } }; return (

Project Overview

{(isAllowed) => ( ( )} control={control} name="name" /> )}
{showSlugField && (
{(isAllowed) => ( ( )} control={control} name="slug" /> )}
)}
{(isAllowed) => ( (