veza/apps/web/src/components/commerce/OrderSummary.tsx
senke 7c69474cf9 aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 11:50:46 +01:00

103 lines
3.4 KiB
TypeScript

import React from 'react';
import { Card } from '../ui/card';
import { Tag, ShieldCheck } from 'lucide-react';
interface OrderSummaryProps {
subtotal: number;
taxRate?: number;
discount?: { code: string; amount: number; type: 'percent' | 'fixed' };
currency?: string;
onCheckout?: () => void;
loading?: boolean;
}
export const OrderSummary: React.FC<OrderSummaryProps> = ({
subtotal,
taxRate = 0.08,
discount,
currency = 'USD',
onCheckout,
loading = false,
}) => {
const discountAmount = discount
? discount.type === 'percent'
? subtotal * (discount.amount / 100)
: discount.amount
: 0;
const taxableAmount = Math.max(0, subtotal - discountAmount);
const taxAmount = taxableAmount * taxRate;
const total = taxableAmount + taxAmount;
const formatPrice = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount);
};
return (
<div className="space-y-6">
<Card variant="gaming" className="p-6">
<h3 className="font-bold text-white mb-6 uppercase tracking-wider text-sm border-b border-kodo-steel pb-2">
Order Summary
</h3>
<div className="space-y-4 text-sm mb-6">
<div className="flex justify-between text-kodo-content-dim">
<span>Subtotal</span>
<span className="text-white font-mono">
{formatPrice(subtotal)}
</span>
</div>
{discount && (
<div className="flex justify-between text-kodo-lime">
<span className="flex items-center gap-2">
<Tag className="w-3 h-3" /> Discount ({discount.code})
</span>
<span className="font-mono">-{formatPrice(discountAmount)}</span>
</div>
)}
<div className="flex justify-between text-kodo-content-dim">
<span>Estimated Tax ({(taxRate * 100).toFixed(0)}%)</span>
<span className="text-white font-mono">
{formatPrice(taxAmount)}
</span>
</div>
</div>
<div className="border-t border-kodo-steel pt-4 mb-6">
<div className="flex justify-between items-end">
<span className="font-bold text-white">Total</span>
<span className="text-2xl font-mono font-bold text-kodo-steel">
{formatPrice(total)}
</span>
</div>
</div>
{onCheckout && (
<button
className="w-full h-12 bg-gradient-to-r from-kodo-cyan-dim to-kodo-cyan text-kodo-void border border-transparent font-bold tracking-wide rounded-lg disabled:opacity-50 disabled:cursor-not-allowed transition-opacity duration-200 hover:opacity-90"
onClick={onCheckout}
disabled={loading}
>
{loading ? 'PROCESSING...' : 'PROCEED TO CHECKOUT'}
</button>
)}
</Card>
<div className="bg-kodo-ink/50 p-4 rounded-xl border border-kodo-steel/50 flex items-start gap-4">
<ShieldCheck className="w-5 h-5 text-kodo-gold flex-shrink-0" />
<div>
<h4 className="font-bold text-white text-sm mb-1">Secure Checkout</h4>
<p className="text-xs text-kodo-content-dim leading-relaxed">
Transactions are encrypted. Downloads are available immediately
after payment.
</p>
</div>
</div>
</div>
);
};