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
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'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 don’t 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>
|
|
</>
|
|
);
|
|
}
|