'use client'; import { useState, useEffect } from 'react'; import { fetchApi } from '@/lib/utils/client'; import useAuth from '@/hooks/useAuth'; import { DanalCreateOrderRequest, PaymentMethodType } from '@/types/request/payment/charge'; import { DanalCreateOrderResponse } from '@/types/response/payment/charge'; import CreditCardIcon from '@/public/icons/payment/credit-card.svg'; import KakaoIcon from '@/public/icons/payment/kakao.svg'; import NaverIcon from '@/public/icons/payment/naver.svg'; import BankIcon from '@/public/icons/payment/bank.svg'; import PhoneIcon from '@/public/icons/payment/phone.svg'; import { Landmark as VBankIcon } from 'lucide-react'; type PaymentMethodOption = { value: PaymentMethodType; label: string; danalMethod: string; danalKey: string; Icon: React.ComponentType>; }; const PAYMENT_METHODS: PaymentMethodOption[] = [ { value: 'Card', label: '신용카드', danalMethod: 'CARD', danalKey: 'card', Icon: CreditCardIcon }, { value: 'KakaoPay', label: '카카오페이', danalMethod: 'KAKAOPAY', danalKey: 'kakaoPay', Icon: KakaoIcon }, { value: 'NaverPay', label: '네이버페이', danalMethod: 'NAVERPAY', danalKey: 'naverPay', Icon: NaverIcon }, { value: 'Transfer', label: '계좌이체', danalMethod: 'TRANSFER', danalKey: 'transfer', Icon: BankIcon }, { value: 'Mobile', label: '휴대폰', danalMethod: 'MOBILE', danalKey: 'mobile', Icon: PhoneIcon }, { value: 'VirtualAccount', label: '가상계좌', danalMethod: 'VIRTUAL_ACCOUNT', danalKey: 'virtualAccount', Icon: VBankIcon }, ]; // 결제수단별 다날 SDK methods 설정 const METHOD_CONFIGS: Record = { card: {}, kakaoPay: {}, naverPay: {}, payco: {}, transfer: {}, mobile: { itemCode: '1270000000', itemType: '1' }, virtualAccount: { notiUrl: `${process.env.NEXT_PUBLIC_API_URL}/api/payment/noti/vaccount` } }; const QUICK_AMOUNTS = [10000, 50000, 100000, 1000000]; export default function ChargePage() { const [amount, setAmount] = useState(0); const [paymentMethod, setPaymentMethod] = useState('Card'); const [loading, setLoading] = useState(false); const [isPopup, setIsPopup] = useState(false); const { member, loginCheck } = useAuth(); useEffect(() => { setIsPopup(!!window.opener); }, []); if (!member || !loginCheck()) { return null; } const handleAmountChange = (value: string) => { const num = parseInt(value.replace(/[^0-9]/g, ''), 10); setAmount(isNaN(num) ? 0 : num); }; const addAmount = (add: number) => { setAmount(prev => prev + add); }; const vatAmount = Math.round(amount / 11); const pointAmount = amount; const handleSubmit = async () => { if (amount < 1000) { alert('최소 충전 금액은 1,000원입니다.'); return; } setLoading(true); try { const res = await fetchApi('/api/payment/order', { method: 'POST', body: { amount, paymentMethod } as DanalCreateOrderRequest }); if (!res.data) { alert(res.message || '주문 생성에 실패했습니다.'); return setLoading(false); } const order = res.data; const selected = PAYMENT_METHODS.find(m => m.value === paymentMethod)!; const { loadDanalPaymentsSDK } = await import('@danalpay/javascript-sdk'); const danalPayments = await loadDanalPaymentsSDK({ clientKey: order.clientKey }); // eslint-disable-next-line @typescript-eslint/no-explicit-any const paymentParams: any = { paymentsMethod: selected.danalMethod, methods: { [selected.danalKey]: METHOD_CONFIGS[selected.danalKey] }, orderName: `DPOT ${pointAmount.toLocaleString()}(P) 충전`, amount: order.amount, merchantId: order.merchantID, orderId: order.orderID, userId: member.id, userEmail: member.email, userName: member.name, successUrl: order.successUrl, failUrl: order.failUrl }; danalPayments.requestPayment(paymentParams); } catch (e) { console.error('결제 요청 실패:', e); alert('결제 요청에 실패했습니다.'); setLoading(false); } }; return (

포인트 충전

{isPopup && ( )}
0 ? amount.toLocaleString() : ''} onChange={e => handleAmountChange(e.target.value)} placeholder="0" inputMode="numeric" autoFocus />
{QUICK_AMOUNTS.map(v => ( ))}
{PAYMENT_METHODS.map(m => ( ))}
충전 (P) {pointAmount.toLocaleString()} P
부가세 (10%) {vatAmount.toLocaleString()} 원
총 결제 금액 {amount.toLocaleString()} 원
); }