order.astro raw
1 ---
2 import Base from '../../layouts/Base.astro';
3 ---
4 <Base title="Поръчка">
5 <section class="section">
6 <div class="container">
7 <a href="/user" style="display:inline-block;margin-bottom:1.5rem;color:var(--primary,#2a9d8f);text-decoration:none;font-size:1rem;">← <span data-i18n="adminBack">Назад</span></a>
8 <div id="order-detail">Зареждане...</div>
9 </div>
10 </section>
11 </Base>
12
13 <script>
14 import { escapeHtml, formatLv } from '../../lib/cart-client';
15 import { t } from '../../lib/i18n';
16
17 function orderStatusLabel(s: string): string {
18 const keys: Record<string, string> = {
19 pending: 'adminStatusPending', paid: 'adminStatusPaid', failed: 'adminStatusFailed',
20 expired: 'adminStatusExpired', shipped: 'adminStatusShipped', delivered: 'adminStatusDelivered', cancelled: 'adminStatusCancelled',
21 };
22 return keys[s] ? t(keys[s]) : s;
23 }
24 function orderMethodLabel(m: string): string {
25 const keys: Record<string, string> = {
26 stripe: 'payStripe', lightning: 'payLightning', onchain: 'payOnchain',
27 bank: 'payBank', cod: 'payCod',
28 };
29 return keys[m] ? t(keys[m]) : m;
30 }
31
32 async function loadOrder() {
33 const p = new URLSearchParams(location.search);
34 const id = p.get('id');
35 if (!id) {
36 document.getElementById('order-detail')!.textContent = t('orderMissingId');
37 return;
38 }
39 const token = localStorage.getItem('token');
40 if (!token) {
41 document.getElementById('order-detail')!.textContent = t('orderLogin');
42 return;
43 }
44 const r = await fetch(`/api/user/orders/${id}`, { headers: { Authorization: 'Bearer ' + token } });
45 if (!r.ok) {
46 document.getElementById('order-detail')!.textContent = t('orderNotFound');
47 return;
48 }
49 const view = await r.json();
50
51 const items = (view.items || []).map((i: any) =>
52 `<div class="order-item"><span>${escapeHtml(i.name)} × ${i.qty} бр.</span><span>${formatLv(i.price_cents * i.qty)}</span></div>`
53 ).join('');
54
55 document.getElementById('order-detail')!.innerHTML = `
56 <h1>${t('orderId')} <span class="order-id">${view.id.slice(0,8)}</span></h1>
57 <p class="order-status"><strong>${orderStatusLabel(view.status)}</strong></p>
58 <div class="order-items">
59 ${items}
60 <div class="order-item order-sub"><span>${t('checkoutSubtotal')}</span><span>${formatLv(view.subtotal_cents)}</span></div>
61 <div class="order-item order-sub"><span>${t('checkoutShippingCost')}</span><span>${view.shipping_cents === 0 ? t('checkoutFreeShipping') : formatLv(view.shipping_cents)}</span></div>
62 <div class="order-item order-total"><strong>${t('checkoutTotal')}</strong><strong>${formatLv(view.total_cents)}</strong></div>
63 </div>
64 <h2>${t('checkoutShipping')}</h2>
65 <p><strong>${t('name')}:</strong> ${escapeHtml(view.customer_name)}</p>
66 <p><strong>${t('phone')}:</strong> ${escapeHtml(view.customer_phone || '—')}</p>
67 <h2>${t('checkoutPayment')}: ${orderMethodLabel(view.payment_method)}</h2>
68 ${view.payment_method === 'lightning' && view.payment?.pr ? `<code class="invoice-code">${escapeHtml(view.payment.pr)}</code>` : ''}
69 ${view.payment_method === 'onchain' && view.payment?.checkoutUrl ? `<p><a class="btn btn-primary" href="${escapeHtml(view.payment.checkoutUrl)}">${t('payOnchain')}</a></p>` : ''}
70 `;
71 loadOrder();
72 }
73
74 window.addEventListener('lang-changed', () => { loadOrder(); });
75 </script>
76
77 <style>
78 .order-id { font-family: monospace; font-size: 0.8em; color: var(--text-light,#888); }
79 .order-items { max-width: 480px; margin: 1rem 0; }
80 .order-item { display: flex; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid #eee; }
81 .order-total { border-bottom: none; font-size: 1.1rem; }
82 .invoice-code { display: block; word-break: break-all; background: #f5f5f5; padding: 0.75rem; border-radius: 8px; font-size: 0.8rem; max-width: 640px; margin: 0.5rem 0; }
83 </style>
84