import { Option } from "@prisma/client"; import clsx from "clsx"; import * as React from "react"; import { Controller, useForm } from "react-hook-form"; import { requiredString } from "../../utils/form-validation"; import Button from "../button"; import CheckCircle from "../icons/check-circle.svg"; import NameInput from "../name-input"; import { ControlledScrollDiv } from "./poll"; import { usePollContext } from "./poll-context"; import { ParticipantForm } from "./types"; export interface ParticipantRowFormProps { defaultValues?: Partial; onSubmit: (data: ParticipantForm) => Promise; className?: string; options: Option[]; onCancel?: () => void; } const ParticipantRowForm: React.VoidFunctionComponent = ({ defaultValues, onSubmit, className, options, onCancel }) => { const { setActiveOptionId, activeOptionId, columnWidth, scrollPosition, sidebarWidth, numberOfColumns, goToNextPage, setScrollPosition, } = usePollContext(); const { handleSubmit, register, control, formState: { errors, submitCount, isSubmitting }, reset, } = useForm({ defaultValues: { name: "", votes: [], ...defaultValues }, }); const isColumnVisible = (index: number) => { return ( scrollPosition + numberOfColumns * columnWidth > columnWidth * index ); }; const checkboxRefs = React.useRef([]); const isAnimatingRef = React.useRef(false); // This hack is necessary because when there is only one checkbox, // react-hook-form does not know to format the value into an array. // See: https://github.com/react-hook-form/react-hook-form/issues/7834 const checkboxProps = register("votes", { onBlur: () => setActiveOptionId(null), }); const checkboxGroupHack = ( ); return (
{ await onSubmit({ name, // if there is only one checkbox then we get a string rather than array // See this issue with using dot notation: https://github.com/react-hook-form/react-hook-form/issues/7834 votes: Array.isArray(votes) ? votes : [votes], }); reset(); })} className={clsx("flex shrink-0 h-14", className)} > {checkboxGroupHack}
(
0, })} placeholder="Your name" {...field} onKeyDown={(e) => { if (e.code === "Tab" && scrollPosition > 0) { e.preventDefault(); setScrollPosition(0); setTimeout(() => { checkboxRefs.current[0].focus(); }, 800); } }} />
)} control={control} />
{options.map((option, index) => { return (
setActiveOptionId(option.id)} onMouseOut={() => setActiveOptionId(null)} > { if (isAnimatingRef.current) { return e.preventDefault(); } if ( e.code === "Tab" && index < options.length - 1 && !isColumnVisible(index + 1) ) { isAnimatingRef.current = true; e.preventDefault(); goToNextPage(); setTimeout(() => { checkboxRefs.current[index + 1].focus(); isAnimatingRef.current = false; }, 500); } }} {...checkboxProps} ref={(el) => { if (el) { checkboxRefs.current[index] = el; checkboxProps.ref(el); } }} onFocus={() => { setActiveOptionId(option.id); }} />
); })}
); }; export default ParticipantRowForm;