diff --git a/src/app/questions-list/questions-list-client.tsx b/src/app/questions-list/questions-list-client.tsx
index 54013e9..dc7577f 100644
--- a/src/app/questions-list/questions-list-client.tsx
+++ b/src/app/questions-list/questions-list-client.tsx
@@ -104,6 +104,20 @@ export default function QuestionsListClient({
});
const { dictionary: t, locale } = useI18n();
const router = useRouter();
+
+ const handleHeaderBack = useCallback(() => {
+ if (onClose) {
+ onClose();
+ } else if (typeof window !== "undefined" && (window as any).HabibApp) {
+ (window as any).HabibApp.postMessage(
+ JSON.stringify({ action: "close_service" }),
+ );
+ } else if (typeof window !== "undefined" && window.history.length > 1) {
+ router.back();
+ } else {
+ router.replace(localizePath("/intro", locale));
+ }
+ }, [onClose, router, locale]);
const queryClient = useQueryClient();
const { data: profile, isLoading: isProfileLoading, isError: isProfileError, isFetched: isProfileFetched, refetch: refetchProfile } =
useMarriageProfileQuery();
@@ -723,15 +737,7 @@ export default function QuestionsListClient({
iconLabel={t["Close questions list"]}
onClick={(e) => {
e.preventDefault();
- if (onClose) {
- onClose();
- } else if (typeof window !== "undefined" && (window as any).HabibApp) {
- (window as any).HabibApp.postMessage(
- JSON.stringify({ action: "close_service" }),
- );
- } else {
- router.push("/");
- }
+ handleHeaderBack();
}}
/>
@@ -805,13 +811,7 @@ export default function QuestionsListClient({
iconLabel={t["Close questions list"]}
onClick={(e) => {
e.preventDefault();
- if (typeof window !== "undefined" && (window as any).HabibApp) {
- (window as any).HabibApp.postMessage(
- JSON.stringify({ action: "close_service" }),
- );
- } else {
- router.push("/");
- }
+ handleHeaderBack();
}}
/>
@@ -930,15 +930,7 @@ export default function QuestionsListClient({
iconLabel={t["Close questions list"]}
onClick={(e) => {
e.preventDefault();
- if (onClose) {
- onClose();
- } else if (typeof window !== "undefined" && (window as any).HabibApp) {
- (window as any).HabibApp.postMessage(
- JSON.stringify({ action: "close_service" }),
- );
- } else {
- router.push("/");
- }
+ handleHeaderBack();
}}
/>
diff --git a/src/app/terms/page.tsx b/src/app/terms/page.tsx
index f694391..3113c51 100644
--- a/src/app/terms/page.tsx
+++ b/src/app/terms/page.tsx
@@ -8,6 +8,7 @@ import {
hasCompletedMarriageProfileBasics,
} from "@/lib/get-submit-path";
import { useHabibWebReady } from "@/hooks/use-habib-web-ready";
+import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler";
import SliderPage from "@/components/Componentes/slider-page";
import Button from "@/components/Componentes/button";
import { useI18n } from "@/translations/provider";
@@ -18,22 +19,26 @@ export default function TermsRoute() {
const router = useRouter();
const { locale, dictionary: t } = useI18n();
- // Signal Flutter to lift its loading cover immediately on mount
- useHabibWebReady(true);
+ const isBasicsCompleted = Boolean(
+ profile &&
+ (profile.status !== "pending_onboarding" ||
+ hasCompletedMarriageProfileBasics(profile)),
+ );
+
+ // Signal Flutter to lift its loading cover, but only cache /terms if onboarding is required
+ useHabibWebReady(!isLoading && !isBasicsCompleted);
+
+ // At the root /terms screen, hardware back tells Flutter to close the WebView screen
+ useHardwareBackHandler(() => false, !isBasicsCompleted);
useEffect(() => {
- if (!isLoading && profile) {
- if (
- profile.status !== "pending_onboarding" ||
- hasCompletedMarriageProfileBasics(profile)
- ) {
- const target = getSubmitPath(profile);
- if (target !== "/terms") {
- router.replace(localizePath(target, locale));
- }
+ if (!isLoading && profile && isBasicsCompleted) {
+ const target = getSubmitPath(profile);
+ if (target !== "/terms") {
+ router.replace(localizePath(target, locale));
}
}
- }, [profile, isLoading, router, locale]);
+ }, [profile, isLoading, isBasicsCompleted, router, locale]);
if (isLoading) {
return (
diff --git a/src/components/Componentes/question-birthplace.tsx b/src/components/Componentes/question-birthplace.tsx
index 067844c..00bdad5 100644
--- a/src/components/Componentes/question-birthplace.tsx
+++ b/src/components/Componentes/question-birthplace.tsx
@@ -163,6 +163,14 @@ export function QuestionBirthplace({
question.id?.includes("residence") ||
question.id?.includes("living_area") ||
question.id?.includes("location");
+
+ const isCurrentResidenceQuestion = Boolean(
+ question.id === "contact_residence.current_residence_location" ||
+ question.id?.endsWith(".current_residence_location") ||
+ question.id?.endsWith(".current_residence") ||
+ question.ui_config?.read_only_fields === true
+ );
+
const storedRegion = isResidence ? getStoredUserGeoRegion() : null;
const initial = parseValue(rawValue);
@@ -189,6 +197,13 @@ export function QuestionBirthplace({
const initialCity = hasSavedAnswer ? initial.city || "" : "";
+ const fallbackCountry = isResidence
+ ? resolveCountryName(storedRegion?.country, locale) ||
+ storedRegion?.country ||
+ ""
+ : "";
+ const fallbackCity = isResidence ? storedRegion?.city || "" : "";
+
const initialLoc =
localizedInitialCountry || initialCity
? [localizedInitialCountry, initialCity].filter(Boolean).join(", ")
@@ -203,12 +218,14 @@ export function QuestionBirthplace({
: "";
const [selectedCountry, setSelectedCountry] = useState(
- () => localizedInitialCountry || "",
+ () => localizedInitialCountry || fallbackCountry,
);
- const [cityInput, setCityInput] = useState(() => initialCity);
+ const [cityInput, setCityInput] = useState(() => initialCity || fallbackCity);
- const cityInputStateRef = useRef(initialCity);
- const selectedCountryStateRef = useRef(localizedInitialCountry || "");
+ const cityInputStateRef = useRef(initialCity || fallbackCity);
+ const selectedCountryStateRef = useRef(
+ localizedInitialCountry || fallbackCountry,
+ );
const lastCoordsRef = useRef<{ latitude?: number; longitude?: number } | undefined>(
storedRegion?.latitude && storedRegion?.longitude
@@ -642,13 +659,16 @@ export function QuestionBirthplace({
@@ -686,13 +708,19 @@ export function QuestionBirthplace({
ref={cityInputRef}
type="text"
data-no-auto-focus
+ readOnly={isCurrentResidenceQuestion}
disabled={disabled}
value={cityInput}
- onChange={handleCityChange}
- onFocus={handleCityFocus}
- onBlur={handleCityBlur}
+ onChange={isCurrentResidenceQuestion ? undefined : handleCityChange}
+ onFocus={isCurrentResidenceQuestion ? (e) => e.target.blur() : handleCityFocus}
+ onBlur={isCurrentResidenceQuestion ? undefined : handleCityBlur}
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] outline-none transition-all",
+ isCurrentResidenceQuestion
+ ? "cursor-default select-none focus:border-[#D0D5DD] focus:ring-0"
+ : "hover:border-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F]",
+ ].join(" ")}
/>
>
diff --git a/src/components/Componentes/slider-page.tsx b/src/components/Componentes/slider-page.tsx
index 601446e..8e0aadf 100644
--- a/src/components/Componentes/slider-page.tsx
+++ b/src/components/Componentes/slider-page.tsx
@@ -1,10 +1,12 @@
"use client";
import { useRouter } from "next/navigation";
-import { useEffect, useState } from "react";
+import { useCallback, useEffect, useState } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { useUpdateMarriageProfileBasicMutation } from "@/hooks/marriage/use-profile-basic";
+import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler";
import { authBridge } from "@/lib/auth-bridge";
+import { setCachedMarriageEntryPath } from "@/lib/entry-route-cache";
import { isInFlutterWebView } from "@/lib/webview-actions";
import {
getSubmitPath,
@@ -63,9 +65,9 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
setActiveSlide(targetIndex);
};
- const goToPreviousSlide = () => {
- goToSlide(activeSlide - 1);
- };
+ const goToPreviousSlide = useCallback(() => {
+ setActiveSlide((prev) => Math.max(0, prev - 1));
+ }, []);
const goToNextSlide = () => {
if (activeSlide === 0 && !hasReadRules) {
@@ -74,6 +76,47 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
goToSlide(activeSlide + 1);
};
+ const handleBackNavigation = useCallback(() => {
+ if (activeSlide > 0) {
+ goToPreviousSlide();
+ return;
+ }
+ if (typeof window !== "undefined") {
+ try {
+ window.sessionStorage.setItem("skip_intro_redirect", "true");
+ } catch (e) {
+ console.warn("sessionStorage is not accessible:", e);
+ }
+ }
+ if (onClose) {
+ onClose();
+ return;
+ }
+ if (typeof window !== "undefined" && (window as any).HabibApp) {
+ (window as any).HabibApp.postMessage(
+ JSON.stringify({ action: "close_service" }),
+ );
+ return;
+ }
+ if (typeof window !== "undefined" && window.history.length > 1) {
+ router.back();
+ } else {
+ router.replace(localizePath("/intro", locale));
+ }
+ }, [activeSlide, goToPreviousSlide, onClose, router, locale]);
+
+ useHardwareBackHandler(() => {
+ if (activeSlide > 0) {
+ goToPreviousSlide();
+ return true; // Handled: keep WebView open, move to previous slide
+ }
+ if (onClose) {
+ onClose();
+ return true; // Handled: closed the overlay
+ }
+ return false; // Root: tell Flutter to close WebView screen
+ });
+
const completeSlider = async () => {
if (isSubmitting) return;
setIsSubmitting(true);
@@ -116,6 +159,7 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
const targetPath = getSubmitPath(freshProfile);
const localizedTarget = localizePath(targetPath, locale);
+ setCachedMarriageEntryPath(targetPath);
router.prefetch?.(localizedTarget);
router.replace(localizedTarget);
} catch (error: any) {
@@ -147,24 +191,7 @@ export default function SliderPage({ onClose }: SliderPageProps = {}) {
{
- if (activeSlide > 0) {
- goToPreviousSlide();
- return;
- }
- if (typeof window !== "undefined") {
- try {
- window.sessionStorage.setItem("skip_intro_redirect", "true");
- } catch (e) {
- console.warn("sessionStorage is not accessible:", e);
- }
- }
- if (onClose) {
- onClose();
- } else {
- router.back();
- }
- }}
+ onClick={handleBackNavigation}
/>
) : activeSlide === maxSlideIndex ? (
diff --git a/src/components/Componentes/slider-slide-one.tsx b/src/components/Componentes/slider-slide-one.tsx
index 68985a2..0d08f29 100644
--- a/src/components/Componentes/slider-slide-one.tsx
+++ b/src/components/Componentes/slider-slide-one.tsx
@@ -123,14 +123,16 @@ export function SliderSlideOne({ index, totalSteps, onScrollToEnd }: SliderSlide
type SliderSlideOneActionsProps = {
onAccept: () => void;
+ onBack?: () => void;
disabled?: boolean;
};
export function SliderSlideOneActions({
onAccept,
+ onBack,
disabled,
}: SliderSlideOneActionsProps) {
- const { dictionary: t } = useI18n();
+ const { dictionary: t, locale } = useI18n();
const handleBack = () => {
if (typeof window !== "undefined") {
@@ -140,6 +142,17 @@ export function SliderSlideOneActions({
console.warn("sessionStorage is not accessible:", e);
}
}
+ if (onBack) {
+ onBack();
+ } else if (typeof window !== "undefined" && (window as any).HabibApp) {
+ (window as any).HabibApp.postMessage(
+ JSON.stringify({ action: "close_service" }),
+ );
+ } else if (typeof window !== "undefined" && window.history.length > 1) {
+ window.history.back();
+ } else if (typeof window !== "undefined") {
+ window.location.replace(locale === "en" ? "/intro" : `/${locale}/intro`);
+ }
};
return (
@@ -147,7 +160,6 @@ export function SliderSlideOneActions({