w-aura/src/components/Payment/nmi/CheckoutForm/index.tsx
2025-07-01 15:22:35 +00:00

275 lines
9.7 KiB
TypeScript

import MainButton from "@/components/MainButton";
import { useEffect, useState } from "react";
import styles from "./styles.module.scss";
import { usePayment } from "@/hooks/payment/nmi/usePayment";
import SecurityPayments from "../../SecurityPayments";
import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import Loader, { LoaderColor } from "@/components/Loader";
import { IFunnelPaymentVariant } from "@/api/resources/Session";
export type TConfirmType = "payment" | "setup";
interface ICheckoutFormProps {
subscriptionReceiptId?: string;
returnUrl?: string;
confirmType?: TConfirmType;
isHide?: boolean;
activeProduct: IFunnelPaymentVariant;
isAnonymous?: boolean;
sessionId?: string;
funnel: ELocalesPlacement;
paymentPlacement: string;
onSuccess?: () => void;
onError?: (error?: string | null) => void;
onModalClosed?: () => void;
}
export default function CheckoutForm({
activeProduct,
isAnonymous = false,
sessionId = "",
funnel,
paymentPlacement,
onError,
onSuccess,
onModalClosed,
isHide = false,
}: ICheckoutFormProps) {
const { translate } = useTranslations(ELocalesPlacement.V1);
const [payButtonClicked, setPayButtonClicked] = useState(false);
const { variant, isReady } = useUnleash({
flag: EUnleashFlags.paymentButtonLogic,
});
const isNewPaymentButton = variant === "new";
const [isCardTypeError, setIsCardTypeError] = useState(false);
// const address = useAddressFields(language);
const {
isLoading,
error,
isPaymentSuccess,
submitInlineForm,
formValidation,
isFormValid,
isModalClosed,
cardType,
} = usePayment({
activeProduct,
paymentFormType: "inline",
isAnonymous,
sessionId,
funnel,
paymentPlacement,
});
useEffect(() => {
// if (error) {
console.log(error);
if (error === "card_type_error") {
return setIsCardTypeError(true);
} else {
setIsCardTypeError(false);
}
onError?.(error);
// }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [error]);
useEffect(() => {
if (isModalClosed && onModalClosed) {
onModalClosed();
}
}, [isModalClosed, onModalClosed]);
useEffect(() => {
if (isPaymentSuccess && onSuccess) {
onSuccess();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isPaymentSuccess]);
const handleSubmit = (
e: React.FormEvent<HTMLFormElement> | React.MouseEvent<HTMLButtonElement>
) => {
e.preventDefault();
setPayButtonClicked(true);
// const isAddressValid = address.validateAll();
if (!isFormValid) {
return;
}
submitInlineForm();
};
if (!isReady) {
return (
<div className={styles.loaderContainer}>
<Loader color={LoaderColor.Black} />
</div>
);
}
return (
<form
className={`${styles.form} ${isHide ? styles.hide : ""}`}
id="payment-form"
onSubmit={handleSubmit}
>
<div className={styles.formContainer}>
<img
className={styles.cardIcon}
src="/payment-form/credit-card.svg"
alt="card"
/>
{isCardTypeError && (
<div className={styles.cardTypeError}>
<svg
width="14"
height="20"
viewBox="0 0 14 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M14 20H0V0H14V20Z" stroke="#E5E7EB" />
<g clipPath="url(#clip0_1_46)">
<path
d="M7 3.625C7.38828 3.625 7.74648 3.83008 7.94336 4.16641L13.8496 14.2289C14.0492 14.568 14.0492 14.9863 13.8551 15.3254C13.6609 15.6645 13.2973 15.875 12.9062 15.875H1.09375C0.702734 15.875 0.339062 15.6645 0.144922 15.3254C-0.049219 14.9863 -0.0464846 14.5652 0.15039 14.2289L6.05664 4.16641C6.25352 3.83008 6.61172 3.625 7 3.625ZM7 7.125C6.63633 7.125 6.34375 7.41758 6.34375 7.78125V10.8438C6.34375 11.2074 6.63633 11.5 7 11.5C7.36367 11.5 7.65625 11.2074 7.65625 10.8438V7.78125C7.65625 7.41758 7.36367 7.125 7 7.125ZM7.875 13.25C7.875 13.0179 7.78281 12.7954 7.61872 12.6313C7.45462 12.4672 7.23206 12.375 7 12.375C6.76794 12.375 6.54538 12.4672 6.38128 12.6313C6.21719 12.7954 6.125 13.0179 6.125 13.25C6.125 13.4821 6.21719 13.7046 6.38128 13.8687C6.54538 14.0328 6.76794 14.125 7 14.125C7.23206 14.125 7.45462 14.0328 7.61872 13.8687C7.78281 13.7046 7.875 13.4821 7.875 13.25Z"
fill="#EF4444"
/>
</g>
<defs>
<clipPath id="clip0_1_46">
<path d="M0 2.75H14V16.75H0V2.75Z" fill="white" />
</clipPath>
</defs>
</svg>
<div className={styles.textContainer}>
<p className={styles.title}>
{translate("payment_modal.card_type_error.title", {
cardType:
cardType?.charAt(0)?.toUpperCase() + cardType?.slice(1),
})}
</p>
<p className={styles.description}>
{translate("payment_modal.card_type_error.description")}
</p>
</div>
</div>
)}
<div className={`${styles.formRow} ${styles.cardNumberRow}`}>
<div className={styles.cardNumberLabelContainer}>
<label htmlFor="card-number">
{translate("payment_modal.card_number")}
</label>
<svg
width="40"
height="25"
viewBox="0 0 40 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.9286 21.5352C17.8178 23.3566 15.0797 24.4563 12.0879 24.4563C5.41189 24.4563 0 18.9816 0 12.2282C0 5.47469 5.41189 0 12.0879 0C15.0797 0 17.8178 1.09961 19.9286 2.92118C22.0394 1.09961 24.7774 0 27.7694 0C34.4453 0 39.8571 5.47469 39.8571 12.2282C39.8571 18.9816 34.4453 24.4563 27.7694 24.4563C24.7774 24.4563 22.0394 23.3566 19.9286 21.5352Z"
fill="#ED0006"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.9286 21.5352C22.5276 19.2923 24.1757 15.9549 24.1757 12.2282C24.1757 8.50135 22.5276 5.16398 19.9286 2.92118C22.0394 1.09961 24.7774 0 27.7694 0C34.4453 0 39.8572 5.47469 39.8572 12.2282C39.8572 18.9816 34.4453 24.4563 27.7694 24.4563C24.7774 24.4563 22.0394 23.3566 19.9286 21.5352Z"
fill="#F9A000"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.9287 2.92114C22.5277 5.16404 24.1758 8.50132 24.1758 12.2281C24.1758 15.9549 22.5277 19.2922 19.9287 21.535C17.3297 19.2922 15.6817 15.9549 15.6817 12.2281C15.6817 8.50132 17.3297 5.16404 19.9287 2.92114Z"
fill="#FF5E00"
/>
</svg>
</div>
<div
id="card-number"
className={`${styles.fieldContainer} ${styles.cardNumber} ${
formValidation.ccnumber.message || isCardTypeError
? styles.invalid
: ""
} ${formValidation.ccnumber.isValid ? styles.valid : ""}`}
/>
{formValidation.ccnumber.message && (
<div className={styles.errorMessage}>
{formValidation.ccnumber.message}
</div>
)}
</div>
<div className={styles.formGroup}>
<div className={styles.formRow}>
<label htmlFor="card-expiry">
{translate("payment_modal.expiration_date")}
</label>
<div
id="card-expiry"
className={`${styles.fieldContainer} ${styles.cardExpiry} ${
formValidation.ccexp.message ? styles.invalid : ""
} ${formValidation.ccexp.isValid ? styles.valid : ""}`}
/>
{formValidation.ccexp.message && (
<div className={styles.errorMessage}>
{formValidation.ccexp.message}
</div>
)}
</div>
<div className={styles.formRow} style={{ marginLeft: "auto" }}>
<label htmlFor="card-cvv">{translate("payment_modal.cvv")}</label>
<div
id="card-cvv"
className={`${styles.fieldContainer} ${styles.cardCvv} ${
formValidation.cvv.message ? styles.invalid : ""
} ${formValidation.cvv.isValid ? styles.valid : ""}`}
/>
{formValidation.cvv.message && (
<div className={styles.errorMessage}>
{formValidation.cvv.message}
</div>
)}
</div>
</div>
{/* <AddressFields
fields={address.fields}
errors={address.errors}
onChange={address.handleChange}
countryList={address.countryList}
/> */}
</div>
{isNewPaymentButton && payButtonClicked && !isFormValid && (
<p className={styles.errorMessage} style={{ marginBottom: "16px" }}>
{translate("payment_modal.form_error")}
</p>
)}
<SecurityPayments />
<MainButton
color="blue"
// disabled={isLoading || !isFormValid}
disabled={isNewPaymentButton ? isLoading : isLoading || !isFormValid}
id="submit"
className={styles.button}
onClick={handleSubmit}
>
<img src="/payment-form/lock.svg" alt="Secure" />
<span>
{isLoading
? translate("payment_modal.processing")
: translate("payment_modal.pay_now")}
</span>
</MainButton>
</form>
);
}