You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

881 lines
33 KiB

"use client";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useEffect, useMemo, useState } from "react";
import { useHabibWebReady } from "@/hooks/use-habib-web-ready";
import AdvisorActionsCard from "@/components/Componentes/advisor-actions-card";
import MarriageAdvisorsOverlay, {
useMarriageAdvisorsOverlay,
} from "@/components/Componentes/marriage-advisors-overlay";
import ErrorToast from "@/components/Componentes/error-toast";
import MatchProfileOverlay, {
useMatchProfileOverlay,
} from "@/components/Componentes/match-profile-overlay";
import CallResultSheet from "@/components/Componentes/call-result-sheet";
import DismissReasonSheet from "@/components/Componentes/dismiss-reason-sheet";
import FemaleConsentSheet from "@/components/Componentes/female-consent-sheet";
import FemaleOutcomeSheet from "@/components/Componentes/female-outcome-sheet";
import { LoadingThreeDot } from "@/components/Componentes/loading-three-dot";
import OutcomeSelectionSheet from "@/components/Componentes/outcome-selection-sheet";
import { PageBackground } from "@/components/Componentes/page-background";
import PageHeader from "@/components/Componentes/page-header";
import SubscriptionRequiredSheet from "@/components/Componentes/subscription-required-sheet";
import SwipeButton from "@/components/Componentes/swipe-button";
import type {
MarriageField,
MarriagePhoneFieldValue,
} from "@/hooks/marriage/types";
import { useMarriageContactInfoQuery } from "@/hooks/marriage/use-contact-info";
import {
useSubmitMarriageContactStatusMutation,
useSubmitMarriageOutcomeMutation,
} from "@/hooks/marriage/use-contact-status";
import {
extractHabcoinPaymentUrl,
useHabcoinPaymentMutation,
} from "@/hooks/marriage/use-habcoin-payment";
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
import { getSubmitPath } from "@/lib/get-submit-path";
import { copyToClipboard } from "@/lib/webview-actions";
import { Ic } from "@/icons";
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/Avatar Image.png" },
{ id: "advisor-tertiary", src: "/assets/images/Avatar Image.png" },
];
type ContactInfoPhoneItem = {
key: string;
label: string;
phoneNumber: string;
};
function sanitizePhoneNumber(value: MarriageField["value"]) {
if (value === null || value === "") {
return null;
}
if (isMarriagePhoneFieldValue(value)) {
const digits = value.phoneNumber.replace(/\D/g, "");
return digits ? `+${value.countryCode}${digits}` : null;
}
const trimmedValue = String(value).trim();
if (!trimmedValue) {
return null;
}
const digits = trimmedValue.replace(/\D/g, "");
if (!digits) {
return null;
}
return trimmedValue.startsWith("+") ? `+${digits}` : digits;
}
function isMarriagePhoneFieldValue(
value: unknown,
): value is MarriagePhoneFieldValue {
if (!value || typeof value !== "object") {
return false;
}
const phoneValue = value as Partial<MarriagePhoneFieldValue>;
return (
typeof phoneValue.countryCode === "string" &&
typeof phoneValue.phoneNumber === "string"
);
}
function getContactInfoPhoneItems(
contactInfoFields: any[] | null | undefined,
): ContactInfoPhoneItem[] {
if (!contactInfoFields || !Array.isArray(contactInfoFields)) {
return [];
}
// Look for contextual representative info if available
const repNameField = contactInfoFields.find(
(f) =>
typeof f?.key === "string" &&
f.key.toLowerCase().includes("representative_s_full_name") &&
f.value,
);
const repRelationField = contactInfoFields.find(
(f) =>
typeof f?.key === "string" &&
f.key.toLowerCase().includes("relationship_to_representative") &&
f.value,
);
const repName = repNameField?.value ? String(repNameField.value).trim() : "";
const repRelation = repRelationField?.value
? String(repRelationField.value).trim()
: "";
return contactInfoFields
.map((field) => {
if (!field) return null;
// Extract phone number from field properties
let phoneNumber: string | null = null;
if (field.phone_number && typeof field.phone_number === "string") {
phoneNumber = field.phone_number.trim();
} else if (field.raw_number && typeof field.raw_number === "string") {
const countryCode = field.country_code
? String(field.country_code).replace(/\D/g, "")
: "98";
phoneNumber = `+${countryCode} ${field.raw_number.trim()}`;
} else if (field.raw_value && typeof field.raw_value === "object") {
phoneNumber = sanitizePhoneNumber(field.raw_value);
} else if (field.value) {
phoneNumber = sanitizePhoneNumber(field.value);
}
// If this field is not a phone field, skip it
if (
!phoneNumber ||
(field.type &&
field.type !== "phone" &&
!field.phone_number &&
!field.raw_number)
) {
return null;
}
const key = String(field.key || "");
const rawLabel = String(field.label || field.key || "");
let label = rawLabel
.replace(/\s+with\s+Country\s+Code/gi, "")
.replace(/\s+با\s+کد\s+کشور/g, "")
.trim();
// Add representative context to label if applicable
if (key.includes("representative")) {
const contextParts = [repRelation, repName].filter(Boolean);
if (contextParts.length > 0 && !label.includes(contextParts[0])) {
label = `${label} (${contextParts.join(" - ")})`;
}
}
return {
key: key || phoneNumber,
label,
phoneNumber,
};
})
.filter((item): item is ContactInfoPhoneItem => item !== null);
}
function ContactInfoPhoneCard({ item }: { item: ContactInfoPhoneItem }) {
const [isCopied, setIsCopied] = useState(false);
const handleCopy = async () => {
try {
await copyToClipboard(item.phoneNumber, item.label);
setIsCopied(true);
setTimeout(() => {
setIsCopied(false);
}, 1500);
} catch (err) {
console.error("Error copying contact to clipboard", err);
}
};
return (
<div className="flex items-center justify-between rounded-[20px] bg-[#FFF5F6] border border-[#FFE4E8] px-5 py-4 shadow-sm transition-all hover:border-[#FFD0D8]">
<div className="text-start min-w-0 flex-1 pe-3">
<p className="text-[19px] font-black text-[#1F2937] tracking-wider dir-ltr text-start select-all leading-tight">
{item.phoneNumber}
</p>
<p className="mt-1 text-[13px] font-semibold text-[#F0445B] text-start truncate leading-snug">
{item.label}
</p>
</div>
<button
type="button"
onClick={handleCopy}
title="Copy"
aria-label="Copy phone number"
className="size-[44px] rounded-[14px] bg-[linear-gradient(180deg,#F0445B_0%,#F54B64_100%)] text-white flex items-center justify-center shrink-0 shadow-[0_4px_12px_rgba(240,68,91,0.25)] active:scale-[0.90] transition-all duration-150 cursor-pointer hover:opacity-95"
>
{isCopied ? (
<Ic name="check" className="size-5 text-white transition-transform scale-110" />
) : (
<Ic name="copy" className="size-5 text-white" />
)}
</button>
</div>
);
}
export default function RequestAcceptedClient() {
const { dictionary: t, locale } = useI18n();
const router = useRouter();
const { isAdvisorOpen, openAdvisors, closeAdvisors } =
useMarriageAdvisorsOverlay();
const { isProfileOpen, openProfile, closeProfile } =
useMatchProfileOverlay();
const [isCallResultSheetOpen, setIsCallResultSheetOpen] = useState(false);
const [isDismissReasonSheetOpen, setIsDismissReasonSheetOpen] =
useState(false);
const [isContactInfoSheetOpen, setIsContactInfoSheetOpen] = useState(false);
const [isSubscriptionSheetOpen, setIsSubscriptionSheetOpen] = useState(false);
const [paymentError, setPaymentError] = useState<string | null>(null);
const [isInsufficientCoins, setIsInsufficientCoins] = useState(false);
const [isOutcomeSheetOpen, setIsOutcomeSheetOpen] = useState(false);
const [isNoContactConfirmOpen, setIsNoContactConfirmOpen] = useState(false);
const [isContactReceivedConfirmOpen, setIsContactReceivedConfirmOpen] =
useState(false);
const [noContactReportedSuccess, setNoContactReportedSuccess] =
useState(false);
const [hasConfirmedFemaleContact, setHasConfirmedFemaleContact] =
useState(false);
const [showPaymentSuccessToast, setShowPaymentSuccessToast] = useState(false);
const [isOpeningProfile, setIsOpeningProfile] = useState(false);
const {
data: profile,
isLoading,
isFetched,
isFetching,
refetch: refetchProfile,
} = useMarriageProfileQuery();
const isFemaleProfile = profile?.gender === "female";
const contactSharedAtStr = profile?.active_case?.contact_shared_at;
useEffect(() => {
if (!profile || !isFetched || noContactReportedSuccess) {
return;
}
const targetPath = getSubmitPath(profile);
if (targetPath !== "/request-accepted") {
router.replace(localizePath(targetPath, locale));
}
}, [profile, isFetched, router, locale, noContactReportedSuccess]);
// Signal Flutter to lift its loading cover immediately on mount
useHabibWebReady(true);
const handleOpenProfile = async () => {
if (!isFetched || isFetching) {
setIsOpeningProfile(true);
try {
await refetchProfile();
} finally {
setIsOpeningProfile(false);
openProfile();
}
return;
}
openProfile();
};
const isRedirecting = useMemo(() => {
if (!profile) return false;
return getSubmitPath(profile) !== "/request-accepted";
}, [profile]);
const caseId = profile?.active_case?.case_id;
const caseStatus = profile?.active_case?.status;
const isFemaleContactConfirmed =
isFemaleProfile &&
(caseStatus === "contacted" || hasConfirmedFemaleContact);
const recommendedPlanId = profile?.recommended_plan?.id;
const paymentMutation = useHabcoinPaymentMutation();
const outcomeMutation = useSubmitMarriageOutcomeMutation(caseId ?? "");
const contactStatusMutation = useSubmitMarriageContactStatusMutation(
caseId ?? "",
{
onSuccess: (_data, variables) => {
if (variables?.action === "no_contact") {
setNoContactReportedSuccess(true);
} else {
if (!isFemaleProfile) {
router.push(localizePath("/finding-match", locale));
}
}
},
},
);
const [isFetchingContact, setIsFetchingContact] = useState(false);
const isMalePaymentDone =
!isFemaleProfile &&
(caseStatus === "payment_done" || caseStatus === "contacted");
const contactInfoQuery = useMarriageContactInfoQuery(caseId, {
enabled: false,
});
const titleText = isFemaleProfile
? t["Request Approved"]
: caseStatus === "payment_done" || caseStatus === "contacted"
? t["Contact info released"]
: t["Request approved!"];
const primaryActionText = isFemaleProfile
? t["No Contact"] || t["No Contact Received"] || "No Contact"
: t["View profile"];
const secondaryActionText = isFemaleProfile
? t["Contact Received"]
: caseStatus === "payment_done" || caseStatus === "contacted"
? t["Contact"]
: t["Pay and get contact"];
const contactInfoPhoneItems = getContactInfoPhoneItems(
contactInfoQuery.data?.contact_info,
);
const handlePrimaryAction = () => {
if (isFemaleProfile) {
setIsDismissReasonSheetOpen(true);
} else {
openProfile();
}
};
const handleSecondaryAction = async () => {
if (isFemaleProfile) {
setIsContactReceivedConfirmOpen(true);
return;
}
if (caseStatus === "female_accepted" || caseStatus === "payment_pending") {
setIsSubscriptionSheetOpen(true);
return;
}
if (caseStatus === "payment_done" || caseStatus === "contacted") {
if (!caseId) {
return;
}
if (!contactInfoQuery.data) {
try {
setIsFetchingContact(true);
await contactInfoQuery.refetch();
} finally {
setIsFetchingContact(false);
}
}
setIsContactInfoSheetOpen(true);
}
};
const handlePayment = async () => {
const planId = recommendedPlanId ?? 1;
if (paymentMutation.isPending) {
return;
}
try {
setPaymentError(null);
setIsInsufficientCoins(false);
const paymentResponse =
await paymentMutation.mutateAsync(planId);
const paymentUrl = extractHabcoinPaymentUrl(paymentResponse);
if (paymentUrl) {
window.location.assign(paymentUrl);
return;
}
setIsSubscriptionSheetOpen(false);
setShowPaymentSuccessToast(true);
if (caseId) {
await contactInfoQuery.refetch();
setIsContactInfoSheetOpen(true);
}
} catch (err: any) {
console.error("Habcoin payment request failed", err);
const msg =
err?.response?.data?.error ||
err?.response?.data?.detail ||
err?.response?.data?.message ||
err?.message ||
"Payment failed";
if (msg === "Not enough coins" || msg?.includes?.("Not enough coins")) {
setIsInsufficientCoins(true);
setPaymentError(
t["Insufficient coin balance. Please recharge your account."] ||
"Insufficient coin balance. Please recharge your account.",
);
} else {
setPaymentError(msg);
}
}
};
const handleNoContactReport = async () => {
if (!caseId || contactStatusMutation.isPending) return;
await contactStatusMutation.mutateAsync({
action: "no_contact",
custom_note:
"No contact reported by female candidate after decision window",
});
};
const isFinalized =
caseStatus === "finalized" || profile?.status === "matched";
return (
<>
<PageBackground />
{isCallResultSheetOpen ? (
<CallResultSheet
onClose={() => setIsCallResultSheetOpen(false)}
onOtherReasonsClick={() => setIsDismissReasonSheetOpen(true)}
onSubmit={async (value) => {
if (caseId) {
await contactStatusMutation.mutateAsync({
action: "contacted",
custom_note: value,
});
}
}}
/>
) : null}
{isContactReceivedConfirmOpen ? (
<FemaleConsentSheet
title={t.Confirm}
description={
<p className="font-bold text-[#00AC78] text-center my-4 text-base">
{t["Are you sure contact has been made?"]}
</p>
}
buttons={
<SwipeButton
theme="green"
text={t["Confirm"]}
onCancel={() => setIsContactReceivedConfirmOpen(false)}
onSuccess={async () => {
setIsContactReceivedConfirmOpen(false);
setHasConfirmedFemaleContact(true);
if (!caseId) {
return;
}
try {
await contactStatusMutation.mutateAsync({
action: "contacted",
custom_note:
"Contact received confirmed by female candidate",
});
} catch (error) {
// The confirmation screen must advance immediately after a swipe.
// Keep the local state visible while the profile query retries.
console.error("Unable to persist received contact", error);
}
}}
/>
}
onClose={() => setIsContactReceivedConfirmOpen(false)}
closeOnOutside={true}
/>
) : null}
{isDismissReasonSheetOpen ? (
<DismissReasonSheet
onClose={() => setIsDismissReasonSheetOpen(false)}
onSubmit={async (value) => {
if (caseId) {
await outcomeMutation.mutateAsync({
status: "failure",
custom_note: value,
});
}
}}
/>
) : null}
{isOutcomeSheetOpen ? (
isFemaleProfile ? (
<FemaleOutcomeSheet
onClose={() => setIsOutcomeSheetOpen(false)}
onSubmit={async (status, reason) => {
if (status === "success") {
// If they confirm they are in the acquaintance/proposal process and nothing is finalized yet:
// No change is made to the profile, we just close the sheet.
setIsOutcomeSheetOpen(false);
} else {
// If they cancel:
if (caseId) {
await outcomeMutation.mutateAsync({
status: "failure",
custom_note: reason,
});
}
}
}}
/>
) : (
<OutcomeSelectionSheet
onClose={() => setIsOutcomeSheetOpen(false)}
onSubmit={async (status) => {
if (status === "success") {
if (caseId) {
await outcomeMutation.mutateAsync({
status: "success",
});
}
} else {
setIsDismissReasonSheetOpen(true);
}
}}
/>
)
) : null}
{isContactInfoSheetOpen ? (
<FemaleConsentSheet
title={t["Contact Detail"]}
description={
t[
"Please mention during the call that you were introduced by the Habib Marriage app."
]
}
buttons={
contactInfoPhoneItems.length ? (
<div className="space-y-4">
{contactInfoPhoneItems.map((item) => (
<ContactInfoPhoneCard key={item.key} item={item} />
))}
</div>
) : (
<div className="rounded-[12px] bg-[#ECECEC] px-4 py-3 group-12 font-semibold text-[#555]">
{t["Contact information is not available yet."]}
</div>
)
}
onClose={() => setIsContactInfoSheetOpen(false)}
/>
) : null}
{isSubscriptionSheetOpen ? (
<SubscriptionRequiredSheet
onClose={() => {
setIsSubscriptionSheetOpen(false);
setPaymentError(null);
setIsInsufficientCoins(false);
}}
onPayment={handlePayment}
isPaymentPending={!recommendedPlanId || paymentMutation.isPending}
errorMessage={paymentError}
showBuyCoins={isInsufficientCoins}
/>
) : null}
{isNoContactConfirmOpen ? (
<FemaleConsentSheet
title={t.Confirm}
description={
<p className="font-bold text-[#E03950] text-center my-4 text-base">
{
t[
"No contact has been made with you in any way or by any party."
]
}
</p>
}
buttons={
<button
type="button"
onClick={async () => {
setIsNoContactConfirmOpen(false);
await handleNoContactReport();
}}
className="w-full h-[48px] rounded-[15px] bg-[#E03950] text-white font-semibold group-14 flex items-center justify-center transition-transform active:scale-[0.98] cursor-pointer hover:opacity-95"
>
{t.Confirm}
</button>
}
onClose={() => setIsNoContactConfirmOpen(false)}
closeOnOutside={true}
/>
) : null}
<PageHeader profile={profile} sticky />
<main className="flex min-h-0 flex-1 flex-col pb-[calc(20px+var(--safe-bottom))] text-center">
<div className="flex flex-1 flex-col justify-between gap-6 pt-4">
<section className="flex flex-col items-center">
{isFinalized ? (
<div className="flex flex-col items-center max-w-[320px] text-center my-auto py-12">
<div className="relative flex items-center justify-center text-[70px] animate-bounce">
🎉
</div>
<h1 className="mt-8 text-center text-[24px] leading-[1.25] font-bold text-[#E03950]">
{t["Congratulations! 🎉"]}
</h1>
<p className="mt-6 text-[#4A4A4A] group-14 font-medium leading-relaxed">
{
t[
"Wishing you a lifetime of love, joy, and happiness. Your profile has been successfully closed."
]
}
</p>
</div>
) : (
<>
{/* Illustration */}
<div className="relative mt-6 flex items-center justify-center">
{/* soft glow */}
<div className="absolute h-[115px] w-[115px] rounded-full bg-[#FF5C7D]/10 blur-xl" />
<div className="relative z-10">
<Image
src="/assets/images/Group 15978804fdasf68.svg"
alt={t["Request accepted"]}
width={131}
height={125}
priority
/>
</div>
</div>
<h1 className="mt-8 text-[20px] leading-none font-black tracking-[0.03em] text-[#171717] uppercase">
{titleText}
</h1>
{caseStatus === "contacted" ||
isFemaleContactConfirmed ||
(isFemaleProfile && contactStatusMutation.isPending) ? (
<div className="w-full border border-[#E2E8F0] bg-white/90 backdrop-blur-sm rounded-[20px] mt-6 px-5 py-4 text-center shadow-sm max-w-[340px] flex flex-col items-center justify-center min-h-[90px]">
{isFemaleProfile && contactStatusMutation.isPending ? (
<LoadingThreeDot className="text-[#E03950]" />
) : (
<p className="text-[#475569] text-[14px] font-medium leading-relaxed">
{isFemaleProfile
? t[
"Thank you for your feedback. To complete the process, please submit the final outcome of this introduction/contact so that the final status can be determined. If the final status is not yet determined, you can stay in this state until it is finalized."
]
: t[
"Thank you for giving us feedback, we would be very happy if you also let us know the final result."
]}
</p>
)}
</div>
) : (
<p className="mt-5 max-w-[340px] text-[15px] leading-[1.6] font-medium text-[#777777]">
{noContactReportedSuccess
? t[
"Thank you for your feedback. Our support team will investigate the matter and notify you of the result. Please wait patiently during the review; our support will contact you."
]
: isFemaleProfile
? t[
"The selected candidate will contact your family shortly."
]
: t[
"You can now view their family's contact details and arrange further steps."
]}
</p>
)}
<>
{caseStatus === "contacted" ||
isFemaleContactConfirmed ||
(isFemaleProfile && contactStatusMutation.isPending) ? (
<div className="flex mt-8 w-full gap-3 justify-center max-w-[350px] mx-auto">
{isFemaleProfile &&
contactStatusMutation.isPending ? null : isFemaleProfile ? (
<button
type="button"
onClick={() => setIsOutcomeSheetOpen(true)}
disabled={outcomeMutation.isPending}
className="w-full h-[50px] px-6 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[15px] flex items-center justify-center shadow-sm transition-transform active:scale-[0.98] cursor-pointer hover:opacity-95 disabled:opacity-50"
>
{outcomeMutation.isPending ? (
<LoadingThreeDot className="text-white" />
) : (
t["Share Result"]
)}
</button>
) : (
<>
<button
type="button"
disabled={isOpeningProfile}
onClick={handleOpenProfile}
className="flex-1 h-[50px] px-3 rounded-[14px] border border-[#E2E8F0] bg-white/95 backdrop-blur-sm text-[#334155] font-bold text-[14px] shadow-sm flex items-center justify-center transition-transform active:scale-[0.98] cursor-pointer hover:bg-[#F8FAFC]"
>
{isOpeningProfile ? (
<LoadingThreeDot />
) : (
t["View Profile"]
)}
</button>
<button
type="button"
onClick={() => setIsOutcomeSheetOpen(true)}
disabled={outcomeMutation.isPending}
className="flex-1 h-[50px] px-3 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[14px] flex items-center justify-center shadow-sm transition-transform active:scale-[0.98] cursor-pointer hover:opacity-95 disabled:opacity-50"
>
{outcomeMutation.isPending ? (
<LoadingThreeDot className="text-white" />
) : (
t["Submit Final Outcome"]
)}
</button>
</>
)}
</div>
) : (
<div className="flex mt-8 w-full justify-center gap-3.5 max-w-md mx-auto">
{isFemaleProfile ? (
<button
type="button"
onClick={() => setIsNoContactConfirmOpen(true)}
disabled={
contactStatusMutation.isPending ||
noContactReportedSuccess
}
className="flex-1 min-h-[48px] px-3.5 py-2.5 rounded-[14px] border border-[#E2E8F0] bg-white/95 backdrop-blur-sm text-[#475569] font-bold text-[13.5px] leading-tight shadow-sm flex items-center justify-center text-center whitespace-nowrap transition-all cursor-pointer hover:bg-[#F8FAFC] active:scale-[0.98] disabled:opacity-50 disabled:cursor-not-allowed"
>
{contactStatusMutation.isPending ? (
<LoadingThreeDot />
) : (
primaryActionText
)}
</button>
) : (
<button
type="button"
disabled={isOpeningProfile}
onClick={handleOpenProfile}
className="flex-1 min-h-[48px] px-3.5 py-2.5 rounded-[14px] border border-[#E2E8F0] bg-white/95 backdrop-blur-sm text-[#475569] font-bold text-[14px] leading-tight shadow-sm flex items-center justify-center text-center whitespace-nowrap transition-all hover:bg-[#F8FAFC] active:scale-[0.98] cursor-pointer"
>
{isOpeningProfile ? (
<LoadingThreeDot />
) : (
primaryActionText
)}
</button>
)}
<button
type="button"
onClick={() => {
void handleSecondaryAction();
}}
disabled={
paymentMutation.isPending ||
isFetchingContact
}
className={
isFemaleProfile
? "flex-1 min-h-[48px] px-3.5 py-2.5 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[13.5px] leading-tight flex items-center justify-center text-center whitespace-nowrap shadow-sm transition-all duration-150 cursor-pointer hover:opacity-95 active:scale-[0.96] disabled:opacity-50 disabled:cursor-not-allowed"
: "flex-1 min-h-[48px] appearance-none border-0 bg-transparent p-0 text-center cursor-pointer transition-transform duration-150 active:scale-[0.96] disabled:opacity-50 disabled:cursor-not-allowed"
}
>
{isFemaleProfile ? (
paymentMutation.isPending ? (
<LoadingThreeDot className="text-white" />
) : (
secondaryActionText
)
) : (
<div className="w-full h-full min-h-[48px] px-3.5 py-2.5 rounded-[14px] bg-gradient-to-r from-[#FF6687] to-[#FF456C] text-white font-bold text-[14px] leading-tight flex items-center justify-center text-center whitespace-nowrap shadow-sm hover:opacity-95 active:shadow-inner">
{paymentMutation.isPending || isFetchingContact ? (
<LoadingThreeDot className="text-white" />
) : (
secondaryActionText
)}
</div>
)}
</button>
</div>
)}
{caseStatus !== "contacted" &&
!isFemaleContactConfirmed &&
!noContactReportedSuccess &&
!(isFemaleProfile && contactStatusMutation.isPending) ? (
<div className="border border-[#FDA4AF]/60 bg-[#FFF1F2]/80 backdrop-blur-sm rounded-[16px] mt-6 p-4 max-w-md mx-auto shadow-sm">
<p className="text-[#BE123C] text-[12px] font-medium leading-[1.65] whitespace-pre-line text-justify">
{
t[
"Please note that after a match introduction is made, you and your family have a maximum of 48 hours to make at least an initial contact with the introduced person or their family and express your willingness to begin the acquaintance process. Failure to establish communication or provide any update within this timeframe will result in the removal of this introduction, and according to the platform’s policies, your account and subscription will be permanently suspended"
]
}
</p>
</div>
) : null}
</>
</>
)}
</section>
<div className="space-y-8 pb-20">
{/* Advisor section */}
<AdvisorActionsCard
title={t["Get an advisor"]}
description={
t[
"Not sure what to do next? Our psychology section is here to guide you at every step."
]
}
avatars={advisorAvatars}
extraCount={7}
getAdvisorLabel={t["Get Advisor"]}
onGetAdvisor={openAdvisors}
/>
<section className="pointer-events-none fixed bottom-0 left-1/2 z-20 w-full max-w-[834px] -translate-x-1/2 bg-[#F5F5F5]">
<div
style={{ paddingBottom: "calc(20px + var(--safe-bottom))" }}
className="pointer-events-auto px-[17px] md:px-8 pt-3"
>
<div className="flex items-center justify-center w-full gap-1 rounded-[11px] bg-[#DBDBDB] py-3.5">
<Image
src="/assets/images/material-symbols_lock.svg"
width={24}
height={24}
alt="lock"
/>
<h2 className="group-14 leading-none font-semibold text-[#747474]">
{t["Profile is locked"]}
</h2>
</div>
</div>
</section>
</div>
</div>
</main>
<MarriageAdvisorsOverlay
open={isAdvisorOpen}
onClose={closeAdvisors}
/>
<MatchProfileOverlay
open={isProfileOpen}
profile={profile}
onClose={closeProfile}
/>
{showPaymentSuccessToast && (
<ErrorToast
variant="success"
message={t["Payment successful"] || "Payment successful"}
onClose={() => setShowPaymentSuccessToast(false)}
/>
)}
</>
);
}