From ce49189a3b4f11066ec1de411960c0139149d9d4 Mon Sep 17 00:00:00 2001 From: mortezaei Date: Mon, 17 Aug 2026 18:54:32 +0330 Subject: [PATCH] fix: improve date string validation, parsing, and formatting logic in date components --- .../Componentes/question-date-sheet.tsx | 19 ++++-- src/components/Componentes/question-date.tsx | 66 +++++++++++++++---- 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/components/Componentes/question-date-sheet.tsx b/src/components/Componentes/question-date-sheet.tsx index b07c62f..1fd0854 100644 --- a/src/components/Componentes/question-date-sheet.tsx +++ b/src/components/Componentes/question-date-sheet.tsx @@ -156,12 +156,23 @@ export function QuestionDateSheet({ const { dictionary: t, locale } = useI18n(); const [isClosing, setIsClosing] = useState(false); - const parts = value ? value.split("-") : []; - const [selectedYear, setSelectedYear] = useState(parts[0] || YEARS[0]); + const parts = + value && typeof value === "string" ? value.trim().split("-") : []; + const rawYear = parts.length === 3 ? parts[0] : ""; + const rawMonth = parts.length === 3 ? parts[1]?.padStart(2, "0") : ""; + const rawDay = parts.length === 3 ? parts[2]?.padStart(2, "0") : ""; + + const [selectedYear, setSelectedYear] = useState( + rawYear && YEARS.includes(rawYear) ? rawYear : YEARS[0], + ); const [selectedMonth, setSelectedMonth] = useState( - parts[1] || MONTH_VALUES[0], + rawMonth && MONTH_VALUES.includes(rawMonth) ? rawMonth : MONTH_VALUES[0], + ); + const [selectedDay, setSelectedDay] = useState( + rawDay && Number.parseInt(rawDay, 10) >= 1 && Number.parseInt(rawDay, 10) <= 31 + ? rawDay + : "01", ); - const [selectedDay, setSelectedDay] = useState(parts[2] || "01"); const dirtyRef = useRef(false); const closeSheet = useCallback(() => { diff --git a/src/components/Componentes/question-date.tsx b/src/components/Componentes/question-date.tsx index ca4af7d..8e9c1b8 100644 --- a/src/components/Componentes/question-date.tsx +++ b/src/components/Componentes/question-date.tsx @@ -19,11 +19,33 @@ function parseDateParts(dateValue: string): { month: string; day: string; } { - const parts = dateValue ? dateValue.split("-") : []; + if (typeof dateValue !== "string") { + return { year: "", month: "", day: "" }; + } + const parts = dateValue.trim().split("-"); + if (parts.length !== 3) { + return { year: "", month: "", day: "" }; + } + const [y, m, d] = parts; + const yearNum = Number.parseInt(y, 10); + const monthNum = Number.parseInt(m, 10); + const dayNum = Number.parseInt(d, 10); + if ( + Number.isNaN(yearNum) || + Number.isNaN(monthNum) || + Number.isNaN(dayNum) || + yearNum <= 0 || + monthNum < 1 || + monthNum > 12 || + dayNum < 1 || + dayNum > 31 + ) { + return { year: "", month: "", day: "" }; + } return { - year: parts[0] || "", - month: parts[1] || "", - day: parts[2] || "", + year: y, + month: m.padStart(2, "0"), + day: d.padStart(2, "0"), }; } @@ -70,16 +92,32 @@ export function QuestionDate({ question, disabled }: QuestionDateProps) { 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); + 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 ""; + } + const date = new Date(y, m - 1, d); + if (Number.isNaN(date.getTime()) || !Number.isFinite(date.getTime())) { + return ""; + } + try { + return new Intl.DateTimeFormat(`${locale}-u-ca-gregory`, { + day: "numeric", + month: "long", + year: "numeric", + }).format(date); + } catch { + return ""; + } }, [year, month, day, locale]); const openSheet = () => {