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.
 
 
 
 
 

411 lines
16 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 { LoadingThreeDot } from "@/components/Componentes/loading-three-dot";
import { PageLoadingSkeleton } from "@/components/Componentes/page-loading-skeleton";
import CallResultSheet from "@/components/Componentes/call-result-sheet";
import DismissReasonSheet from "@/components/Componentes/dismiss-reason-sheet";
import OutcomeSelectionSheet from "@/components/Componentes/outcome-selection-sheet";
import PageHeader from "@/components/Componentes/page-header";
import AdvisorActionsCard from "@/components/Componentes/advisor-actions-card";
import MarriageAdvisorsOverlay, {
useMarriageAdvisorsOverlay,
} from "@/components/Componentes/marriage-advisors-overlay";
import MatchProfileOverlay, {
useMatchProfileOverlay,
} from "@/components/Componentes/match-profile-overlay";
import { PageBackground } from "@/components/Componentes/page-background";
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
import {
useSubmitMarriageContactStatusMutation,
useSubmitMarriageOutcomeMutation,
} from "@/hooks/marriage/use-contact-status";
import { getSubmitPath } from "@/lib/get-submit-path";
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" },
];
export default function CandidateContactClient() {
const { dictionary: t, locale } = useI18n();
const router = useRouter();
const [isOutcomeSheetOpen, setIsOutcomeSheetOpen] = useState(false);
const [isCallResultSheetOpen, setIsCallResultSheetOpen] = useState(false);
const [isDismissReasonSheetOpen, setIsDismissReasonSheetOpen] =
useState(false);
const { isAdvisorOpen, openAdvisors, closeAdvisors } =
useMarriageAdvisorsOverlay();
const { isProfileOpen, openProfile, closeProfile } =
useMatchProfileOverlay();
const { data: profile, isLoading: isProfileLoading } =
useMarriageProfileQuery({
refetchInterval: 3000,
});
useEffect(() => {
if (!profile) {
return;
}
const targetPath = getSubmitPath(profile);
if (targetPath !== "/candidate-contact") {
router.replace(localizePath(targetPath, locale));
}
}, [profile, router, locale]);
// Signal Flutter to lift its loading cover once the profile is available.
useHabibWebReady(!!profile && !isProfileLoading);
const isRedirecting = useMemo(() => {
if (!profile) return false;
return getSubmitPath(profile) !== "/candidate-contact";
}, [profile]);
const caseId = profile?.active_case?.case_id;
const caseStatus = profile?.active_case?.status;
const isFemale = profile?.gender === "female";
const isFinalized =
caseStatus === "finalized" || profile?.status === "matched";
const contactStatusMutation = useSubmitMarriageContactStatusMutation(
caseId ?? "",
);
const outcomeMutation = useSubmitMarriageOutcomeMutation(caseId ?? "");
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",
});
};
if (isProfileLoading || isRedirecting) {
return <PageLoadingSkeleton />;
}
// If female, render the beautiful, customized layout matching the design
if (isFemale) {
return (
<>
<PageBackground />
{isOutcomeSheetOpen ? (
<OutcomeSelectionSheet
onClose={() => setIsOutcomeSheetOpen(false)}
onSubmit={async (status) => {
if (status === "success") {
if (caseId) {
await outcomeMutation.mutateAsync({
status: "success",
});
}
} else {
setIsDismissReasonSheetOpen(true);
}
}}
/>
) : null}
{isDismissReasonSheetOpen ? (
<DismissReasonSheet
onClose={() => setIsDismissReasonSheetOpen(false)}
onSubmit={async (value) => {
if (caseId) {
await outcomeMutation.mutateAsync({
status: "failure",
custom_note: value,
});
}
}}
/>
) : null}
<main className="-mx-[17px] flex min-h-screen flex-col px-[23px] pt-[max(12px,calc(var(--safe-top)+4px))] pb-[calc(20px+var(--safe-bottom))]">
<PageHeader
className="-mx-[6px]"
profile={profile}
leftButton={
isFemale ? { icon: "back", className: "hidden" } : undefined
}
/>
<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 section */}
<div className="relative mt-4 flex items-center justify-center">
<Image
src="/assets/images/Group 159788fd0467.svg"
alt={t["Selected candidate contact status"]}
width={160}
height={152}
priority
/>
</div>
{/* Title / Status message */}
<h1 className="mt-8 text-center text-[20px] leading-[1.25] font-bold text-[#1A1A1A] max-w-[280px]">
{
t[
"The selected candidate will contact your family shortly."
]
}
</h1>
{caseStatus === "contacted" ? (
<>
{/* Outcome instructions and button */}
<div className="w-full border border-[#ECECEC] bg-white rounded-[15px] mt-8 px-4 py-4 text-center shadow-sm">
<p className="text-[#555555] group-14 font-medium leading-relaxed">
{
t[
"Thank you for giving us feedback, we would be very happy if you also let us know the final result."
]
}
</p>
</div>
<div className="flex mt-6 w-full gap-3">
<button
type="button"
onClick={() => openProfile()}
className="flex-1 h-[52px] rounded-[15px] border border-[#BFBFBF] bg-white text-[#36363C] font-semibold group-14 flex items-center justify-center transition-transform active:scale-[0.98] cursor-pointer hover:bg-[#F5F5F5]"
>
{t["View Profile"]}
</button>
<button
type="button"
onClick={() => setIsOutcomeSheetOpen(true)}
disabled={outcomeMutation.isPending}
className="flex-1 h-[52px] rounded-[15px] bg-gradient-to-r from-[#FE6F82] to-[#E03950] text-white font-semibold group-14 flex items-center justify-center shadow-lg shadow-[#FE6F82]/30 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>
</>
) : (
<>
{/* Action Buttons Row */}
<div className="flex mt-8 w-full gap-3">
<button
type="button"
onClick={handleNoContactReport}
disabled={contactStatusMutation.isPending}
className="flex-1 h-[52px] rounded-[15px] bg-[#F5F5F7] text-[#8E8E93] font-semibold group-14 flex items-center justify-center transition-transform active:scale-[0.98] cursor-pointer hover:bg-[#EAEAEF] disabled:opacity-50"
>
{contactStatusMutation.isPending ? (
<LoadingThreeDot className="text-[#8E8E93]" />
) : (
t["Report No Contact"]
)}
</button>
<button
type="button"
onClick={async () => {
if (caseId) {
await contactStatusMutation.mutateAsync({
action: "contacted",
});
}
}}
disabled={contactStatusMutation.isPending}
className="flex-1 h-[52px] rounded-[15px] bg-gradient-to-r from-[#FE6F82] to-[#E03950] text-white font-semibold group-14 flex items-center justify-center shadow-lg shadow-[#FE6F82]/30 transition-transform active:scale-[0.98] cursor-pointer hover:opacity-95 disabled:opacity-50"
>
{contactStatusMutation.isPending ? (
<LoadingThreeDot className="text-white" />
) : (
t["Confirm Contacted"]
)}
</button>
</div>
{/* Red warning box */}
<div className="w-full border border-[#F0445B] bg-[#FFF5F6] rounded-[15px] mt-4 px-4 py-3 text-center">
<p className="text-[#F0445B] group-12 font-semibold leading-normal">
{
t[
"To keep the process moving smoothly, the other party has a 48-hour (2-day) window to make initial contact with you or your family. If no contact is established after 2 days, you have the option to decline his request or notify us that he hasn't reached out."
]
}
</p>
</div>
</>
)}
</>
)}
</section>
<div className="space-y-4 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}
/>
{/* Profile Locked banner */}
<section className="pointer-events-none fixed bottom-0 left-1/2 z-20 w-full sm:max-w-[375px] -translate-x-1/2 bg-[#F5F5F5]">
<div
style={{ paddingBottom: "calc(20px + var(--safe-bottom))" }}
className="pointer-events-auto px-[17px] 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}
onClose={closeProfile}
/>
</>
);
}
// Fallback UI for male/other users
return (
<>
<PageBackground />
{isCallResultSheetOpen ? (
<CallResultSheet
onClose={() => setIsCallResultSheetOpen(false)}
onOtherReasonsClick={() => setIsDismissReasonSheetOpen(true)}
onSubmit={async (value) => {
if (caseId) {
await contactStatusMutation.mutateAsync({
action: "contacted",
custom_note: value,
});
}
}}
/>
) : null}
{isDismissReasonSheetOpen ? (
<DismissReasonSheet
onClose={() => setIsDismissReasonSheetOpen(false)}
onSubmit={async (value) => {
if (caseId) {
await contactStatusMutation.mutateAsync({
action: "contacted",
custom_note: value,
});
}
}}
/>
) : null}
<main className="-mx-[17px] flex min-h-screen flex-col px-[17px] pt-[max(12px,calc(var(--safe-top)+4px))] pb-36">
<PageHeader profile={profile} />
<section className="flex flex-1 items-center justify-center">
<div className="flex max-w-[300px] flex-col items-center">
<Image
src="/assets/images/Group 1597880467.svg"
alt={t["Selected candidate contact status"]}
width={131}
height={125}
/>
<h1 className="mt-10 text-center text-[18px] leading-[1.2] font-bold text-[#1A1A1A]">
{t["The selected candidate will contact your family shortly."]}
</h1>
</div>
</section>
<section
style={{ paddingBottom: `calc(2rem + var(--safe-bottom))` }}
className="fixed right-0 bottom-0 left-0 z-20 mx-auto flex w-full sm:max-w-[375px] gap-3 rounded-t-[30px] bg-white px-[17px] pt-6 shadow-[0_-18px_50px_rgba(15,23,42,0.08)]"
>
<button
type="button"
onClick={() => setIsCallResultSheetOpen(true)}
className="flex-1 h-[52px] rounded-[11px] bg-gradient-to-tl from-[#FE6F82] to-[#E03950] text-white font-semibold flex items-center justify-center cursor-pointer transition-opacity active:opacity-90"
>
{t["Confirm Contacted"]}
</button>
<button
type="button"
onClick={handleNoContactReport}
disabled={contactStatusMutation.isPending}
className="flex-1 h-[52px] rounded-[11px] border border-[#8B8B8B] bg-transparent text-[#8B8B8B] font-semibold flex items-center justify-center cursor-pointer transition-opacity active:opacity-90 disabled:opacity-50"
>
{contactStatusMutation.isPending ? (
<LoadingThreeDot className="text-[#8B8B8B]" />
) : (
t["Report No Contact"]
)}
</button>
</section>
</main>
<MarriageAdvisorsOverlay
open={isAdvisorOpen}
onClose={closeAdvisors}
/>
<MatchProfileOverlay
open={isProfileOpen}
onClose={closeProfile}
/>
</>
);
}