+97
-51
@@ -14,8 +14,9 @@ interface PaymentModalProps {
|
||||
export default function PaymentModal({ album, onClose, onSuccess }: PaymentModalProps) {
|
||||
const [cardNumber, setCardNumber] = useState('');
|
||||
const [cardName, setCardName] = useState('');
|
||||
const [expiry, setExpiry] = useState('');
|
||||
const [cvv, setCvv] = useState('');
|
||||
const [phoneNumber, setPhoneNumber] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [txReceipt, setTxReceipt] = useState('');
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@@ -25,12 +26,11 @@ export default function PaymentModal({ album, onClose, onSuccess }: PaymentModal
|
||||
return groups ? groups.join(' ') : numbers;
|
||||
};
|
||||
|
||||
const formatExpiry = (value: string) => {
|
||||
const formatPhoneNumber = (value: string) => {
|
||||
const numbers = value.replace(/\D/g, '');
|
||||
if (numbers.length >= 2) {
|
||||
return numbers.slice(0, 2) + '/' + numbers.slice(2, 4);
|
||||
}
|
||||
return numbers;
|
||||
if (numbers.length <= 3) return numbers;
|
||||
if (numbers.length <= 6) return `(${numbers.slice(0, 3)}) ${numbers.slice(3)}`;
|
||||
return `(${numbers.slice(0, 3)}) ${numbers.slice(3, 6)}-${numbers.slice(6, 10)}`;
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@@ -44,32 +44,60 @@ export default function PaymentModal({ album, onClose, onSuccess }: PaymentModal
|
||||
}
|
||||
|
||||
if (!cardName.trim()) {
|
||||
setError('Card name is required');
|
||||
setError('Name is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (expiry.length !== 5) {
|
||||
setError('Invalid expiry date');
|
||||
if (phoneNumber.replace(/\D/g, '').length < 10) {
|
||||
setError('Invalid phone number');
|
||||
return;
|
||||
}
|
||||
|
||||
if (cvv.length !== 3 && cvv.length !== 4) {
|
||||
setError('Invalid CVV');
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
setError('Invalid email address');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!txReceipt.trim()) {
|
||||
setError('Transaction receipt is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!album) return;
|
||||
|
||||
setProcessing(true);
|
||||
|
||||
// Simulate payment processing
|
||||
setTimeout(() => {
|
||||
// Generate a mock transaction ID
|
||||
const transactionId = 'TXN-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9).toUpperCase();
|
||||
try {
|
||||
// Use the provided transaction receipt as the ID
|
||||
const transactionId = txReceipt.trim() || 'TXN-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9).toUpperCase();
|
||||
|
||||
// Create purchase via API
|
||||
const response = await fetch('/api/purchases', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
albumId: album.id,
|
||||
transactionId,
|
||||
customerName: cardName.trim(),
|
||||
email: email.trim(),
|
||||
phoneNumber: phoneNumber,
|
||||
txReceipt: txReceipt.trim(),
|
||||
purchaseDate: new Date().getTime(),
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
throw new Error(data.error || 'Failed to process purchase');
|
||||
}
|
||||
|
||||
setProcessing(false);
|
||||
if (album) {
|
||||
onSuccess(album.id, transactionId);
|
||||
}
|
||||
}, 2000);
|
||||
onSuccess(album.id, transactionId);
|
||||
} catch (err: any) {
|
||||
setProcessing(false);
|
||||
setError(err.message || 'Failed to process payment');
|
||||
}
|
||||
};
|
||||
|
||||
if (!album) return null;
|
||||
@@ -136,46 +164,64 @@ export default function PaymentModal({ album, onClose, onSuccess }: PaymentModal
|
||||
{/* Card Name */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Name on Card
|
||||
Full Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={cardName}
|
||||
onChange={(e) => setCardName(e.target.value.toUpperCase())}
|
||||
placeholder="JOHN DOE"
|
||||
onChange={(e) => setCardName(e.target.value)}
|
||||
placeholder="John Doe"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Expiry and CVV */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Expiry Date
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={expiry}
|
||||
onChange={(e) => setExpiry(formatExpiry(e.target.value))}
|
||||
placeholder="MM/YY"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
CVV
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={cvv}
|
||||
onChange={(e) => setCvv(e.target.value.replace(/\D/g, '').slice(0, 4))}
|
||||
placeholder="123"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{/* Phone Number */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Phone Number
|
||||
</label>
|
||||
<input
|
||||
type="tel"
|
||||
value={phoneNumber}
|
||||
onChange={(e) => {
|
||||
const formatted = formatPhoneNumber(e.target.value);
|
||||
setPhoneNumber(formatted);
|
||||
}}
|
||||
placeholder="(123) 456-7890"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Email Address
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="john@example.com"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Transaction Receipt */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Transaction Receipt / ID
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={txReceipt}
|
||||
onChange={(e) => setTxReceipt(e.target.value)}
|
||||
placeholder="TXN-123456789"
|
||||
className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg focus:border-accent-cyan focus:outline-none focus:ring-2 focus:ring-accent-cyan/50 text-white placeholder-gray-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
|
||||
Reference in New Issue
Block a user