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.
198 lines
6.4 KiB
198 lines
6.4 KiB
"use client";
|
|
|
|
import type { QuestionField } from "@/lib/schema-adapter";
|
|
import { useQuestionAnswers } from "./question-answer-storage";
|
|
import QuestionTitle from "./question-title";
|
|
|
|
type QuestionCheckboxProps = {
|
|
question: QuestionField;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
export function QuestionCheckbox({
|
|
question,
|
|
disabled,
|
|
}: QuestionCheckboxProps) {
|
|
const options = question.options || [];
|
|
const { getAnswerValue, setAnswerValue } = useQuestionAnswers();
|
|
const rawValue = getAnswerValue(question);
|
|
|
|
const value = Array.isArray(rawValue)
|
|
? rawValue
|
|
: rawValue
|
|
? [String(rawValue)]
|
|
: [];
|
|
|
|
const isSingleCheckbox = options.length === 0;
|
|
|
|
if (isSingleCheckbox) {
|
|
const isChecked = Boolean(
|
|
rawValue === true ||
|
|
rawValue === "true" ||
|
|
rawValue === "confirmed" ||
|
|
(Array.isArray(rawValue) && rawValue.length > 0),
|
|
);
|
|
|
|
const toggleSingle = () => {
|
|
setAnswerValue(question, isChecked ? null : ["confirmed"]);
|
|
};
|
|
|
|
const labelText =
|
|
question.description ||
|
|
question.title ||
|
|
"تأیید میکنم که نام، سن، تصویر و اطلاعات هویتی من با مدارک بارگذاریشده مطابقت دارد.";
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
"flex w-full flex-col gap-3.5 transition-opacity duration-200",
|
|
disabled ? "pointer-events-none opacity-30" : "",
|
|
].join(" ")}
|
|
>
|
|
<QuestionTitle question={question} />
|
|
|
|
<div className="flex flex-col gap-3.5 pt-1">
|
|
<label
|
|
htmlFor={`checkbox-${question.id}`}
|
|
className={[
|
|
"cursor-pointer rounded-[16px] font-semibold text-[15px] transition-all duration-200 active:scale-[0.99] flex items-center gap-3 w-full px-5 py-4 text-start leading-snug",
|
|
isChecked
|
|
? "bg-[#F0445B] text-white shadow-[0_8px_20px_rgba(240,68,91,0.25)]"
|
|
: "bg-[#FAFAFA] text-[#181818] hover:bg-white shadow-[0_2px_6px_rgba(0,0,0,0.03)] border border-[#F0EDED]",
|
|
].join(" ")}
|
|
>
|
|
<input
|
|
type="checkbox"
|
|
id={`checkbox-${question.id}`}
|
|
checked={isChecked}
|
|
disabled={disabled}
|
|
onChange={toggleSingle}
|
|
className="sr-only"
|
|
/>
|
|
<div
|
|
className={[
|
|
"size-[18px] shrink-0 rounded-[5px] border-[2px] transition-all flex items-center justify-center",
|
|
isChecked
|
|
? "border-white bg-white text-[#F0445B]"
|
|
: "border-[#D0D5DD] bg-white text-transparent",
|
|
].join(" ")}
|
|
>
|
|
{isChecked && (
|
|
<svg
|
|
width="10"
|
|
height="8"
|
|
viewBox="0 0 10 8"
|
|
fill="none"
|
|
className="stroke-current stroke-[2]"
|
|
>
|
|
<path
|
|
d="M1 4L3.5 6.5L9 1"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
)}
|
|
</div>
|
|
<span className="flex-1">{labelText}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const toggleOption = (optionId: string) => {
|
|
let nextValue: string[];
|
|
if (value.includes(optionId)) {
|
|
nextValue = value.filter((v) => v !== optionId);
|
|
} else {
|
|
nextValue = [...value, optionId];
|
|
}
|
|
|
|
setAnswerValue(
|
|
question, nextValue.length > 0 ? nextValue : null,
|
|
);
|
|
};
|
|
|
|
// Render horizontally only for 2-option binary choices
|
|
const isShortOptions =
|
|
options.length <= 2 &&
|
|
options.every((opt) => String(opt.label || opt.value || "").length <= 10);
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
"flex w-full flex-col gap-3.5 transition-opacity duration-200",
|
|
disabled ? "pointer-events-none opacity-30" : "",
|
|
].join(" ")}
|
|
>
|
|
<QuestionTitle question={question} />
|
|
|
|
<div
|
|
className={
|
|
isShortOptions
|
|
? "flex flex-row flex-wrap items-center gap-3 pt-1"
|
|
: "flex flex-col gap-3.5 pt-1"
|
|
}
|
|
>
|
|
{options.map((option) => {
|
|
const optionId = `checkbox-${question.id}-${option.id}`;
|
|
const isSelected = value.includes(option.id);
|
|
|
|
return (
|
|
<label
|
|
key={option.id}
|
|
htmlFor={optionId}
|
|
className={[
|
|
"cursor-pointer rounded-[16px] font-semibold text-[15px] transition-all duration-200 active:scale-[0.99] flex items-center gap-3",
|
|
isShortOptions
|
|
? "flex-1 min-w-[90px] px-5 py-3.5 text-center justify-center"
|
|
: "w-full px-5 py-4 text-start leading-snug",
|
|
isSelected
|
|
? "bg-[#F0445B] text-white shadow-[0_8px_20px_rgba(240,68,91,0.25)]"
|
|
: "bg-[#FAFAFA] text-[#181818] hover:bg-white shadow-[0_2px_6px_rgba(0,0,0,0.03)] border border-[#F0EDED]",
|
|
].join(" ")}
|
|
>
|
|
<input
|
|
type="checkbox"
|
|
id={optionId}
|
|
checked={isSelected}
|
|
disabled={disabled}
|
|
onChange={() => toggleOption(option.id)}
|
|
className="sr-only"
|
|
/>
|
|
{!isShortOptions && (
|
|
<div
|
|
className={[
|
|
"size-[18px] shrink-0 rounded-[5px] border-[2px] transition-all flex items-center justify-center",
|
|
isSelected
|
|
? "border-white bg-white text-[#F0445B]"
|
|
: "border-[#D0D5DD] bg-white text-transparent",
|
|
].join(" ")}
|
|
>
|
|
{isSelected && (
|
|
<svg
|
|
width="10"
|
|
height="8"
|
|
viewBox="0 0 10 8"
|
|
fill="none"
|
|
className="stroke-current stroke-[2]"
|
|
>
|
|
<path
|
|
d="M1 4L3.5 6.5L9 1"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
)}
|
|
</div>
|
|
)}
|
|
<span className="flex-1">{option.label || option.value || ""}</span>
|
|
</label>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default QuestionCheckbox;
|