Files
jaengseung-made/app/components/PurchaseAgreementModal.tsx
gahusb 8da844bb40 fix: 배포 전 보강 — HMAC 타이밍 안전 비교 + 계좌 업데이트 + 고아 정리
- lib/admin-auth: createHmac 비교를 timingSafeEqual로 교체 (타이밍 공격 방어)
- PurchaseAgreementModal: 입금 계좌 케이뱅크 100-116-337157 박재오
- /legal/refund: 구독 서비스 설명에서 삭제된 로또/주식 언급 제거
- app/landing/: 삭제된 서비스 참조만 남은 고아 디렉토리 제거

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 01:13:00 +09:00

186 lines
6.7 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
interface Props {
isOpen: boolean;
onClose: () => void;
productName: string;
price: string;
bankInfo?: {
bank: string;
account: string;
holder: string;
};
}
const DEFAULT_BANK = {
bank: '케이뱅크',
account: '100-116-337157',
holder: '박재오',
};
export default function PurchaseAgreementModal({
isOpen,
onClose,
productName,
price,
bankInfo = DEFAULT_BANK,
}: Props) {
const [agreed, setAgreed] = useState(false);
const [email, setEmail] = useState('');
const [sent, setSent] = useState(false);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!isOpen) {
setAgreed(false);
setEmail('');
setSent(false);
}
}, [isOpen]);
if (!isOpen) return null;
const handleSubmit = async () => {
if (!agreed || !email) return;
setLoading(true);
try {
await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
service: `구매 신청: ${productName}`,
name: email.split('@')[0],
email,
phone: '',
message: `상품: ${productName} (${price})\n입금 대기 중. 입금 확인 후 이메일로 상품 전달 예정.`,
}),
});
setSent(true);
} catch (e) {
alert('신청 전송 실패. 다시 시도해주세요.');
} finally {
setLoading(false);
}
};
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm"
onClick={onClose}
>
<div
className="bg-white rounded-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="bg-gradient-to-br from-slate-900 to-slate-800 px-6 py-5 text-white">
<h3 className="font-extrabold text-lg">{productName}</h3>
<p className="text-slate-300 text-sm mt-0.5">{price}</p>
</div>
{sent ? (
<div className="p-8 text-center">
<div className="text-5xl mb-4"></div>
<h4 className="text-lg font-extrabold text-slate-900 mb-2"> </h4>
<p className="text-sm text-slate-600 leading-relaxed">
<strong>24 </strong> .
</p>
<div className="mt-5 bg-slate-50 border border-slate-200 rounded-xl p-4 text-left">
<p className="text-xs text-slate-500 mb-1"> </p>
<p className="font-mono text-sm text-slate-900">
{bankInfo.bank} {bankInfo.account}
</p>
<p className="text-xs text-slate-600 mt-1"> {bankInfo.holder}</p>
</div>
<button
onClick={onClose}
className="mt-6 w-full bg-slate-900 text-white py-3 rounded-xl font-bold text-sm hover:bg-slate-800 transition"
>
</button>
</div>
) : (
<div className="p-6 space-y-5">
<div>
<label className="block text-xs font-bold text-slate-700 mb-2">
( )
</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="your@email.com"
className="w-full px-4 py-3 border border-slate-300 rounded-xl text-sm focus:outline-none focus:border-violet-500"
/>
</div>
<div className="bg-amber-50 border border-amber-200 rounded-xl p-4 text-xs text-slate-700 leading-relaxed">
<p className="font-bold text-amber-900 mb-2">📌 </p>
<ul className="space-y-1.5 list-disc pl-4">
<li>
<strong> </strong>, ( )
17 2 5 () <strong></strong>.
</li>
<li>
<strong> · </strong> .
</li>
<li>
· <strong> </strong>.
</li>
<li>
{' '}
<Link href="/legal/refund" className="underline text-amber-900 font-bold" target="_blank">
</Link>{' '}
.
</li>
</ul>
</div>
<label className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
className="mt-0.5 w-4 h-4 accent-violet-600"
/>
<span className="text-sm text-slate-700 leading-relaxed">
, {' '}
<strong className="text-slate-900"></strong>. ()
</span>
</label>
<div className="bg-slate-50 border border-slate-200 rounded-xl p-4 text-xs">
<p className="font-bold text-slate-900 mb-1">💳 방법: 계좌이체</p>
<p className="font-mono text-slate-700">
{bankInfo.bank} {bankInfo.account} ({bankInfo.holder})
</p>
<p className="text-slate-500 mt-2">
24 .
</p>
</div>
<div className="flex gap-2">
<button
onClick={onClose}
className="flex-1 py-3 border border-slate-300 rounded-xl text-sm font-bold text-slate-700 hover:bg-slate-50"
>
</button>
<button
onClick={handleSubmit}
disabled={!agreed || !email || loading}
className="flex-[2] py-3 bg-violet-600 hover:bg-violet-500 disabled:bg-slate-300 disabled:cursor-not-allowed text-white rounded-xl text-sm font-bold transition"
>
{loading ? '전송 중...' : '구매 신청'}
</button>
</div>
</div>
)}
</div>
</div>
);
}