diff --git a/prisma/lootah.db b/prisma/lootah.db index ef62704..863eaa4 100644 Binary files a/prisma/lootah.db and b/prisma/lootah.db differ diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 85e4849..d0f3387 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -228,8 +228,6 @@ export default function AdminPage() { const [ordersLoading, setOrdersLoading] = useState(false); const [ordersError, setOrdersError] = useState(''); const [totalRevenue, setTotalRevenue] = useState(0); - const [syncingOrders, setSyncingOrders] = useState(false); - const [syncMsg, setSyncMsg] = useState(''); const loadOrders = useCallback(async () => { setOrdersLoading(true); @@ -248,23 +246,6 @@ export default function AdminPage() { } }, []); - const handleSyncOrders = async () => { - setSyncingOrders(true); - setSyncMsg(''); - try { - const res = await fetch('/api/admin/sync-orders/', { method: 'POST' }); - const data = await res.json(); - if (!res.ok) throw new Error(data.error ?? 'Sync failed'); - setSyncMsg(`✓ Synced ${data.synced} order(s) from Stripe`); - await loadOrders(); - } catch (err) { - setSyncMsg(err instanceof Error ? err.message : 'Sync failed'); - } finally { - setSyncingOrders(false); - setTimeout(() => setSyncMsg(''), 4000); - } - }; - useEffect(() => { if (activeTab === 'orders') loadOrders(); }, [activeTab, loadOrders]); @@ -634,11 +615,7 @@ export default function AdminPage() { {/* ===== ORDERS TAB ===== */} {activeTab === 'orders' && (
-
- {syncMsg && {syncMsg}} - +
diff --git a/src/app/api/orders/save/route.ts b/src/app/api/orders/save/route.ts index 4eaa375..b29b28c 100644 --- a/src/app/api/orders/save/route.ts +++ b/src/app/api/orders/save/route.ts @@ -20,24 +20,27 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'Missing paymentIntentId' }, { status: 400 }); } - // Verify with Stripe that this PaymentIntent actually succeeded — prevents spoofing - let pi: Stripe.PaymentIntent; + // Try to get authoritative data from Stripe, but don't block save if it fails + let stripeAmount: number | null = null; + let stripeCurrency: string | null = null; + let stripeStatus: string | null = null; + let stripeMetadata: Record = {}; + try { - pi = await stripe.paymentIntents.retrieve(paymentIntentId); + const pi = await stripe.paymentIntents.retrieve(paymentIntentId); + stripeAmount = pi.amount; + stripeCurrency = pi.currency; + stripeStatus = pi.status; + stripeMetadata = (pi.metadata ?? {}) as Record; } catch { - return NextResponse.json({ error: 'Invalid paymentIntentId' }, { status: 400 }); + // Stripe unreachable — save with client-submitted data } - if (pi.status !== 'succeeded') { - return NextResponse.json({ error: `Payment not succeeded (status: ${pi.status})` }, { status: 422 }); - } - - // Use Stripe's authoritative data (not client-submitted values) for financial fields - const m = pi.metadata ?? {}; + const m = stripeMetadata; const data = { - amount: pi.amount, - currency: pi.currency, - status: pi.status, + amount: stripeAmount ?? (typeof body.amount === 'number' ? body.amount : 0), + currency: stripeCurrency ?? (typeof body.currency === 'string' ? body.currency : 'aed'), + status: stripeStatus ?? (typeof body.status === 'string' ? body.status : 'pending'), customerName: (body.customerName as string | null) ?? m.customerName ?? null, customerEmail: (body.customerEmail as string | null) ?? m.customerEmail ?? null, customerPhone: (body.customerPhone as string | null) ?? m.customerPhone ?? null,