2026-04-10 15:31:59 +04:00

183 lines
6.3 KiB
TypeScript

'use client';
import { useState, useCallback } from 'react';
import { orderStore, type PaymentInfo } from '@/store/useOrderStore';
const inputStyle: React.CSSProperties = {
width: '100%',
padding: '0.6rem 0.75rem',
borderRadius: '0.375rem',
border: '1px solid rgba(0, 0, 0, 0.08)',
background: 'rgba(255, 255, 255, 0.8)',
color: '#1a1a2e',
fontSize: '0.8rem',
outline: 'none',
transition: 'border-color 0.2s ease',
};
const labelStyle: React.CSSProperties = {
fontSize: '0.7rem',
fontWeight: 500,
color: '#94a3b8',
marginBottom: '0.3rem',
display: 'block',
};
const errorStyle: React.CSSProperties = {
fontSize: '0.65rem',
color: '#ef4444',
marginTop: '0.2rem',
};
interface FormErrors {
[key: string]: string;
}
function formatCardNumber(value: string): string {
const digits = value.replace(/\D/g, '').slice(0, 16);
return digits.replace(/(\d{4})(?=\d)/g, '$1 ');
}
function formatExpiry(value: string): string {
const digits = value.replace(/\D/g, '').slice(0, 4);
if (digits.length > 2) {
return `${digits.slice(0, 2)}/${digits.slice(2)}`;
}
return digits;
}
export function PaymentStep() {
const [form, setForm] = useState<PaymentInfo>({
cardNumber: '',
expiry: '',
cvv: '',
nameOnCard: '',
});
const [errors, setErrors] = useState<FormErrors>({});
const handleChange = useCallback((field: keyof PaymentInfo, value: string) => {
let processed = value;
if (field === 'cardNumber') processed = formatCardNumber(value);
if (field === 'expiry') processed = formatExpiry(value);
if (field === 'cvv') processed = value.replace(/\D/g, '').slice(0, 3);
setForm((prev) => ({ ...prev, [field]: processed }));
setErrors((prev) => {
const next = { ...prev };
delete next[field];
return next;
});
}, []);
const validate = (): boolean => {
const errs: FormErrors = {};
const digits = form.cardNumber.replace(/\s/g, '');
if (digits.length < 16) errs.cardNumber = 'Enter a valid 16-digit card number';
if (form.expiry.length < 5) errs.expiry = 'Enter a valid expiry (MM/YY)';
if (form.cvv.length < 3) errs.cvv = 'Enter a valid 3-digit CVV';
if (!form.nameOnCard.trim()) errs.nameOnCard = 'Name on card is required';
setErrors(errs);
return Object.keys(errs).length === 0;
};
const handleSubmit = () => {
if (!validate()) return;
orderStore.getState().setPayment(form);
orderStore.getState().setStep('review');
};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<h3 style={{ fontSize: '1rem', fontWeight: 600, color: '#1a1a2e', margin: 0 }}>
Payment Details
</h3>
<div style={{
padding: '0.6rem 0.75rem',
borderRadius: '0.375rem',
background: 'rgba(245, 158, 11, 0.06)',
border: '1px solid rgba(245, 158, 11, 0.15)',
fontSize: '0.7rem',
color: '#d97706',
}}>
This is a demo checkout. No real payment will be processed.
</div>
<div>
<label style={labelStyle}>Card Number</label>
<input
type="text"
value={form.cardNumber}
onChange={(e) => handleChange('cardNumber', e.target.value)}
placeholder="4242 4242 4242 4242"
style={{ ...inputStyle, fontFamily: 'monospace', letterSpacing: '0.1em', borderColor: errors.cardNumber ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)' }}
onFocus={(e) => { e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.5)'; }}
onBlur={(e) => { e.currentTarget.style.borderColor = errors.cardNumber ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)'; }}
/>
{errors.cardNumber && <div style={errorStyle}>{errors.cardNumber}</div>}
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
<div>
<label style={labelStyle}>Expiry Date</label>
<input
type="text"
value={form.expiry}
onChange={(e) => handleChange('expiry', e.target.value)}
placeholder="MM/YY"
style={{ ...inputStyle, fontFamily: 'monospace', borderColor: errors.expiry ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)' }}
onFocus={(e) => { e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.5)'; }}
onBlur={(e) => { e.currentTarget.style.borderColor = errors.expiry ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)'; }}
/>
{errors.expiry && <div style={errorStyle}>{errors.expiry}</div>}
</div>
<div>
<label style={labelStyle}>CVV</label>
<input
type="text"
value={form.cvv}
onChange={(e) => handleChange('cvv', e.target.value)}
placeholder="123"
style={{ ...inputStyle, fontFamily: 'monospace', borderColor: errors.cvv ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)' }}
onFocus={(e) => { e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.5)'; }}
onBlur={(e) => { e.currentTarget.style.borderColor = errors.cvv ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)'; }}
/>
{errors.cvv && <div style={errorStyle}>{errors.cvv}</div>}
</div>
</div>
<div>
<label style={labelStyle}>Name on Card</label>
<input
type="text"
value={form.nameOnCard}
onChange={(e) => handleChange('nameOnCard', e.target.value)}
placeholder="John Doe"
style={{ ...inputStyle, borderColor: errors.nameOnCard ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)' }}
onFocus={(e) => { e.currentTarget.style.borderColor = 'rgba(59, 130, 246, 0.5)'; }}
onBlur={(e) => { e.currentTarget.style.borderColor = errors.nameOnCard ? 'rgba(239, 68, 68, 0.4)' : 'rgba(0, 0, 0, 0.08)'; }}
/>
{errors.nameOnCard && <div style={errorStyle}>{errors.nameOnCard}</div>}
</div>
<button
onClick={handleSubmit}
style={{
marginTop: '0.5rem',
padding: '0.75rem',
borderRadius: '0.375rem',
border: '1px solid rgba(59, 130, 246, 0.5)',
background: 'rgba(59, 130, 246, 0.08)',
color: '#2563eb',
cursor: 'pointer',
fontSize: '0.85rem',
fontWeight: 600,
transition: 'all 0.2s ease',
}}
>
Review Order
</button>
</div>
);
}