kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 94 lines 2.6 kB view raw
1import { useCallback, useEffect, useRef } from "react"; 2import { useForm } from "react-hook-form"; 3import { useTranslation } from "react-i18next"; 4 5import { Form, FormField } from "@/components/ui/form"; 6import { useUpdateTaskTitle } from "@/hooks/mutations/task/use-update-task-title"; 7import useGetTask from "@/hooks/queries/task/use-get-task"; 8import debounce from "@/lib/debounce"; 9 10type TaskTitleProps = { 11 taskId: string; 12}; 13 14export default function TaskTitle({ taskId }: TaskTitleProps) { 15 const { t } = useTranslation(); 16 const { data: task } = useGetTask(taskId); 17 const { mutateAsync: updateTaskTitle } = useUpdateTaskTitle(); 18 const isInitializedRef = useRef(false); 19 const taskRef = useRef(task); 20 const updateTaskRef = useRef(updateTaskTitle); 21 22 useEffect(() => { 23 taskRef.current = task; 24 updateTaskRef.current = updateTaskTitle; 25 }, [task, updateTaskTitle]); 26 27 // biome-ignore lint/correctness/useExhaustiveDependencies: taskId is not needed here 28 useEffect(() => { 29 isInitializedRef.current = false; 30 }, [taskId]); 31 32 const form = useForm<{ 33 title: string; 34 }>({ 35 values: { 36 title: task?.title || "", 37 }, 38 }); 39 40 useEffect(() => { 41 if (task?.title !== undefined) isInitializedRef.current = true; 42 }, [task?.title]); 43 44 const debouncedUpdate = useCallback( 45 debounce(async (title: string) => { 46 if (!isInitializedRef.current) return; 47 48 const currentTask = taskRef.current; 49 const updateTaskFn = updateTaskRef.current; 50 51 if (!currentTask || !updateTaskFn) return; 52 53 try { 54 await updateTaskFn({ 55 ...currentTask, 56 title, 57 }); 58 } catch (error) { 59 console.error("Failed to update title:", error); 60 } 61 }, 800), 62 [], 63 ); 64 65 const handleTitleChange = useCallback( 66 (value: string) => { 67 if (!isInitializedRef.current) return; 68 69 debouncedUpdate(value); 70 }, 71 [debouncedUpdate], 72 ); 73 74 return ( 75 <Form {...form}> 76 <FormField 77 control={form.control} 78 name="title" 79 render={({ field }) => ( 80 <input 81 {...field} 82 type="text" 83 placeholder={t("tasks:detail.titlePlaceholder")} 84 className="block h-auto w-full appearance-none border-0 bg-transparent p-0 font-heading text-[2rem] leading-[1.15] font-semibold tracking-[-0.02em] text-foreground outline-none placeholder:text-foreground/45" 85 onChange={(e) => { 86 field.onChange(e); 87 handleTitleChange(e.target.value); 88 }} 89 /> 90 )} 91 /> 92 </Form> 93 ); 94}