You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.6 KiB
102 lines
2.6 KiB
"use client";
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
import type { QuestionField } from "@/lib/schema-adapter";
|
|
import { cn } from "@/lib/utils";
|
|
import { useI18n } from "@/translations/provider";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { useQuestionAnswers } from "./question-answer-storage";
|
|
import QuestionTitle from "./question-title";
|
|
|
|
type QuestionTextareaProps = {
|
|
question: QuestionField;
|
|
description?: string;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
export function QuestionTextarea({
|
|
question,
|
|
description,
|
|
disabled,
|
|
}: QuestionTextareaProps) {
|
|
const { dictionary: t } = useI18n();
|
|
const { getAnswerValue, setAnswerValue } = useQuestionAnswers();
|
|
const value = getAnswerValue(question);
|
|
|
|
const [localValue, setLocalValue] = useState(String(value ?? ""));
|
|
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
const isFocusedRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (!isFocusedRef.current) {
|
|
setLocalValue(String(value ?? ""));
|
|
}
|
|
}, [value]);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
if (debounceTimerRef.current) {
|
|
clearTimeout(debounceTimerRef.current);
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
const val = e.target.value;
|
|
setLocalValue(val);
|
|
|
|
if (debounceTimerRef.current) {
|
|
clearTimeout(debounceTimerRef.current);
|
|
}
|
|
|
|
debounceTimerRef.current = setTimeout(() => {
|
|
setAnswerValue(question, val);
|
|
}, 300);
|
|
};
|
|
|
|
const handleFocus = () => {
|
|
isFocusedRef.current = true;
|
|
};
|
|
|
|
const handleBlur = () => {
|
|
isFocusedRef.current = false;
|
|
if (debounceTimerRef.current) {
|
|
clearTimeout(debounceTimerRef.current);
|
|
}
|
|
setAnswerValue(question, localValue);
|
|
};
|
|
|
|
const stringValue = localValue.trim();
|
|
const isAnswered =
|
|
question.required === false ? true : stringValue.length > 0;
|
|
|
|
return (
|
|
<div
|
|
data-question-answered={isAnswered ? "true" : "false"}
|
|
data-question-type="textarea"
|
|
className={cn(
|
|
"flex w-full flex-col gap-2 transition-opacity duration-200",
|
|
disabled && "pointer-events-none opacity-30",
|
|
)}
|
|
>
|
|
<QuestionTitle question={question} />
|
|
<Textarea
|
|
value={localValue}
|
|
onChange={handleChange}
|
|
onFocus={handleFocus}
|
|
onBlur={handleBlur}
|
|
placeholder={question.extras.placeHolder}
|
|
disabled={disabled}
|
|
rows={5}
|
|
className="h-[270px]"
|
|
/>
|
|
{description ? (
|
|
<span className="block group-10 font-semibold text-[#747474]">
|
|
{description}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default QuestionTextarea;
|