storenest-commerce
Version:
Complete e-commerce SDK for Storenest platform with React components, multi-language support, secure checkout, and enterprise-grade security
711 lines • 61.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckoutBox = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const checkout_1 = require("../checkout");
const utils_1 = require("../utils");
// Ensure this component is only used client-side
const isClient = typeof window !== 'undefined';
// Create a safe wrapper that prevents SSR issues
const createSafeComponent = () => {
if (!isClient) {
return () => ((0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '400px',
background: '#f8f9fa',
borderRadius: '8px'
}, children: (0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: '24px', marginBottom: '16px' }, children: "\uD83D\uDD04" }), (0, jsx_runtime_1.jsx)("div", { children: "Loading checkout component..." })] }) }));
}
// Only import React hooks when on client side
const React = require('react');
const { useState, useEffect } = React;
return function CheckoutBoxClient({ config = {}, onSuccess, onError, onCancel }) {
const [checkout] = useState(() => new (require('../checkout').StorenestCheckout)(config));
const [loading, setLoading] = useState(false);
const [currentStep, setCurrentStep] = useState('shipping');
const [session, setSession] = useState(null);
const [shippingMethods, setShippingMethods] = useState([]);
const [paymentMethods, setPaymentMethods] = useState([]);
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
phone: '',
address: '',
city: '',
state: '',
zipCode: '',
country: 'US',
notes: '',
marketingConsent: false
});
const [errors, setErrors] = useState({});
const [orderSummary, setOrderSummary] = useState({
subtotal: 0,
shipping: 0,
tax: 0,
total: 0,
currency: config.currency || 'EUR'
});
// Initialize checkout session
useEffect(() => {
const initCheckout = async () => {
try {
setLoading(true);
const { getOrCreateUserId } = require('../utils');
const userId = getOrCreateUserId();
if (!userId) {
throw new Error('User ID not found');
}
const response = await fetch('/api/checkout/init', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cartId: userId })
});
if (!response.ok) {
throw new Error('Failed to create checkout session');
}
const sessionData = await response.json();
setSession(sessionData);
// Load shipping and payment methods
await loadShippingMethods();
await loadPaymentMethods();
}
catch (err) {
onError?.(err.message);
}
finally {
setLoading(false);
}
};
initCheckout();
}, []);
const loadShippingMethods = async () => {
try {
const address = {
firstName: formData.firstName,
lastName: formData.lastName,
email: formData.email,
address: formData.address,
city: formData.city,
state: formData.state,
zipCode: formData.zipCode,
country: formData.country
};
const response = await fetch('/api/checkout/shipping-methods', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ address })
});
if (response.ok) {
const methods = await response.json();
setShippingMethods(methods);
// Auto-select first method
if (methods.length > 0 && !formData.shippingMethodId) {
setFormData(prev => ({ ...prev, shippingMethodId: methods[0].id }));
updateOrderSummary(methods[0].price);
}
}
}
catch (err) {
console.error('Failed to load shipping methods:', err);
}
};
const loadPaymentMethods = async () => {
try {
const response = await fetch('/api/checkout/payment-methods', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
const methods = await response.json();
setPaymentMethods(methods);
// Auto-select first method
if (methods.length > 0 && !formData.paymentMethodId) {
setFormData(prev => ({ ...prev, paymentMethodId: methods[0].id }));
}
}
}
catch (err) {
console.error('Failed to load payment methods:', err);
}
};
const updateOrderSummary = (shippingCost) => {
const subtotal = 80; // Mock subtotal - in real app, get from cart
const tax = subtotal * 0.08; // 8% tax
const total = subtotal + shippingCost + tax;
setOrderSummary({
subtotal,
shipping: shippingCost,
tax,
total,
currency: config.currency || 'EUR'
});
};
const validateForm = () => {
const newErrors = {};
// Required fields
if (!formData.firstName)
newErrors.firstName = 'First name is required';
if (!formData.lastName)
newErrors.lastName = 'Last name is required';
if (!formData.email)
newErrors.email = 'Email is required';
if (!formData.address)
newErrors.address = 'Address is required';
if (!formData.city)
newErrors.city = 'City is required';
if (!formData.zipCode)
newErrors.zipCode = 'Zip code is required';
if (!formData.country)
newErrors.country = 'Country is required';
// Email validation
if (formData.email && !/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Please enter a valid email address';
}
// Payment method validation
if (!formData.paymentMethodId) {
newErrors.paymentMethod = 'Please select a payment method';
}
// Shipping method validation
if (!formData.shippingMethodId) {
newErrors.shippingMethod = 'Please select a shipping method';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleInputChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }));
// Clear error when user starts typing
if (errors[field]) {
setErrors(prev => ({ ...prev, [field]: '' }));
}
};
const handleShippingMethodChange = (methodId) => {
const method = shippingMethods.find(m => m.id === methodId);
setFormData(prev => ({ ...prev, shippingMethodId: methodId }));
if (method) {
updateOrderSummary(method.price);
}
};
const handleNextStep = () => {
if (validateForm()) {
if (currentStep === 'shipping') {
setCurrentStep('payment');
}
else if (currentStep === 'payment') {
setCurrentStep('review');
}
}
};
const handlePreviousStep = () => {
if (currentStep === 'payment') {
setCurrentStep('shipping');
}
else if (currentStep === 'review') {
setCurrentStep('payment');
}
};
const handleSubmit = async () => {
if (!validateForm())
return;
try {
setLoading(true);
// In a real implementation, this would call the backend to process the order
const orderId = `order_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
// Simulate processing delay
await new Promise(resolve => setTimeout(resolve, 2000));
onSuccess?.(orderId);
}
catch (err) {
onError?.(err.message);
}
finally {
setLoading(false);
}
};
const formatPrice = (amount) => {
return new Intl.NumberFormat(config.locale || 'en-US', {
style: 'currency',
currency: config.currency || 'EUR'
}).format(amount);
};
if (loading && !session) {
return ((0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '400px',
background: '#f8f9fa',
borderRadius: '8px'
}, children: (0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: '24px', marginBottom: '16px' }, children: "\uD83D\uDD04" }), (0, jsx_runtime_1.jsx)("div", { children: "Initializing checkout..." })] }) }));
}
return ((0, jsx_runtime_1.jsxs)("div", { style: {
maxWidth: '800px',
margin: '0 auto',
background: '#fff',
borderRadius: '12px',
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)',
overflow: 'hidden'
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
background: config.theme === 'modern' ? '#0070f3' : '#f8f9fa',
padding: '24px',
borderBottom: '1px solid #e1e5e9'
}, children: [(0, jsx_runtime_1.jsx)("h2", { style: {
margin: 0,
color: config.theme === 'modern' ? '#fff' : '#333',
fontSize: '24px',
fontWeight: '600'
}, children: "Secure Checkout" }), (0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'space-between',
marginTop: '16px'
}, children: ['shipping', 'payment', 'review'].map((step, index) => ((0, jsx_runtime_1.jsxs)("div", { style: {
display: 'flex',
alignItems: 'center',
color: config.theme === 'modern' ? '#fff' : '#666'
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
width: '32px',
height: '32px',
borderRadius: '50%',
background: currentStep === step ? '#fff' : 'rgba(255,255,255,0.3)',
color: currentStep === step ? '#0070f3' : '#fff',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: '600',
fontSize: '14px'
}, children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { style: { marginLeft: '8px', fontSize: '14px' }, children: step.charAt(0).toUpperCase() + step.slice(1) })] }, step))) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, padding: '32px' }, children: [currentStep === 'shipping' && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { style: { margin: '0 0 24px 0', color: '#333' }, children: "Shipping Information" }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "First Name *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.firstName, onChange: (e) => handleInputChange('firstName', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.firstName ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "First name" }), errors.firstName && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.firstName }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Last Name *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.lastName, onChange: (e) => handleInputChange('lastName', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.lastName ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Last name" }), errors.lastName && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.lastName }))] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Email Address *" }), (0, jsx_runtime_1.jsx)("input", { type: "email", value: formData.email, onChange: (e) => handleInputChange('email', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.email ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "your@email.com" }), errors.email && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.email }))] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Address *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.address, onChange: (e) => handleInputChange('address', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.address ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Street address" }), errors.address && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.address }))] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "City *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.city, onChange: (e) => handleInputChange('city', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.city ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "City" }), errors.city && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.city }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Zip Code *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.zipCode, onChange: (e) => handleInputChange('zipCode', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.zipCode ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Zip code" }), errors.zipCode && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.zipCode }))] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Country *" }), (0, jsx_runtime_1.jsxs)("select", { value: formData.country, onChange: (e) => handleInputChange('country', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.country ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, children: [(0, jsx_runtime_1.jsx)("option", { value: "US", children: "United States" }), (0, jsx_runtime_1.jsx)("option", { value: "CA", children: "Canada" }), (0, jsx_runtime_1.jsx)("option", { value: "GB", children: "United Kingdom" }), (0, jsx_runtime_1.jsx)("option", { value: "DE", children: "Germany" }), (0, jsx_runtime_1.jsx)("option", { value: "FR", children: "France" })] }), errors.country && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.country }))] }), shippingMethods.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("h4", { style: { margin: '0 0 16px 0', color: '#333' }, children: "Shipping Method" }), shippingMethods.map((method) => ((0, jsx_runtime_1.jsxs)("label", { style: {
display: 'flex',
alignItems: 'center',
padding: '16px',
border: `1px solid ${formData.shippingMethodId === method.id ? '#0070f3' : '#dee2e6'}`,
borderRadius: '6px',
marginBottom: '8px',
cursor: 'pointer',
background: formData.shippingMethodId === method.id ? '#f0f8ff' : '#fff'
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "radio", name: "shippingMethod", value: method.id, checked: formData.shippingMethodId === method.id, onChange: (e) => handleShippingMethodChange(e.target.value), style: { marginRight: '12px' } }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1 }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: '500' }, children: method.name }), (0, jsx_runtime_1.jsxs)("div", { style: { color: '#666', fontSize: '14px' }, children: [method.estimatedDays, " \u2022 ", formatPrice(method.price)] })] })] }, method.id))), errors.shippingMethod && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.shippingMethod }))] }))] })), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', justifyContent: 'space-between', marginTop: '32px' }, children: [currentStep !== 'shipping' && ((0, jsx_runtime_1.jsx)("button", { onClick: handlePreviousStep, style: {
padding: '12px 24px',
border: '1px solid #dee2e6',
background: '#fff',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '16px'
}, children: "\u2190 Previous" })), (0, jsx_runtime_1.jsx)("div", { style: { marginLeft: 'auto' }, children: currentStep === 'review' ? ((0, jsx_runtime_1.jsx)("button", { onClick: handleSubmit, disabled: loading, style: {
padding: '12px 32px',
background: loading ? '#ccc' : '#0070f3',
color: '#fff',
border: 'none',
borderRadius: '6px',
cursor: loading ? 'not-allowed' : 'pointer',
fontSize: '16px',
fontWeight: '500'
}, children: loading ? 'Processing...' : 'Place Order' })) : ((0, jsx_runtime_1.jsx)("button", { onClick: handleNextStep, style: {
padding: '12px 32px',
background: '#0070f3',
color: '#fff',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '16px',
fontWeight: '500'
}, children: "Continue \u2192" })) })] })] }), config.showOrderSummary !== false && ((0, jsx_runtime_1.jsxs)("div", { style: {
width: '300px',
background: '#f8f9fa',
padding: '24px',
borderLeft: '1px solid #e1e5e9'
}, children: [(0, jsx_runtime_1.jsx)("h3", { style: { margin: '0 0 24px 0', color: '#333' }, children: "Order Summary" }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }, children: [(0, jsx_runtime_1.jsx)("span", { children: "Subtotal" }), (0, jsx_runtime_1.jsx)("span", { children: formatPrice(orderSummary.subtotal) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }, children: [(0, jsx_runtime_1.jsx)("span", { children: "Shipping" }), (0, jsx_runtime_1.jsx)("span", { children: formatPrice(orderSummary.shipping) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }, children: [(0, jsx_runtime_1.jsx)("span", { children: "Tax" }), (0, jsx_runtime_1.jsx)("span", { children: formatPrice(orderSummary.tax) })] }), (0, jsx_runtime_1.jsxs)("div", { style: {
display: 'flex',
justifyContent: 'space-between',
paddingTop: '16px',
borderTop: '1px solid #dee2e6',
fontWeight: '600',
fontSize: '18px'
}, children: [(0, jsx_runtime_1.jsx)("span", { children: "Total" }), (0, jsx_runtime_1.jsx)("span", { children: formatPrice(orderSummary.total) })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: '14px', color: '#666', lineHeight: '1.5' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { marginBottom: '8px' }, children: "\uD83D\uDD12 Secure checkout powered by Storenest" }), (0, jsx_runtime_1.jsx)("div", { children: "Your payment information is encrypted and secure" })] })] }))] })] }));
};
};
exports.CheckoutBox = createSafeComponent();
exports.default = exports.CheckoutBox;
config ? : {
theme: 'modern' | 'classic' | 'minimal',
currency: string,
locale: string,
showOrderSummary: boolean,
enableGuestCheckout: boolean
};
onSuccess ? : (orderId) => void ;
onError ? : (error) => void ;
onCancel ? : () => void ;
const CheckoutBox = ({ config = {}, onSuccess, onError, onCancel }) => {
// Only render on client side
if (!isClient) {
return ((0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '400px',
background: '#f8f9fa',
borderRadius: '8px'
}, children: (0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: '24px', marginBottom: '16px' }, children: "\uD83D\uDD04" }), (0, jsx_runtime_1.jsx)("div", { children: "Loading checkout component..." })] }) }));
}
// Client-side only - React hooks are safe here
return (0, jsx_runtime_1.jsx)(CheckoutBoxClient, { config: config, onSuccess: onSuccess, onError: onError, onCancel: onCancel });
};
exports.CheckoutBox = CheckoutBox;
// Separate client component that uses React hooks
const CheckoutBoxClient = ({ config = {}, onSuccess, onError, onCancel }) => {
const [checkout] = (0, react_1.useState)(() => new checkout_1.StorenestCheckout(config));
const [loading, setLoading] = (0, react_1.useState)(false);
const [currentStep, setCurrentStep] = (0, react_1.useState)('shipping');
const [session, setSession] = (0, react_1.useState)(null);
const [shippingMethods, setShippingMethods] = (0, react_1.useState)([]);
const [paymentMethods, setPaymentMethods] = (0, react_1.useState)([]);
const [formData, setFormData] = (0, react_1.useState)({
firstName: '',
lastName: '',
email: '',
phone: '',
address: '',
city: '',
state: '',
zipCode: '',
country: 'US',
notes: '',
marketingConsent: false
});
const [errors, setErrors] = (0, react_1.useState)({});
const [orderSummary, setOrderSummary] = (0, react_1.useState)({
subtotal: 0,
shipping: 0,
tax: 0,
total: 0,
currency: config.currency || 'EUR'
});
// Initialize checkout session
(0, react_1.useEffect)(() => {
const initCheckout = async () => {
try {
setLoading(true);
const userId = (0, utils_1.getOrCreateUserId)();
if (!userId) {
throw new Error('User ID not found');
}
const response = await fetch('/api/checkout/init', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cartId: userId })
});
if (!response.ok) {
throw new Error('Failed to create checkout session');
}
const sessionData = await response.json();
setSession(sessionData);
// Load shipping and payment methods
await loadShippingMethods();
await loadPaymentMethods();
}
catch (err) {
onError?.(err.message);
}
finally {
setLoading(false);
}
};
initCheckout();
}, []);
const loadShippingMethods = async () => {
try {
const address = {
firstName: formData.firstName,
lastName: formData.lastName,
email: formData.email,
address: formData.address,
city: formData.city,
state: formData.state,
zipCode: formData.zipCode,
country: formData.country
};
const response = await fetch('/api/checkout/shipping-methods', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ address })
});
if (response.ok) {
const methods = await response.json();
setShippingMethods(methods);
// Auto-select first method
if (methods.length > 0 && !formData.shippingMethodId) {
setFormData(prev => ({ ...prev, shippingMethodId: methods[0].id }));
updateOrderSummary(methods[0].price);
}
}
}
catch (err) {
console.error('Failed to load shipping methods:', err);
}
};
const loadPaymentMethods = async () => {
try {
const response = await fetch('/api/checkout/payment-methods', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
const methods = await response.json();
setPaymentMethods(methods);
// Auto-select first method
if (methods.length > 0 && !formData.paymentMethodId) {
setFormData(prev => ({ ...prev, paymentMethodId: methods[0].id }));
}
}
}
catch (err) {
console.error('Failed to load payment methods:', err);
}
};
const updateOrderSummary = (shippingCost) => {
const subtotal = 80; // Mock subtotal - in real app, get from cart
const tax = subtotal * 0.08; // 8% tax
const total = subtotal + shippingCost + tax;
setOrderSummary({
subtotal,
shipping: shippingCost,
tax,
total,
currency: config.currency || 'EUR'
});
};
const validateForm = () => {
const newErrors = {};
// Required fields
if (!formData.firstName)
newErrors.firstName = 'First name is required';
if (!formData.lastName)
newErrors.lastName = 'Last name is required';
if (!formData.email)
newErrors.email = 'Email is required';
if (!formData.address)
newErrors.address = 'Address is required';
if (!formData.city)
newErrors.city = 'City is required';
if (!formData.zipCode)
newErrors.zipCode = 'Zip code is required';
if (!formData.country)
newErrors.country = 'Country is required';
// Email validation
if (formData.email && !/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Please enter a valid email address';
}
// Payment method validation
if (!formData.paymentMethodId) {
newErrors.paymentMethod = 'Please select a payment method';
}
// Shipping method validation
if (!formData.shippingMethodId) {
newErrors.shippingMethod = 'Please select a shipping method';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleInputChange = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }));
// Clear error when user starts typing
if (errors[field]) {
setErrors(prev => ({ ...prev, [field]: '' }));
}
};
const handleShippingMethodChange = (methodId) => {
const method = shippingMethods.find(m => m.id === methodId);
setFormData(prev => ({ ...prev, shippingMethodId: methodId }));
if (method) {
updateOrderSummary(method.price);
}
};
const handleNextStep = () => {
if (validateForm()) {
if (currentStep === 'shipping') {
setCurrentStep('payment');
}
else if (currentStep === 'payment') {
setCurrentStep('review');
}
}
};
const handlePreviousStep = () => {
if (currentStep === 'payment') {
setCurrentStep('shipping');
}
else if (currentStep === 'review') {
setCurrentStep('payment');
}
};
const handleSubmit = async () => {
if (!validateForm())
return;
try {
setLoading(true);
// In a real implementation, this would call the backend to process the order
const orderId = `order_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
// Simulate processing delay
await new Promise(resolve => setTimeout(resolve, 2000));
onSuccess?.(orderId);
}
catch (err) {
onError?.(err.message);
}
finally {
setLoading(false);
}
};
const formatPrice = (amount) => {
return new Intl.NumberFormat(config.locale || 'en-US', {
style: 'currency',
currency: config.currency || 'EUR'
}).format(amount);
};
if (loading && !session) {
return ((0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '400px',
background: '#f8f9fa',
borderRadius: '8px'
}, children: (0, jsx_runtime_1.jsxs)("div", { style: { textAlign: 'center' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: '24px', marginBottom: '16px' }, children: "\uD83D\uDD04" }), (0, jsx_runtime_1.jsx)("div", { children: "Initializing checkout..." })] }) }));
}
return ((0, jsx_runtime_1.jsxs)("div", { style: {
maxWidth: '800px',
margin: '0 auto',
background: '#fff',
borderRadius: '12px',
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)',
overflow: 'hidden'
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
background: config.theme === 'modern' ? '#0070f3' : '#f8f9fa',
padding: '24px',
borderBottom: '1px solid #e1e5e9'
}, children: [(0, jsx_runtime_1.jsx)("h2", { style: {
margin: 0,
color: config.theme === 'modern' ? '#fff' : '#333',
fontSize: '24px',
fontWeight: '600'
}, children: "Secure Checkout" }), (0, jsx_runtime_1.jsx)("div", { style: {
display: 'flex',
justifyContent: 'space-between',
marginTop: '16px'
}, children: ['shipping', 'payment', 'review'].map((step, index) => ((0, jsx_runtime_1.jsxs)("div", { style: {
display: 'flex',
alignItems: 'center',
color: config.theme === 'modern' ? '#fff' : '#666'
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
width: '32px',
height: '32px',
borderRadius: '50%',
background: currentStep === step ? '#fff' : 'rgba(255,255,255,0.3)',
color: currentStep === step ? '#0070f3' : '#fff',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: '600',
fontSize: '14px'
}, children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { style: { marginLeft: '8px', fontSize: '14px' }, children: step.charAt(0).toUpperCase() + step.slice(1) })] }, step))) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, padding: '32px' }, children: [currentStep === 'shipping' && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { style: { margin: '0 0 24px 0', color: '#333' }, children: "Shipping Information" }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "First Name *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.firstName, onChange: (e) => handleInputChange('firstName', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.firstName ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "First name" }), errors.firstName && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.firstName }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Last Name *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.lastName, onChange: (e) => handleInputChange('lastName', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.lastName ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Last name" }), errors.lastName && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.lastName }))] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Email Address *" }), (0, jsx_runtime_1.jsx)("input", { type: "email", value: formData.email, onChange: (e) => handleInputChange('email', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.email ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "your@email.com" }), errors.email && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.email }))] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Address *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.address, onChange: (e) => handleInputChange('address', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.address ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Street address" }), errors.address && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.address }))] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "City *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.city, onChange: (e) => handleInputChange('city', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.city ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "City" }), errors.city && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.city }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Zip Code *" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: formData.zipCode, onChange: (e) => handleInputChange('zipCode', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.zipCode ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, placeholder: "Zip code" }), errors.zipCode && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.zipCode }))] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("label", { style: { display: 'block', marginBottom: '8px', fontWeight: '500' }, children: "Country *" }), (0, jsx_runtime_1.jsxs)("select", { value: formData.country, onChange: (e) => handleInputChange('country', e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${errors.country ? '#dc3545' : '#dee2e6'}`,
borderRadius: '6px',
fontSize: '16px'
}, children: [(0, jsx_runtime_1.jsx)("option", { value: "US", children: "United States" }), (0, jsx_runtime_1.jsx)("option", { value: "CA", children: "Canada" }), (0, jsx_runtime_1.jsx)("option", { value: "GB", children: "United Kingdom" }), (0, jsx_runtime_1.jsx)("option", { value: "DE", children: "Germany" }), (0, jsx_runtime_1.jsx)("option", { value: "FR", children: "France" })] }), errors.country && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.country }))] }), shippingMethods.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("h4", { style: { margin: '0 0 16px 0', color: '#333' }, children: "Shipping Method" }), shippingMethods.map((method) => ((0, jsx_runtime_1.jsxs)("label", { style: {
display: 'flex',
alignItems: 'center',
padding: '16px',
border: `1px solid ${formData.shippingMethodId === method.id ? '#0070f3' : '#dee2e6'}`,
borderRadius: '6px',
marginBottom: '8px',
cursor: 'pointer',
background: formData.shippingMethodId === method.id ? '#f0f8ff' : '#fff'
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "radio", name: "shippingMethod", value: method.id, checked: formData.shippingMethodId === method.id, onChange: (e) => handleShippingMethodChange(e.target.value), style: { marginRight: '12px' } }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1 }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: '500' }, children: method.name }), (0, jsx_runtime_1.jsxs)("div", { style: { color: '#666', fontSize: '14px' }, children: [method.estimatedDays, " \u2022 ", formatPrice(method.price)] })] })] }, method.id))), errors.shippingMethod && ((0, jsx_runtime_1.jsx)("div", { style: { color: '#dc3545', fontSize: '14px', marginTop: '4px' }, children: errors.shippingMethod }))] }))] })), currentStep === 'payment' && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { style: { margin: '0 0 24px 0', color: '#333' }, children: "Payment Information" }), paymentMethods.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '24px' }, children: [(0, jsx_runtime_1.jsx)("h4", { style: { margin: '0 0 16px 0', color: '#333' }, children: "Payment Method" }), paymentMethods.map((method) => ((0, jsx_runtime_1.jsxs)("label", { style: {
display: 'flex',
alignItems: 'center',
padding: '16px',
border: `1px solid ${formData.paymentMethodId === method.id ? '#0070f3'