import { useLocaleContext } from '@arcblock/ux/lib/Locale/context'; import { TextField, Button, Alert, Box, InputAdornment } from '@mui/material'; import { Add } from '@mui/icons-material'; import { useState } from 'react'; import LoadingButton from './loading-button'; import api from '../libs/api'; import { usePaymentContext } from '../contexts/payment'; export interface AppliedPromoCode { id: string; code: string; discount_amount?: string; } interface PromotionCodeProps { checkoutSessionId: string; initialAppliedCodes?: AppliedPromoCode[]; disabled?: boolean; className?: string; placeholder?: string; currencyId: string; onUpdate?: (data: { appliedCodes: AppliedPromoCode[]; discountAmount: string }) => void; } export default function PromotionCode({ checkoutSessionId, initialAppliedCodes = [], disabled = false, className = '', placeholder = '', onUpdate = undefined, currencyId, }: PromotionCodeProps) { const { t } = useLocaleContext(); const [showInput, setShowInput] = useState(false); const [code, setCode] = useState(''); const [error, setError] = useState(''); const [applying, setApplying] = useState(false); const [appliedCodes, setAppliedCodes] = useState(initialAppliedCodes); const { session, paymentState } = usePaymentContext(); const handleLoginCheck = () => { if (!session.user) { session?.login(() => { handleApply(); }); } else { handleApply(); } }; const handleApply = async () => { if (!code.trim()) return; // Prevent applying promotion during payment process if (paymentState.paying || paymentState.stripePaying) { return; } setApplying(true); setError(''); try { const response = await api.post(`/api/checkout-sessions/${checkoutSessionId}/apply-promotion`, { promotion_code: code.trim(), currency_id: currencyId, }); const discounts = response.data.discounts || []; const appliedDiscount = discounts[0]; if (appliedDiscount) { const newCode: AppliedPromoCode = { id: appliedDiscount.promotion_code || appliedDiscount.coupon, code: code.trim(), discount_amount: appliedDiscount.discount_amount, }; setAppliedCodes([newCode]); setCode(''); setShowInput(false); onUpdate?.({ appliedCodes: [newCode], discountAmount: appliedDiscount.discount_amount, }); } } catch (err: any) { const errorMessage = err.response?.data?.error || err.message; setError(errorMessage); } finally { setApplying(false); } }; const handleKeyPress = (event: React.KeyboardEvent) => { if (event.key === 'Enter' && !applying && code.trim()) { handleLoginCheck(); } }; const isPaymentInProgress = paymentState.paying || paymentState.stripePaying; return ( {/* Input field or add button - only show if no codes applied */} {appliedCodes.length === 0 && !disabled && !isPaymentInProgress && (showInput ? ( { if (!code.trim()) { setShowInput(false); } }}> setCode(e.target.value)} onKeyPress={handleKeyPress} placeholder={placeholder || t('payment.checkout.promotion.placeholder')} variant="outlined" size="small" disabled={applying} autoFocus slotProps={{ input: { endAdornment: ( {t('payment.checkout.promotion.apply')} ), }, }} sx={{ '& .MuiOutlinedInput-root': { pr: 1, }, }} /> {error && ( {error} )} ) : ( ))} ); }