"use client"; import { useEffect, useMemo, useState } from "react"; import type { QuestionField } from "@/lib/schema-adapter"; import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; import { Input } from "@/components/ui/input"; import { isKnownCountry } from "@/data/countries"; import { resolveDefaultCurrency } from "@/data/currencies"; import { getStoredUserGeoRegion } from "@/lib/geo-region"; import { CurrencySheet } from "./currency-sheet"; type QuestionNumberProps = { question: QuestionField; disabled?: boolean; derivedFromQuestion?: QuestionField; derivedFromQuestionIndex?: number; }; const PERSIAN_DIGITS = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"]; const ARABIC_DIGITS = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]; export function normalizeNumberString(val: string): string { if (!val) return ""; let result = ""; for (let i = 0; i < val.length; i++) { const char = val[i]; const pIdx = PERSIAN_DIGITS.indexOf(char); if (pIdx !== -1) { result += String(pIdx); continue; } const aIdx = ARABIC_DIGITS.indexOf(char); if (aIdx !== -1) { result += String(aIdx); continue; } if (char === "٫") { result += "."; continue; } result += char; } return result; } const NUMBER_INPUT_PATTERN = /^-?\d*\.?\d*$/; export default function QuestionNumber({ question, disabled, derivedFromQuestion, derivedFromQuestionIndex, }: QuestionNumberProps) { const { dictionary: t, locale } = useI18n(); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const value = getAnswerValue(question); const derivedValue = derivedFromQuestion && derivedFromQuestionIndex !== undefined ? getAnswerValue(derivedFromQuestion) : null; useEffect(() => { if (derivedFromQuestion && typeof derivedValue === "string") { const age = calculateAge(derivedValue); if (age !== String(value)) { setAnswerValue(question, age); } } }, [ derivedFromQuestion, derivedValue, question, setAnswerValue, value, ]); useEffect(() => { if (typeof value === "string" && value.length > 0) { const normalized = normalizeNumberString(value); console.log( `[NUM_LOG] useEffect normalize: id=${question.id}, value="${value}", normalized="${normalized}"`, ); if (!NUMBER_INPUT_PATTERN.test(normalized)) { console.log( `[NUM_LOG] useEffect clearing invalid value: id=${question.id}, value="${value}"`, ); setAnswerValue(question, null); } else if (normalized !== value) { const parsed = parseFloat(normalized); console.log( `[NUM_LOG] useEffect updating normalized: id=${question.id}, parsed=${parsed}`, ); setAnswerValue( question, Number.isNaN(parsed) ? normalized : parsed, ); } } }, [question, setAnswerValue, value]); const [min, max] = question.extras.range; const numValue = typeof value === "number" ? value : typeof value === "string" ? parseFloat(normalizeNumberString(value)) : NaN; const isOutOfRange = useMemo(() => { if (Number.isNaN(numValue)) return false; if (min !== 0 && numValue < min) return true; if (max !== 0 && numValue > max) return true; return false; }, [numValue, min, max]); const rawInputValue = value == null ? "" : String(value); const normalizedRaw = normalizeNumberString(rawInputValue); const inputValue = NUMBER_INPUT_PATTERN.test(normalizedRaw) ? normalizedRaw : ""; console.log( `[NUM_LOG] Render: id=${question.id}, value=${JSON.stringify(value)}, inputValue="${inputValue}", isOutOfRange=${isOutOfRange}`, ); const isMonthlyIncome = question.ui_config?.currency_enabled === true; const currencyStorageKey = question.ui_config?.currency_storage_key || "marriage:income:currency"; const countryName = useMemo(() => getCountryFromStorage(), []); const [currencyCode, setCurrencyCode] = useState(() => { if (typeof window !== "undefined") { const stored = window.localStorage.getItem(currencyStorageKey); if (stored) return stored; } const geo = getStoredUserGeoRegion(); return resolveDefaultCurrency({ countryCode: geo?.countryCode, countryName: countryName || geo?.country, fallbackLocale: locale, }); }); const [isCurrencySheetOpen, setIsCurrencySheetOpen] = useState(false); useEffect(() => { if (typeof window !== "undefined") { const stored = window.localStorage.getItem(currencyStorageKey); if (stored) { setCurrencyCode(stored); return; } } const geo = getStoredUserGeoRegion(); const derived = resolveDefaultCurrency({ countryCode: geo?.countryCode, countryName: countryName || geo?.country, fallbackLocale: locale, }); setCurrencyCode(derived); }, [countryName, currencyStorageKey, locale]); const placeholderCurrency = useMemo(() => { if (currencyCode === "TOMAN") { return locale === "fa" || locale === "fa-ir" ? "تومان" : "TOMAN"; } return currencyCode; }, [currencyCode, locale]); const dynamicPlaceholder = useMemo(() => { if (!isMonthlyIncome) { return question.extras.placeHolder; } return locale === "fa" || locale === "fa-ir" ? `مثال: ۴۰۰۰ ${placeholderCurrency}` : `e.g. 4000 ${placeholderCurrency}`; }, [ isMonthlyIncome, question.extras.placeHolder, placeholderCurrency, locale, ]); const [localTextValue, setLocalTextValue] = useState(() => formatNumberWithCommas(inputValue), ); useEffect(() => { const formatted = formatNumberWithCommas( value == null ? "" : String(value), ); const cleanLocal = localTextValue.replace(/,/g, ""); const cleanFormatted = formatted.replace(/,/g, ""); if (cleanFormatted !== cleanLocal) { setLocalTextValue(formatted); } }, [value, localTextValue]); if (isMonthlyIncome) { return (