Browse Source

fix(birthplace): update birthplace state and tests

master
mortezaei 3 days ago
parent
commit
175b0199bb
  1. 30
      src/components/Componentes/question-birthplace.tsx
  2. 46
      src/components/Componentes/ui-config.test.tsx

30
src/components/Componentes/question-birthplace.tsx

@ -161,6 +161,8 @@ export function QuestionBirthplace({
const cityInputRef = useRef<HTMLInputElement>(null); const cityInputRef = useRef<HTMLInputElement>(null);
const listRef = useRef<HTMLDivElement>(null); const listRef = useRef<HTMLDivElement>(null);
const isMountedRef = useRef(true); const isMountedRef = useRef(true);
const isFocusedRef = useRef(false);
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
const [mode, setMode] = useState<"auto" | "manual">("auto"); const [mode, setMode] = useState<"auto" | "manual">("auto");
const [isDetecting, setIsDetecting] = useState(false); const [isDetecting, setIsDetecting] = useState(false);
@ -171,6 +173,9 @@ export function QuestionBirthplace({
isMountedRef.current = true; isMountedRef.current = true;
return () => { return () => {
isMountedRef.current = false; isMountedRef.current = false;
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
}; };
}, []); }, []);
@ -301,6 +306,9 @@ export function QuestionBirthplace({
// Synchronize state ONLY if rawValue changes externally (e.g. draft fetch or reset) // Synchronize state ONLY if rawValue changes externally (e.g. draft fetch or reset)
useEffect(() => { useEffect(() => {
if (isFocusedRef.current) {
return;
}
if (rawValue === lastInternalAnswerRef.current) { if (rawValue === lastInternalAnswerRef.current) {
return; return;
} }
@ -357,8 +365,26 @@ export function QuestionBirthplace({
} }
const newCity = e.target.value; const newCity = e.target.value;
setCityInput(newCity); setCityInput(newCity);
updateAnswers(selectedCountry, newCity);
setDetectedLocation([selectedCountry, newCity].filter(Boolean).join(", ")); setDetectedLocation([selectedCountry, newCity].filter(Boolean).join(", "));
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
debounceTimerRef.current = setTimeout(() => {
updateAnswers(selectedCountry, newCity);
}, 250);
};
const handleCityFocus = () => {
isFocusedRef.current = true;
};
const handleCityBlur = () => {
isFocusedRef.current = false;
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
updateAnswers(selectedCountry, cityInput);
}; };
const isRtl = locale === "fa" || locale === "ar" || locale === "ur"; const isRtl = locale === "fa" || locale === "ar" || locale === "ur";
@ -613,6 +639,8 @@ export function QuestionBirthplace({
disabled={disabled} disabled={disabled}
value={cityInput} value={cityInput}
onChange={handleCityChange} onChange={handleCityChange}
onFocus={handleCityFocus}
onBlur={handleCityBlur}
placeholder={cityPlaceholder} placeholder={cityPlaceholder}
className="h-[54px] w-full rounded-[16px] border border-[#D0D5DD] bg-white px-4.5 text-[15px] font-medium text-[#181818] placeholder:text-[#98A2B3] hover:border-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] outline-none transition-all" className="h-[54px] w-full rounded-[16px] border border-[#D0D5DD] bg-white px-4.5 text-[15px] font-medium text-[#181818] placeholder:text-[#98A2B3] hover:border-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] outline-none transition-all"
/> />

46
src/components/Componentes/ui-config.test.tsx

@ -346,6 +346,52 @@ describe("UI Config based behavior", () => {
expect(screen.getByText("فرانسه")).toBeDefined(); expect(screen.getByText("فرانسه")).toBeDefined();
expect((cityInput as HTMLInputElement).value).toBe("برلین مرکزی"); expect((cityInput as HTMLInputElement).value).toBe("برلین مرکزی");
}); });
it("should not duplicate or alter city text when focused and typing continuously", async () => {
const qBirthplace = {
id: "birthplace_typing_test",
title: "محل تولد",
type: "birthplace",
order: 1,
required: true,
isVisible: true,
description: "",
tooltip: "",
extras: { placeHolder: "شهر، منطقه یا محله" },
options: [],
ui_config: {},
} as any;
render(
<QueryClientProvider client={queryClient}>
<QuestionAnswersProvider slug="test-typing" questions={[qBirthplace]}>
<QuestionBirthplace question={qBirthplace} />
</QuestionAnswersProvider>
</QueryClientProvider>,
);
const cityInput = screen.getByPlaceholderText("شهر، منطقه یا محله");
fireEvent.focus(cityInput);
// Simulate character-by-character typing: ت -> ته -> تهر -> تهرا -> تهران
fireEvent.change(cityInput, { target: { value: "ت" } });
expect((cityInput as HTMLInputElement).value).toBe("ت");
fireEvent.change(cityInput, { target: { value: "ته" } });
expect((cityInput as HTMLInputElement).value).toBe("ته");
fireEvent.change(cityInput, { target: { value: "تهر" } });
expect((cityInput as HTMLInputElement).value).toBe("تهر");
fireEvent.change(cityInput, { target: { value: "تهرا" } });
expect((cityInput as HTMLInputElement).value).toBe("تهرا");
fireEvent.change(cityInput, { target: { value: "تهران" } });
expect((cityInput as HTMLInputElement).value).toBe("تهران");
fireEvent.blur(cityInput);
expect((cityInput as HTMLInputElement).value).toBe("تهران");
});
}); });
Loading…
Cancel
Save