/* My Vital Cell — Checkout */ function Checkout({ onNav }) { const { Button, Input, Select, Eyebrow, Badge } = window.VitalCellDesignSystem_fbb4ec; const [items, setItems] = React.useState(() => window.VC_CART.get()); React.useEffect(() => { const h = () => setItems(window.VC_CART.get()); window.addEventListener('vc-cart-change', h); return () => window.removeEventListener('vc-cart-change', h); }, []); React.useEffect(() => { window.lucide && window.lucide.createIcons(); }); const [step, setStep] = React.useState(1); // 1 contact, 2 shipping, 3 payment, 4 review, 5 confirm const [orderId, setOrderId] = React.useState(''); const [placing, setPlacing] = React.useState(false); const [payError, setPayError] = React.useState(''); const [form, setForm] = React.useState({ email: '', firstName: '', lastName: '', organization: '', address1: '', address2: '', city: '', region: '', postal: '', country: 'United States', shipMethod: 'standard', cardName: '', cardNumber: '', cardExp: '', cardCvc: '', researchAck: false, termsAck: false, fdaAck: false, }); const upd = (k) => (e) => setForm((f) => ({ ...f, [k]: e && e.target ? (e.target.type === 'checkbox' ? e.target.checked : e.target.value) : e })); const subtotal = items.reduce((s, it) => s + (it.price || 0) * (it.qty || 1), 0); const shipRates = { standard: 18, standard: 34, express: 62 }; const shipping = items.length ? shipRates[form.shipMethod] : 0; const tax = Math.round(subtotal * 0.0725 * 100) / 100; const total = subtotal + shipping + tax; const fmt = (n) => '$' + n.toFixed(2); const stepValid = { 1: /.+@.+\..+/.test(form.email) && form.firstName && form.lastName, 2: form.address1 && form.city && form.region && form.postal, 3: form.cardName && form.cardNumber.replace(/\s/g, '').length >= 13 && /^\d{2}\/\d{2}$/.test(form.cardExp) && form.cardCvc.length >= 3, 4: form.researchAck && form.termsAck && form.fdaAck, }; const next = () => setStep((s) => Math.min(4, s + 1)); const back = () => setStep((s) => Math.max(1, s - 1)); const placeOrder = async () => { setPlacing(true); setPayError(''); try { const stripe = await window.VC_STRIPE.getStripe(); const { clientSecret } = await window.VC_STRIPE.createPaymentIntent({ amount: Math.round(total * 100), currency: 'usd', items: items.map((it) => ({ name: it.name, qty: it.qty || 1, price: it.price })), email: form.email, }); const [expMonth, expYear] = form.cardExp.split('/'); const result = await stripe.confirmCardPayment(clientSecret, { payment_method: { card: { number: form.cardNumber.replace(/\s/g, ''), exp_month: parseInt(expMonth, 10), exp_year: parseInt('20' + expYear, 10), cvc: form.cardCvc, }, billing_details: { name: form.cardName, email: form.email, address: { line1: form.address1, line2: form.address2, city: form.city, state: form.region, postal_code: form.postal, country: form.country }, }, }, __amount: Math.round(total * 100), }); if (result.error) { setPayError(result.error.message || 'Payment could not be processed.'); setStep(3); setPlacing(false); return; } const pi = result.paymentIntent; const id = 'MVC-' + (pi.id.slice(-8) || Math.random().toString(36).slice(2, 7)).toUpperCase() + '-' + Date.now().toString().slice(-4); setOrderId(id); window.VC_CART.clear(); setStep(5); setPlacing(false); window.scrollTo({ top: 0, behavior: 'instant' }); } catch (err) { setPayError((err && err.message) || 'Something went wrong. Please try again.'); setPlacing(false); } }; // Empty state if (items.length === 0 && step !== 5) { return (
Checkout

Your cart is empty

Add research compounds to your cart to begin checkout. Every order is CoA-matched and shipped under shipping integrity.

); } // Confirmation if (step === 5) { return (
Order confirmed

Thank you, {form.firstName || 'researcher'}.

Your order is queued for our team. A confirmation with CoAs (available on request), shipping manifest and tracking will arrive at {form.email} within one business day.

Order reference {orderId}
); } const stepLabels = ['Contact', 'Shipping', 'Payment', 'Review']; return (
{/* Header */}
Secure checkout

Complete your order

{/* Stepper */}
    {stepLabels.map((label, i) => { const n = i + 1; const done = step > n; const active = step === n; return (
  1. {done ? : n} {label}
  2. ); })}
{/* LEFT: form */}
{step === 1 && (
)} {step === 2 && (
{[ { id: 'standard', name: 'Standard ambient', eta: '5–7 business days', price: 18, note: 'For non-sensitive supplies only.' }, { id: 'standard', name: 'Standard shipping', eta: '2–3 business days', price: 34, note: 'Protective packaging with tracked delivery.' }, { id: 'express', name: 'Express shipping', eta: 'Next business day', price: 62, note: 'Priority overnight with signature required.' }, ].map((o) => { const sel = form.shipMethod === o.id; return ( ); })}
)} {step === 3 && (
{/* Test-mode banner */} {!(window.VC_STRIPE && window.VC_STRIPE.isLive) && (
Stripe test mode. No card is charged. Use 4242 4242 4242 4242 to succeed, 4000 0000 0000 0002 to trigger a decline.
)} {/* Express checkout row */}
Express checkout
{[ { id: 'apple', label: '\uf179 Pay', bg: '#000', fg: '#fff' }, { id: 'google', label: 'G Pay', bg: '#fff', fg: '#3c4043', border: '1px solid #dadce0' }, { id: 'link', label: 'Link', bg: '#00d66f', fg: '#0a2540' }, ].map((b) => ( ))}
OR PAY WITH CARD
{/* Card fields — Stripe Payment Element look */}
setForm((f) => ({ ...f, cardNumber: e.target.value.replace(/[^\d]/g, '').slice(0, 19).replace(/(\d{4})(?=\d)/g, '$1 ') }))} placeholder="4242 4242 4242 4242" inputMode="numeric" />
{['#1a1f71', '#eb001b', '#0071ce', '#2a2a2a'].map((c, i) => ( ))}
{ let v = e.target.value.replace(/[^\d]/g, '').slice(0, 4); if (v.length >= 3) v = v.slice(0, 2) + '/' + v.slice(2); setForm((f) => ({ ...f, cardExp: v })); }} placeholder="12/28" inputMode="numeric" /> setForm((f) => ({ ...f, cardCvc: e.target.value.replace(/[^\d]/g, '').slice(0, 4) }))} placeholder="123" inputMode="numeric" />
{payError && (
{payError}
)}
256-BIT TLS · PCI-DSS SAQ-A Powered by stripe
)} {step === 4 && (
setStep(1)}>
{form.firstName} {form.lastName}
{form.email}
{form.organization &&
{form.organization}
}
setStep(2)}>
{form.address1}{form.address2 ? ', ' + form.address2 : ''}
{form.city}, {form.region} {form.postal} · {form.country}
setStep(2)}>
{form.shipMethod === 'standard' ? 'Standard (2–3 days)' : form.shipMethod === 'express' ? 'Express shipping (next day)' : 'Standard ambient (5–7 days)'}
setStep(3)}>
Card ending in {form.cardNumber.replace(/\s/g, '').slice(-4) || '····'}
Exp {form.cardExp || '··/··'}
)} {/* Nav */}
{step < 4 ? ( ) : ( )}
{/* RIGHT: order summary */}
); } function SectionTitle({ n, title, hint }) { return (
{n}

{title}

{hint &&

{hint}

}
); } function ReviewRow({ label, children, onEdit }) { return (
{label}
{children}
); } function TrustLine({ icon, children }) { return (
{children}
); } Object.assign(window, { Checkout });