"use client"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { FaLock } from "react-icons/fa6"; import AdvisorActionsCard from "@/components/Componentes/advisor-actions-card"; import PageHeader from "@/components/Componentes/page-header"; import { PageBackground } from "@/components/Componentes/page-background"; import { IoClose } from "react-icons/io5"; import { LoadingSkeleton } from "@/components/Componentes/loading-skeleton"; import { LoadingThreeDot } from "@/components/Componentes/loading-three-dot"; import { useHabcoinPaymentMutation } from "@/hooks/marriage/use-habcoin-payment"; import { useRespondToMarriageCaseMutation } from "@/hooks/marriage/use-case-respond"; import type { MarriageField, MarriageFieldValue, MarriageMatchSummary, MarriagePhoneFieldValue, } from "@/hooks/marriage/types"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; import { useViewPaddings } from "@/hooks/use-view-paddings"; import { getSubmitPath } from "@/lib/get-submit-path"; import { buyHabibCoinPackages, isInFlutterWebView, } from "@/lib/webview-actions"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; const advisorAvatars = [ { id: "advisor-primary", src: "/assets/images/Avatar Image.png" }, { id: "advisor-secondary", src: "/assets/images/Ellipse 370.png" }, { id: "advisor-tertiary", src: "/assets/images/Avatar Image.png" }, ]; const fieldCandidates = { name: ["name", "full_name", "fullname", "first_name", "display_name"], occupation: [ "occupation", "job", "profession", "career", "work", "education", "highest_level_of_education", ], age: ["age"], city: [ "city", "current_city", "residence_city", "location", "residence", "birth_city", ], maritalStatus: [ "marital_status", "maritalstatus", "relationship_status", "current_marital_status", ], cityPreference: [ "city_preference", "citypreference", "preferred_city", "preferred_location", "future_residence", ], } as const; type DisplayField = { id: string; label: string; value: string; }; function normalizeFieldName(value: string) { return value .toLowerCase() .replace(/^q\d+[_-]?/, "") .replace(/[^a-z0-9]/g, ""); } function formatFieldValue(value: MarriageFieldValue) { if (value === null || value === "") { return null; } if (isMarriagePhoneFieldValue(value)) { return `+${value.countryCode}${value.phoneNumber}`; } if (typeof value === "boolean") { return value ? "Yes" : "No"; } return String(value); } function isMarriagePhoneFieldValue( value: unknown, ): value is MarriagePhoneFieldValue { if (!value || typeof value !== "object") { return false; } const phoneValue = value as Partial; return ( typeof phoneValue.countryCode === "string" && typeof phoneValue.phoneNumber === "string" ); } function titleFromKey(key: string) { return key .replace(/^q\d+[_-]?/i, "") .replace(/[_-]+/g, " ") .replace(/\s+/g, " ") .trim() .replace(/\b\w/g, (letter) => letter.toUpperCase()); } function toDisplayField(field: MarriageField): DisplayField | null { const value = formatFieldValue(field.value); if (!value) { return null; } return { id: field.key || field.label || value, label: field.label || titleFromKey(field.key), value, }; } function pickField( fields: MarriageField[], candidates: readonly string[], usedIndexes: Set, ) { const candidateSet = new Set(candidates.map(normalizeFieldName)); for (const [fieldIndex, field] of fields.entries()) { if (usedIndexes.has(fieldIndex)) { continue; } const displayField = toDisplayField(field); if ( displayField && [field.key, field.label].some((value) => candidateSet.has(normalizeFieldName(value)), ) ) { usedIndexes.add(fieldIndex); return displayField; } } return null; } function useMatchSummaryDisplay(matchSummary: MarriageMatchSummary | null) { return useMemo(() => { const fields = matchSummary?.public_info ?? []; const usedIndexes = new Set(); const name = pickField(fields, fieldCandidates.name, usedIndexes); const occupation = pickField( fields, fieldCandidates.occupation, usedIndexes, ); const age = pickField(fields, fieldCandidates.age, usedIndexes); const city = pickField(fields, fieldCandidates.city, usedIndexes); const maritalStatus = pickField( fields, fieldCandidates.maritalStatus, usedIndexes, ); const cityPreference = pickField( fields, fieldCandidates.cityPreference, usedIndexes, ); const extraFields = fields .filter((_, index) => !usedIndexes.has(index)) .map(toDisplayField) .filter((field): field is DisplayField => Boolean(field)) .slice(0, 4); return { age, city, cityPreference, extraFields, maritalStatus, name: name?.value ?? (matchSummary?.id ? `Profile #${matchSummary.id}` : null), occupation, }; }, [matchSummary]); } function FieldLine({ field }: { field: DisplayField }) { return (

{field.label}: {field.value}

); } export default function NewMatchClient() { const router = useRouter(); const { dictionary: t, locale } = useI18n(); const { top, bottom } = useViewPaddings(); const { data: profile, isError, isLoading } = useMarriageProfileQuery(); const [isPaymentSheetOpen, setIsPaymentSheetOpen] = useState(false); const [paymentError, setPaymentError] = useState(null); const [isInsufficientCoins, setIsInsufficientCoins] = useState(false); const paymentMutation = useHabcoinPaymentMutation(); const caseId = profile?.active_case?.case_id; const respondMutation = useRespondToMarriageCaseMutation(caseId ?? "", { onSuccess: () => { router.replace(localizePath("/finding-match", locale)); }, }); const handlePayment = async () => { const recommendedPlanId = profile?.recommended_plan?.id; if (!recommendedPlanId) return; try { setPaymentError(null); setIsInsufficientCoins(false); await paymentMutation.mutateAsync(recommendedPlanId); setIsPaymentSheetOpen(false); router.push(localizePath("/new-match/profile", locale)); } catch (err: any) { console.error("Payment failed", err); const msg = err?.response?.data?.error || err?.message || "Payment failed"; const modalT = (t as any).paymentModal || {}; if (msg === "Not enough coins") { setIsInsufficientCoins(true); setPaymentError( modalT.insufficientCoins || "Insufficient coin balance. Please recharge your account.", ); } else { setPaymentError(msg); } } }; const handleDecline = async () => { if (!caseId) return; try { await respondMutation.mutateAsync({ action: "reject" }); } catch (err) { console.error("Decline failed", err); } }; useEffect(() => { if (!profile) { return; } const targetPath = getSubmitPath(profile); if (targetPath !== "/new-match") { router.replace(localizePath(targetPath, locale)); } }, [profile, locale, router]); // Signal Flutter to lift its loading cover once the profile is available. useEffect(() => { if (profile && !isLoading) { window.__announceHabibWebReady?.(); } }, [profile, isLoading]); const isRedirecting = useMemo(() => { if (!profile) return false; return getSubmitPath(profile) !== "/new-match"; }, [profile]); const matchSummary = profile?.match_summary ?? null; const matchDisplay = useMatchSummaryDisplay(matchSummary); if (isLoading || isRedirecting) { return ( <>
{/* Header Section Skeleton */}
{/* Match Card Skeleton */}
{/* Name line */} {/* Subtitle / Details lines */}
{/* Button skeleton */}
{/* Advisor Card Skeleton */}
); } const pairedFields = [matchDisplay.age, matchDisplay.city].filter( (field): field is DisplayField => Boolean(field), ); const isFemaleProfile = profile?.gender === "female"; const matchHeadingTitle = isFemaleProfile ? t["New Marriage Proposal"] : t["YOU HAVE A NEW MATCH!"]; const matchHeadingDescription = isFemaleProfile ? t[ "A suitable match has been found for you. If approved, your profile will be evaluated to proceed with the introduction process." ] : t[ "If you proceed, we will notify the other party, and upon their approval, you can view each other's contact information." ]; const isMale = profile?.gender === "male"; const hasActiveSub = !!profile?.active_subscription; const isMatchAvailable = !!profile?.match_summary; return ( <>

{matchHeadingTitle}

{matchHeadingDescription}

{isLoading ? (
{/* Name line */} {/* Subtitle / Details lines */}
{/* Button skeleton */}
) : (
{isError ? (

Unable to load match summary.

) : matchSummary ? ( <>

Name: {matchDisplay.name}

{matchDisplay.occupation ? ( ) : null} {pairedFields.length ? (

{pairedFields.map((field, index) => ( {index > 0 ? | : null} {field.label}: {field.value} ))}

) : null} {matchDisplay.maritalStatus ? ( ) : null} {matchDisplay.cityPreference ? ( ) : null}
) : (

No match summary is available yet.

)}
)}
{profile?.can_edit_profile === false && (
)} {isPaymentSheetOpen && (

{t["Verification & Subscription Activation"] || "Verification & Subscription Activation"}

{t[ "This payment acts as a verification process for your account and activates a 3-month subscription to receive new case introductions. The cost of this subscription is 50 Habib Coins." ] || "This payment acts as a verification process for your account and activates a 3-month subscription to receive new case introductions. The cost of this subscription is 50 Habib Coins."}

{t["Valid for 3 months"] || "Valid for 3 months"} {t["50 Coins"] || "50 Habib Coins"}

{t[ "Please note that there is no guarantee for a specific number of cases, and the volume of incoming cases is solely subject to profile compatibility with other users." ] || "Please note that there is no guarantee for a specific number of cases, and the volume of incoming cases is solely subject to profile compatibility with other users."}

{paymentError && (
{paymentError}
)} {isInsufficientCoins && isInFlutterWebView() && ( )}
)} ); }