145 lines
4.1 KiB
TypeScript
145 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { usePaymentLaunchFlow } from "@/app/_hooks/use-payment-launch-flow";
|
|
import type { TipCoffeeType } from "@/lib/tip/tip_coffee";
|
|
import {
|
|
usePaymentDispatch,
|
|
usePaymentState,
|
|
} from "@/stores/payment/payment-context";
|
|
import { Logger } from "@/utils";
|
|
|
|
import { LazyStripePaymentDialog } from "../subscription/components/lazy-stripe-payment-dialog";
|
|
import { stripePaymentDialogStyles as dialogStyles } from "../subscription/components/stripe-payment-dialog.styles";
|
|
import styles from "./tip-screen.module.css";
|
|
|
|
const log = new Logger("TipCheckoutButton");
|
|
|
|
export interface TipCheckoutButtonProps {
|
|
coffeeType: TipCoffeeType;
|
|
disabled?: boolean;
|
|
isAuthLoading?: boolean;
|
|
onOrder: () => void;
|
|
returnPath: string;
|
|
}
|
|
|
|
export function TipCheckoutButton({
|
|
coffeeType,
|
|
disabled = false,
|
|
isAuthLoading = false,
|
|
onOrder,
|
|
returnPath,
|
|
}: TipCheckoutButtonProps) {
|
|
const payment = usePaymentState();
|
|
const paymentDispatch = usePaymentDispatch();
|
|
const paymentLaunch = usePaymentLaunchFlow({
|
|
log,
|
|
logScope: "tip-checkout",
|
|
payment,
|
|
paymentDispatch,
|
|
subscriptionType: "tip",
|
|
tipCoffeeType: coffeeType,
|
|
});
|
|
|
|
const isLoading =
|
|
isAuthLoading || payment.isCreatingOrder || payment.isPollingOrder;
|
|
const label = payment.isPollingOrder
|
|
? "Processing payment..."
|
|
: payment.isCreatingOrder
|
|
? "Creating order..."
|
|
: payment.isPaid
|
|
? "Thanks for the coffee"
|
|
: "Order and Buy";
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
type="button"
|
|
data-analytics-key="tip.checkout"
|
|
data-analytics-label="Buy coffee tip"
|
|
className={styles.checkoutButton}
|
|
disabled={disabled || isLoading}
|
|
onClick={onOrder}
|
|
>
|
|
{label}
|
|
</button>
|
|
{payment.errorMessage ? (
|
|
<p className={styles.checkoutError} role="alert">
|
|
{payment.errorMessage}
|
|
</p>
|
|
) : null}
|
|
{paymentLaunch.shouldShowEzpayConfirmDialog ? (
|
|
<EzpayRedirectConfirmDialog
|
|
orderId={payment.currentOrderId ?? ""}
|
|
isConfirming={paymentLaunch.isConfirmingEzpay}
|
|
onCancel={paymentLaunch.handleEzpayCancel}
|
|
onConfirm={paymentLaunch.handleEzpayConfirm}
|
|
/>
|
|
) : null}
|
|
{paymentLaunch.shouldShowStripeDialog && paymentLaunch.stripeClientSecret ? (
|
|
<LazyStripePaymentDialog
|
|
clientSecret={paymentLaunch.stripeClientSecret}
|
|
returnPath={returnPath}
|
|
onClose={paymentLaunch.handleStripeClose}
|
|
onConfirmed={paymentLaunch.handleStripeConfirmed}
|
|
/>
|
|
) : null}
|
|
</>
|
|
);
|
|
}
|
|
|
|
interface EzpayRedirectConfirmDialogProps {
|
|
orderId: string;
|
|
isConfirming: boolean;
|
|
onCancel: () => void;
|
|
onConfirm: () => void;
|
|
}
|
|
|
|
function EzpayRedirectConfirmDialog({
|
|
orderId,
|
|
isConfirming,
|
|
onCancel,
|
|
onConfirm,
|
|
}: EzpayRedirectConfirmDialogProps) {
|
|
return (
|
|
<div
|
|
className={dialogStyles.overlay}
|
|
role="alertdialog"
|
|
aria-modal="true"
|
|
aria-labelledby="tip-ezpay-redirect-title"
|
|
>
|
|
<div className={dialogStyles.dialog}>
|
|
<div className={dialogStyles.header}>
|
|
<h2 id="tip-ezpay-redirect-title" className={dialogStyles.title}>
|
|
Continue to GCash?
|
|
</h2>
|
|
<p className={dialogStyles.content}>
|
|
Your coffee order is ready. Continue to GCash to finish the
|
|
payment.
|
|
</p>
|
|
<p className={dialogStyles.content}>Order No. {orderId}</p>
|
|
</div>
|
|
<div className={dialogStyles.actions}>
|
|
<button
|
|
type="button"
|
|
className={`${dialogStyles.button} ${dialogStyles.secondary}`}
|
|
disabled={isConfirming}
|
|
onClick={onCancel}
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="button"
|
|
data-analytics-key="tip.external_checkout"
|
|
data-analytics-label="Continue to external checkout"
|
|
className={`${dialogStyles.button} ${dialogStyles.primary}`}
|
|
disabled={isConfirming}
|
|
onClick={onConfirm}
|
|
>
|
|
{isConfirming ? "Opening..." : "Continue"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|