import { zodResolver } from "@hookform/resolvers/zod"; import { t } from "@lingui/core/macro"; import { env } from "next-runtime-env"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { HiCheck, HiXMark } from "react-icons/hi2"; import { z } from "zod"; import Button from "~/components/Button"; import Input from "~/components/Input"; import { useDebounce } from "~/hooks/useDebounce"; import { useModal } from "~/providers/modal"; import { usePopup } from "~/providers/popup"; import { api } from "~/utils/api"; interface QueryParams { boardPublicId: string; members: string[]; labels: string[]; lists: string[]; } export function UpdateBoardSlugForm({ boardPublicId, workspaceSlug, boardSlug, queryParams, }: { boardPublicId: string; workspaceSlug: string; boardSlug: string; queryParams: QueryParams; }) { const { closeModal } = useModal(); const { showPopup } = usePopup(); const utils = api.useUtils(); const schema = z.object({ slug: z .string() .min(3, { message: t`Board URL must be at least 3 characters long`, }) .max(60, { message: t`Board URL cannot exceed 60 characters` }) .regex(/^(?![-]+$)[a-zA-Z0-9-]+$/, { message: t`Board URL can only contain letters, numbers, and hyphens`, }), }); type FormValues = z.infer; const { register, handleSubmit, formState: { isDirty, errors }, watch, } = useForm({ resolver: zodResolver(schema), values: { slug: boardSlug, }, mode: "onChange", }); const slug = watch("slug"); const [debouncedSlug] = useDebounce(slug, 500); const updateBoardSlug = api.board.update.useMutation({ onError: () => { showPopup({ header: t`Unable to update board URL`, message: t`Please try again later, or contact customer support.`, icon: "error", }); }, onSettled: async () => { closeModal(); await utils.board.byId.invalidate(queryParams); }, }); const checkBoardSlugAvailability = api.board.checkSlugAvailability.useQuery( { boardSlug: debouncedSlug, boardPublicId, }, { enabled: !!debouncedSlug && debouncedSlug !== boardSlug && !errors.slug, }, ); const isBoardSlugAvailable = checkBoardSlugAvailability.data; useEffect(() => { const nameElement: HTMLElement | null = document.querySelector("#board-slug"); if (nameElement) nameElement.focus(); }, []); const onSubmit = (data: FormValues) => { if (!isBoardSlugAvailable) return; if (isBoardSlugAvailable.isReserved) return; updateBoardSlug.mutate({ slug: data.slug, boardPublicId, }); }; return (

{t`Edit board URL`}

{ if (e.key === "Enter") { e.preventDefault(); await handleSubmit(onSubmit)(); } }} iconRight={ !!errors.slug?.message || isBoardSlugAvailable?.isReserved ? ( ) : ( ) } />
); }