|
|
@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
|
import { useCallback, useEffect, useRef, useState } from "react"; |
|
|
import { useCallback, useEffect, useRef, useState } from "react"; |
|
|
import { createPortal } from "react-dom"; |
|
|
import { createPortal } from "react-dom"; |
|
|
import { getCountryList, resolveCountryName, COUNTRIES_EN, COUNTRIES_FA } from "@/data/countries"; |
|
|
|
|
|
|
|
|
import { getCountryList, resolveCountryName, isKnownCountry, COUNTRIES_EN, COUNTRIES_FA } from "@/data/countries"; |
|
|
import type { QuestionField } from "@/lib/schema-adapter"; |
|
|
import type { QuestionField } from "@/lib/schema-adapter"; |
|
|
import { useI18n } from "@/translations/provider"; |
|
|
import { useI18n } from "@/translations/provider"; |
|
|
import { useQuestionAnswers } from "./question-answer-storage"; |
|
|
import { useQuestionAnswers } from "./question-answer-storage"; |
|
|
@ -30,13 +30,15 @@ function parseValue(rawValue: unknown): { country: string; city: string } { |
|
|
if (typeof rawValue === "object" && rawValue !== null) { |
|
|
if (typeof rawValue === "object" && rawValue !== null) { |
|
|
const obj = rawValue as BirthplaceValue; |
|
|
const obj = rawValue as BirthplaceValue; |
|
|
return { |
|
|
return { |
|
|
country: typeof obj.country === "string" ? obj.country : "", |
|
|
|
|
|
city: typeof obj.city === "string" ? obj.city : "", |
|
|
|
|
|
|
|
|
country: typeof obj.country === "string" ? obj.country.trim() : "", |
|
|
|
|
|
city: typeof obj.city === "string" ? obj.city.trim() : "", |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof rawValue === "string") { |
|
|
if (typeof rawValue === "string") { |
|
|
let str = rawValue.trim(); |
|
|
let str = rawValue.trim(); |
|
|
|
|
|
if (!str) return { country: "", city: "" }; |
|
|
|
|
|
|
|
|
// Clean legacy country names with parentheses containing commas
|
|
|
// Clean legacy country names with parentheses containing commas
|
|
|
str = str.replace( |
|
|
str = str.replace( |
|
|
"United Kingdom (UK, England, Wales, Scotland, Northern Ireland)", |
|
|
"United Kingdom (UK, England, Wales, Scotland, Northern Ireland)", |
|
|
@ -63,16 +65,33 @@ function parseValue(rawValue: unknown): { country: string; city: string } { |
|
|
"ایالات متحده آمریکا (US)", |
|
|
"ایالات متحده آمریکا (US)", |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
let parts: string[] = []; |
|
|
if (str.includes(",")) { |
|
|
if (str.includes(",")) { |
|
|
const parts = str.split(",").map((s) => s.trim()); |
|
|
|
|
|
return { city: parts[0] || "", country: parts[1] || "" }; |
|
|
|
|
|
|
|
|
parts = str.split(",").map((s) => s.trim()); |
|
|
|
|
|
} else if (str.includes("،")) { |
|
|
|
|
|
parts = str.split("،").map((s) => s.trim()); |
|
|
|
|
|
} else if (str.includes(" - ")) { |
|
|
|
|
|
parts = str.split(" - ").map((s) => s.trim()); |
|
|
} |
|
|
} |
|
|
if (str.includes(" - ")) { |
|
|
|
|
|
const parts = str.split(" - ").map((s) => s.trim()); |
|
|
|
|
|
return { country: parts[0] || "", city: parts[1] || "" }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parts.length >= 2) { |
|
|
|
|
|
const part0 = parts[0] || ""; |
|
|
|
|
|
const part1 = parts.slice(1).join(", ").trim(); |
|
|
|
|
|
|
|
|
|
|
|
const isPart0Country = isKnownCountry(part0); |
|
|
|
|
|
const isPart1Country = isKnownCountry(part1); |
|
|
|
|
|
|
|
|
|
|
|
if (isPart0Country && !isPart1Country) { |
|
|
|
|
|
return { country: part0, city: part1 }; |
|
|
} |
|
|
} |
|
|
const isCountry = COUNTRIES_EN.includes(str) || COUNTRIES_FA.includes(str); |
|
|
|
|
|
if (isCountry) { |
|
|
|
|
|
|
|
|
if (isPart1Country && !isPart0Country) { |
|
|
|
|
|
return { country: part1, city: part0 }; |
|
|
|
|
|
} |
|
|
|
|
|
// Default standard order: City first, Country second
|
|
|
|
|
|
return { city: part0, country: part1 }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (isKnownCountry(str)) { |
|
|
return { country: str, city: "" }; |
|
|
return { country: str, city: "" }; |
|
|
} |
|
|
} |
|
|
return { country: "", city: str }; |
|
|
return { country: "", city: str }; |
|
|
@ -120,6 +139,7 @@ export function QuestionBirthplace({ |
|
|
const [mode, setMode] = useState<"auto" | "manual">("auto"); |
|
|
const [mode, setMode] = useState<"auto" | "manual">("auto"); |
|
|
const [isDetecting, setIsDetecting] = useState(false); |
|
|
const [isDetecting, setIsDetecting] = useState(false); |
|
|
const [detectedLocation, setDetectedLocation] = useState(initialLoc); |
|
|
const [detectedLocation, setDetectedLocation] = useState(initialLoc); |
|
|
|
|
|
const hasAutoDetectedRef = useRef(false); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
isMountedRef.current = true; |
|
|
isMountedRef.current = true; |
|
|
@ -163,8 +183,12 @@ export function QuestionBirthplace({ |
|
|
}, [isOpen, closeSheet]); |
|
|
}, [isOpen, closeSheet]); |
|
|
|
|
|
|
|
|
const updateAnswers = (country: string, city: string) => { |
|
|
const updateAnswers = (country: string, city: string) => { |
|
|
|
|
|
const cleanCountry = country?.trim() || ""; |
|
|
|
|
|
const cleanCity = city?.trim() || ""; |
|
|
const formatted = |
|
|
const formatted = |
|
|
city && country ? `${city}, ${country}` : city || country || null; |
|
|
|
|
|
|
|
|
cleanCity && cleanCountry |
|
|
|
|
|
? `${cleanCity}, ${cleanCountry}` |
|
|
|
|
|
: cleanCity || cleanCountry || null; |
|
|
setAnswerValue(question, formatted); |
|
|
setAnswerValue(question, formatted); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
@ -176,8 +200,8 @@ export function QuestionBirthplace({ |
|
|
const cName = resolveCountryName(parsed.country, locale); |
|
|
const cName = resolveCountryName(parsed.country, locale); |
|
|
if (cName || parsed.city) { |
|
|
if (cName || parsed.city) { |
|
|
const loc = [parsed.city, cName].filter(Boolean).join(", "); |
|
|
const loc = [parsed.city, cName].filter(Boolean).join(", "); |
|
|
setSelectedCountry(cName); |
|
|
|
|
|
setCityInput(parsed.city); |
|
|
|
|
|
|
|
|
if (cName) setSelectedCountry(cName); |
|
|
|
|
|
if (parsed.city) setCityInput(parsed.city); |
|
|
setDetectedLocation(loc); |
|
|
setDetectedLocation(loc); |
|
|
setMode("auto"); |
|
|
setMode("auto"); |
|
|
return; |
|
|
return; |
|
|
@ -217,7 +241,8 @@ export function QuestionBirthplace({ |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
if (isLoading) return; |
|
|
if (isLoading) return; |
|
|
if (isResidence) { |
|
|
|
|
|
|
|
|
if (isResidence && !hasAutoDetectedRef.current) { |
|
|
|
|
|
hasAutoDetectedRef.current = true; |
|
|
void detectLocation(); |
|
|
void detectLocation(); |
|
|
} |
|
|
} |
|
|
}, [isResidence, isLoading, detectLocation]); |
|
|
}, [isResidence, isLoading, detectLocation]); |
|
|
@ -248,7 +273,7 @@ export function QuestionBirthplace({ |
|
|
if (resolvedC && resolvedC !== selectedCountry) { |
|
|
if (resolvedC && resolvedC !== selectedCountry) { |
|
|
setSelectedCountry(resolvedC); |
|
|
setSelectedCountry(resolvedC); |
|
|
} |
|
|
} |
|
|
if (updated.city.trim() !== cityInput.trim()) { |
|
|
|
|
|
|
|
|
if (updated.city && updated.city.trim() !== cityInput.trim()) { |
|
|
setCityInput(updated.city); |
|
|
setCityInput(updated.city); |
|
|
} |
|
|
} |
|
|
if (resolvedC || updated.city) { |
|
|
if (resolvedC || updated.city) { |
|
|
|