1import { useEffect, useState } from 'react';
2import { useNavigate } from 'react-router-dom';
3import MainLayout from '../components/Layout/MainLayout';
4// import removed: TenantSelector
5import { apiFetch } from '../lib/api';
7export default function Orders() {
8 const token = localStorage.getItem('token');
12 const payload = token.split('.')[1];
13 const decoded = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
14 tenantId = decoded.tenant_id || decoded.tenantId || '';
17 const navigate = useNavigate();
18 const [items, setItems] = useState([]);
19 const [loading, setLoading] = useState(true);
20 const [error, setError] = useState(null);
21 const [isMSP, setIsMSP] = useState(false);
22 const [tenantsMap, setTenantsMap] = useState({});
28 async function fetchData(fetchTenantId = tenantId) {
31 const token = localStorage.getItem('token');
32 let url = '/products/reorder';
34 url += `?tenant_id=${tenantId}`;
36 const res = await apiFetch(url, {
37 headers: { Authorization: `Bearer ${token}` }
39 if (!res.ok) throw new Error('Failed to load reorder list');
40 const data = await res.json();
41 setItems(data.products || []);
45 setError(err.message || 'Failed to load');
54 const token = localStorage.getItem('token');
56 const res = await apiFetch('/tenants', { headers: { Authorization: `Bearer ${token}` } });
59 const data = await res.json();
61 (data.tenants || data || []).forEach(t => { if (t.tenant_id) map[t.tenant_id] = t.name; });
67 // Silently fail - 403 is expected for non-MSP users
76 <div className="page-content">
77 <div className="page-header">
78 <div className="header-content">
80 <div className="header-actions">
81 <button className="btn" onClick={fetchData}>
82 <span className="material-symbols-outlined">refresh</span>
86 className="btn primary"
88 if (!items || items.length === 0) return;
89 // For MVP, pass all items to PO form; future: group by supplier
90 const lines = items.map(p => ({
91 product_id: p.product_id,
92 sku: p.sku || p.upc || p.ean || '',
95 needed_qty: p.needed_qty,
96 price_retail: p.price_retail || p.price_ex_tax || 0
98 navigate('/purchase-orders/new', { state: { lines } });
100 disabled={!items || items.length === 0}
102 <span className="material-symbols-outlined">local_shipping</span>
103 Create Purchase Order
108 {error && <div className="error-message">{error}</div>}
110 <div className="loading">Loading...</div>
113 {items.length === 0 ? (
114 <div className="empty-state">
115 <span className="material-symbols-outlined" style={{ fontSize: 48, color: '#888' }}>inventory_2</span>
116 <div style={{ marginTop: 8 }}>All stocked products are above minimum levels.</div>
119 <table className="data-table">
122 {isMSP && <th>Tenant</th>}
125 <th>Current Stock</th>
133 <tr key={p.product_id}>
135 <td title={p.tenant_id ? `Tenant #${p.tenant_id}` : ''}>
136 {p.tenant_id === 1 ? 'Root Tenant' : (p.tenant_name || tenantsMap[p.tenant_id] || (p.tenant_id ? `#${p.tenant_id}` : '-'))}
140 <td>{p.supplier || '-'}</td>
141 <td>{p.stock_quantity}</td>
142 <td>{p.min_stock}</td>
144 <span className="status-badge status-warning">{p.needed_qty}</span>
146 <td>${Number(p.price_retail || p.price_ex_tax || 0).toFixed(2)}</td>