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.
 
 
 
 
 

197 lines
5.8 KiB

"use client";
import { useMemo, useState } from "react";
import type { QuestionField } from "@/lib/schema-adapter";
import { useI18n } from "@/translations/provider";
import { useQuestionAnswers } from "./question-answer-storage";
import QuestionDateSheet from "./question-date-sheet";
import QuestionTitle from "./question-title";
type QuestionDateProps = {
question: QuestionField;
disabled?: boolean;
};
const MIN_AGE = 18;
function parseDateParts(dateValue: string): {
year: string;
month: string;
day: string;
} {
const parts = dateValue ? dateValue.split("-") : [];
return {
year: parts[0] || "",
month: parts[1] || "",
day: parts[2] || "",
};
}
export function QuestionDate({ question, disabled }: QuestionDateProps) {
const { dictionary: t, locale } = useI18n();
const { getAnswerValue, setAnswerValue } = useQuestionAnswers();
const value = getAnswerValue(question);
const dateValue = typeof value === "string" ? value : "";
const { year, month, day } = parseDateParts(dateValue);
const [isOpen, setIsOpen] = useState(false);
const calculatedAge = useMemo(() => {
if (!year || !month || !day) return null;
const y = Number.parseInt(year, 10);
const m = Number.parseInt(month, 10);
const d = Number.parseInt(day, 10);
if (
!y ||
!m ||
!d ||
Number.isNaN(y) ||
Number.isNaN(m) ||
Number.isNaN(d)
) {
return null;
}
const today = new Date();
const cYear = today.getFullYear();
const cMonth = today.getMonth() + 1;
const cDay = today.getDate();
let age = cYear - y;
if (cMonth < m || (cMonth === m && cDay < d)) {
age -= 1;
}
return age >= 0 ? age : null;
}, [year, month, day]);
const isUnder18 = calculatedAge !== null && calculatedAge < MIN_AGE;
const displayDate = useMemo(() => {
if (!year || !month || !day) return "";
const date = new Date(
Number.parseInt(year, 10),
Number.parseInt(month, 10) - 1,
Number.parseInt(day, 10),
);
return new Intl.DateTimeFormat(`${locale}-u-ca-gregory`, {
day: "numeric",
month: "long",
year: "numeric",
}).format(date);
}, [year, month, day, locale]);
const openSheet = () => {
if (disabled) return;
setIsOpen(true);
};
const handleApply = (formattedDate: string) => {
setAnswerValue(question, formattedDate);
};
const placeholder =
t["Select date"] || (locale === "fa" ? "انتخاب تاریخ" : "Select date");
return (
<div
className={[
"flex w-full flex-col gap-2.5 transition-opacity duration-200",
disabled ? "pointer-events-none opacity-30" : "",
].join(" ")}
>
<QuestionTitle question={question} />
{/* Date Trigger Field (single input, like the Flutter app's DOB field) */}
<button
type="button"
disabled={disabled}
onClick={openSheet}
aria-haspopup="dialog"
className={[
"flex h-[54px] w-full cursor-pointer items-center gap-2.5 rounded-[16px] border bg-white px-4 text-start transition-all outline-none",
isOpen
? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]"
: "border-[#D0D5DD] hover:border-[#98A2B3]",
].join(" ")}
>
<svg
aria-hidden="true"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
className="shrink-0 text-[#667085]"
>
<path
d="M15.5 3H14V2.25C14 1.836 13.664 1.5 13.25 1.5C12.836 1.5 12.5 1.836 12.5 2.25V3H7.5V2.25C7.5 1.836 7.166 1.5 6.75 1.5C6.336 1.5 6 1.836 6 2.25V3H4.5C3.671 3 3 3.671 3 4.5V15.5C3 16.329 3.671 17 4.5 17H15.5C16.329 17 17 16.329 17 15.5V4.5C17 3.671 16.329 3 15.5 3ZM15.5 15.5H4.5V7H15.5V15.5Z"
fill="currentColor"
/>
</svg>
<span
className={[
"flex-1 truncate text-[15px] font-medium",
displayDate ? "text-[#181818]" : "text-[#667085]",
].join(" ")}
>
{displayDate || placeholder}
</span>
<svg
aria-hidden="true"
width="16"
height="10"
viewBox="0 0 16 10"
fill="none"
className="shrink-0 transition-transform duration-200"
>
<path
d="M14.75 1.25L7.75 8.25L0.75 1.25"
stroke="#344054"
strokeWidth="1.75"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
{calculatedAge !== null ? (
<div className="mt-2.5 flex w-full flex-col gap-2">
<span className="group-14 block leading-tight font-semibold text-[#181818]">
{t.Age || (locale === "fa" ? "سن" : "Age")}
</span>
<input
type="text"
disabled
readOnly
value={calculatedAge}
className={[
"h-[54px] w-full cursor-not-allowed rounded-[16px] border px-4.5 text-[15px] font-medium outline-none disabled:bg-[#F5F2F1] disabled:text-[#7C7472]",
isUnder18
? "border-[#F2465F] text-[#F2465F] ring-1 ring-[#F2465F]"
: "border-[#D0D5DD] text-[#7C7472]",
].join(" ")}
/>
{isUnder18 ? (
<span className="block text-[11px] font-semibold text-[#F2465F]">
{locale === "fa"
? "حداقل سن برای ثبت‌نام ۱۸ سال می‌باشد."
: "Minimum age required for registration is 18 years."}
</span>
) : null}
</div>
) : null}
{isOpen && (
<QuestionDateSheet
question={question}
value={dateValue}
onApply={handleApply}
onClose={() => setIsOpen(false)}
/>
)}
</div>
);
}
export default QuestionDate;