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.
 
 
 
 
 

389 lines
13 KiB

"use client";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { getSubmitPath } from "@/lib/get-submit-path";
import { FiCopy, FiPhone } from "react-icons/fi";
import CallResultSheet from "@/components/ui/call-result-sheet";
import FemaleConsentSheet from "@/components/ui/female-consent-sheet";
import NavigationButton from "@/components/ui/navigation-button";
import SubscriptionRequiredSheet from "@/components/ui/subscription-required-sheet";
import { PageBackground } from "@/components/utils/page-background";
import type { MarriageField, MarriagePhoneFieldValue } from "@/hooks/marriage/types";
import { useMarriageContactInfoQuery } from "@/hooks/marriage/use-contact-info";
import { useSubmitMarriageContactStatusMutation } from "@/hooks/marriage/use-contact-status";
import {
extractHabcoinPaymentUrl,
useHabcoinPaymentMutation,
} from "@/hooks/marriage/use-habcoin-payment";
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
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: MarriageField[] | null | undefined,
): ContactInfoPhoneItem[] {
if (!contactInfoFields) {
return [];
}
return contactInfoFields
.map((field) => {
const phoneNumber = sanitizePhoneNumber(field.value);
if (!phoneNumber) {
return null;
}
return {
key: field.key,
label: field.label || field.key,
phoneNumber,
};
})
.filter((item): item is ContactInfoPhoneItem => item !== null);
}
function ContactInfoPhoneCard({ item }: { item: ContactInfoPhoneItem }) {
return (
<div className="flex items-center justify-between rounded-[15px] border border-[#E4E4E4] bg-[#FBFBFB] px-4 py-3.5 shadow-[0_4px_12px_rgba(0,0,0,0.03)]">
<div className="text-left">
<p className="text-xs font-semibold text-[#8F8F8F]">{item.label}</p>
<p className="text-base font-bold text-[#1F1F1F] dir-ltr">{item.phoneNumber}</p>
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => {
navigator.clipboard
.writeText(item.phoneNumber)
.catch(() => {});
}}
className="inline-flex p-3 items-center justify-center rounded-[10px] bg-[#F0445B] text-white"
>
<Image src={"/assets/images/Frame 2095586fdas679.svg"} width={16} height={16} alt="copy"/>
</button>
<a
href={`tel:${item.phoneNumber}`}
className="inline-flex p-3 items-center justify-center rounded-[10px] bg-[#F0445B] text-white"
>
<Image src={"/assets/images/Vecfdastor.svg"} width={16} height={16} alt="copy"/>
</a>
</div>
</div>
);
}
export default function RequestAcceptedPage() {
const { locale } = useI18n();
const router = useRouter();
const [isCallResultSheetOpen, setIsCallResultSheetOpen] = useState(false);
const [isContactInfoSheetOpen, setIsContactInfoSheetOpen] = useState(false);
const [isSubscriptionSheetOpen, setIsSubscriptionSheetOpen] = useState(false);
const profileHref = localizePath("/new-match/profile", locale);
const { data: profile } = useMarriageProfileQuery({
refetchInterval: 3000,
});
useEffect(() => {
if (!profile) {
return;
}
const targetPath = getSubmitPath(profile);
if (targetPath !== "/request-accepted") {
router.replace(localizePath(targetPath, locale));
}
}, [profile, router, locale]);
const isFemaleProfile = profile?.gender === "female";
const caseId = profile?.active_case?.case_id;
const caseStatus = profile?.active_case?.status;
const recommendedPlanId = profile?.recommended_plan?.id;
const paymentMutation = useHabcoinPaymentMutation();
const contactStatusMutation = useSubmitMarriageContactStatusMutation(caseId ?? "", {
onSuccess: () => {
router.push(localizePath("/finding-match", locale));
},
});
const contactInfoQuery = useMarriageContactInfoQuery(caseId, {
enabled: false,
});
const titleText = isFemaleProfile
? "درخواست تایید شد"
: caseStatus === "payment_done"
? "اطلاعات تماس آزاد شد"
: "درخواست توسط خانم تایید شد!";
const primaryActionText = isFemaleProfile
? "اطلاع‌رسانی عدم تماس"
: "مشاهده پروفایل";
const secondaryActionText = isFemaleProfile
? "ثبت نتیجه تماس"
: caseStatus === "payment_done"
? "مشاهده شماره تماس"
: "پرداخت و دریافت تماس";
const contactInfoPhoneItems = getContactInfoPhoneItems(
contactInfoQuery.data?.contact_info,
);
const handleSecondaryAction = async () => {
if (isFemaleProfile) {
setIsCallResultSheetOpen(true);
return;
}
if (caseStatus === "female_accepted" || caseStatus === "payment_pending") {
setIsSubscriptionSheetOpen(true);
return;
}
if (caseStatus === "payment_done") {
if (!caseId) {
return;
}
if (!contactInfoQuery.data) {
await contactInfoQuery.refetch();
}
setIsContactInfoSheetOpen(true);
}
};
const handlePayment = async () => {
if (!recommendedPlanId || paymentMutation.isPending) {
return;
}
try {
const paymentResponse =
await paymentMutation.mutateAsync(recommendedPlanId);
const paymentUrl = extractHabcoinPaymentUrl(paymentResponse);
if (paymentUrl) {
window.location.assign(paymentUrl);
return;
}
router.push(profileHref);
} catch (error) {
console.error("Habcoin payment request failed", error);
}
};
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",
});
};
return (
<>
<PageBackground />
{isCallResultSheetOpen ? (
<CallResultSheet
onClose={() => setIsCallResultSheetOpen(false)}
onSubmit={async (value) => {
if (caseId) {
await contactStatusMutation.mutateAsync({
action: "contacted",
custom_note: value,
});
}
}}
/>
) : null}
{isContactInfoSheetOpen ? (
<FemaleConsentSheet
title="Contact Detail"
description="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]">
Contact information is not available yet.
</div>
)
}
onClose={() => setIsContactInfoSheetOpen(false)}
/>
) : null}
{isSubscriptionSheetOpen ? (
<SubscriptionRequiredSheet
onClose={() => setIsSubscriptionSheetOpen(false)}
onPayment={handlePayment}
isPaymentPending={!recommendedPlanId || paymentMutation.isPending}
/>
) : null}
<main
style={{ paddingBottom: "calc(40px + var(--safe-bottom))" }}
className="-mx-[17px] flex min-h-screen flex-col px-[23px] pt-[max(16px,calc(var(--safe-top)+8px))] text-center"
>
<header className="-mx-[6px] flex items-center justify-between pb-3">
<NavigationButton icon="back" />
<h1 className="font-faminela group-16">Habib Marriage</h1>
<NavigationButton icon="support" iconLabel="Support" />
</header>
<div className="flex flex-1 flex-col justify-between gap-20 pt-[109px]">
<section className="flex flex-col items-center">
<div className="relative isolate flex items-center justify-center">
<Image
src="/assets/images/Group 15978804fdasf68.svg"
alt="Request sent"
width={131}
height={125}
priority
className="relative z-10"
/>
</div>
<h1 className="mt-11 group-16 leading-none font-black tracking-[0.02em] text-[#171717] uppercase">
{titleText}
</h1>
<p className="mt-4 max-w-[315px] group-12 leading-[1.45] font-semibold text-[#777777]">
You can now view their family&apos;s contact details and arrange
further steps.
</p>
<div className="flex mt-9 w-full justify-center gap-4">
{isFemaleProfile ? (
<button
type="button"
onClick={handleNoContactReport}
disabled={contactStatusMutation.isPending}
className="max-w-[212px] cursor-pointer appearance-none border-0 bg-transparent p-0 text-left"
>
<div className="bg-[#F5F5F5] px-4 py-2 rounded-[15px] shadow group-14 text-center font-semibold text-[#36363C] hover:bg-[#EBEBEB] transition-colors">
{primaryActionText}
</div>
</button>
) : (
<Link href={profileHref} className="max-w-[212px]">
<div className="bg-[#F5F5F5] px-4 py-2 rounded-[15px] shadow group-14 text-center font-semibold text-[#36363C]">
{primaryActionText}
</div>
</Link>
)}
<button
type="button"
onClick={() => {
if (isFemaleProfile) {
setIsCallResultSheetOpen(true);
return;
}
if (
caseStatus === "female_accepted" ||
caseStatus === "payment_pending"
) {
setIsCallResultSheetOpen(true);
return;
}
if (caseStatus === "payment_done") {
void handleSecondaryAction();
return;
}
setIsSubscriptionSheetOpen(true);
}}
className="max-w-[212px] appearance-none border-0 bg-transparent p-0 text-left"
>
<div className="bg-linear-180 from-[#FE6F82] to-[#E03950] px-4 py-2 rounded-[15px] shadow group-14 text-center font-semibold text-[#fff] shadow-md shadow-[#F2596E]/60">
{secondaryActionText}
</div>
</button>
</div>
<div className="border border-[#F0445B] bg-[#F0445B]/10 rounded-xl mt-4">
<p className="text-[#F0445B] group-12 font-semibold py-2.5 px-3.5">
If they dont contact you within 2 days, please inform us.
</p>
</div>
</section>
<div className="space-y-8">
<section className="flex flex-col items-center text-center">
<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]">
Profile is locked
</h2>
</div>
</section>
</div>
</div>
</main>
</>
);
}