'use client';
import { useEffect, useState } from 'react';
import AdminLayout from '../../components/AdminLayout';
import { getOrders, updateOrder } from '../../lib/api';
const STATUS_OPTIONS = ['paid', 'preparing', 'shipped', 'delivered', 'installed'];
const CARRIERS = ['UPS', 'FedEx', 'USPS', 'DHL'];
export default function OrdersPage() {
const [orders, setOrders] = useState([]);
const [filter, setFilter] = useState('');
const [loading, setLoading] = useState(true);
const [showTrackingModal, setShowTrackingModal] = useState(null);
useEffect(() => {
loadOrders();
}, [filter]);
const loadOrders = async () => {
try {
setLoading(true);
const data = await getOrders(filter || undefined);
setOrders(data.orders || []);
} catch (err) {
console.error('Failed to load orders:', err);
} finally {
setLoading(false);
}
};
const handleStatusChange = async (orderId, newStatus) => {
try {
await updateOrder(orderId, { status: newStatus });
loadOrders();
} catch (err) {
alert('Failed to update status: ' + err.message);
}
};
return (
Orders
{loading ? (
Loading...
) : orders.length === 0 ? (
No orders yet
Orders are created when customers purchase through the app
) : (
{orders.map((order) => (
#{order.order_number || order.id.slice(0,8)}
${((order.total_amount || 0) / 100).toFixed(2)}
Customer:
{order.user?.email || order.customer_email || 'N/A'}
Date:
{new Date(order.created_at).toLocaleString()}
{order.shipping_address && (
Address:
{order.shipping_address}
)}
{order.tracking_number && (
)}
{(order.status === 'preparing' || order.status === 'paid') && !order.tracking_number && (
)}
))}
)}
{showTrackingModal && (
setShowTrackingModal(null)}
onSaved={() => {
setShowTrackingModal(null);
loadOrders();
}}
/>
)}
);
}
function TrackingModal({ order, onClose, onSaved }) {
const [form, setForm] = useState({
carrier: 'UPS',
tracking_number: '',
estimated_delivery: '',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
await updateOrder(order.id, {
status: 'shipped',
...form,
});
onSaved();
} catch (err) {
alert('Failed: ' + err.message);
} finally {
setLoading(false);
}
};
return (
e.stopPropagation()}>
Add Tracking
);
}
function StatusBadge({ status }) {
const colors = {
paid: { bg: '#DBEAFE', color: '#1E40AF' },
preparing: { bg: '#FEF3C7', color: '#92400E' },
shipped: { bg: '#D1FAE5', color: '#065F46' },
delivered: { bg: '#E0E7FF', color: '#3730A3' },
installed: { bg: '#D1FAE5', color: '#065F46' },
};
const style = colors[status] || { bg: '#F3F4F6', color: '#6B7280' };
return (
{status}
);
}
function getTrackingUrl(carrier, number) {
const urls = {
UPS: `https://www.ups.com/track?tracknum=${number}`,
FedEx: `https://www.fedex.com/fedextrack/?trknbr=${number}`,
USPS: `https://tools.usps.com/go/TrackConfirmAction?tLabels=${number}`,
DHL: `https://www.dhl.com/en/express/tracking.html?AWB=${number}`,
};
return urls[carrier] || '#';
}
const styles = {
header: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '24px',
},
title: {
fontSize: '24px',
fontWeight: '600',
},
select: {
padding: '10px 16px',
fontSize: '14px',
border: '1px solid var(--border)',
borderRadius: '8px',
background: 'white',
cursor: 'pointer',
},
loading: {
color: 'var(--text-muted)',
},
empty: {
background: 'white',
padding: '48px',
borderRadius: '12px',
textAlign: 'center',
color: 'var(--text-muted)',
},
emptyHint: {
fontSize: '13px',
marginTop: '8px',
color: 'var(--text-muted)',
},
list: {
display: 'flex',
flexDirection: 'column',
gap: '16px',
},
orderCard: {
background: 'white',
borderRadius: '12px',
padding: '20px',
},
orderHeader: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '16px',
},
orderId: {
fontSize: '16px',
fontWeight: '600',
marginRight: '12px',
},
amount: {
fontSize: '14px',
color: 'var(--text-muted)',
},
orderInfo: {
display: 'flex',
flexDirection: 'column',
gap: '8px',
marginBottom: '16px',
paddingBottom: '16px',
borderBottom: '1px solid var(--border)',
},
infoRow: {
display: 'flex',
fontSize: '14px',
gap: '8px',
},
label: {
color: 'var(--text-muted)',
minWidth: '80px',
},
address: {
color: 'var(--text-secondary)',
},
trackingLink: {
color: 'var(--primary)',
textDecoration: 'none',
},
actions: {
display: 'flex',
gap: '12px',
},
statusSelect: {
padding: '8px 12px',
fontSize: '13px',
border: '1px solid var(--border)',
borderRadius: '6px',
background: 'white',
cursor: 'pointer',
},
trackingBtn: {
padding: '8px 16px',
fontSize: '13px',
fontWeight: '500',
color: 'white',
background: 'var(--primary)',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
},
modalOverlay: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0,0,0,0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000,
},
modal: {
background: 'white',
borderRadius: '16px',
padding: '32px',
width: '100%',
maxWidth: '400px',
},
modalTitle: {
fontSize: '20px',
fontWeight: '600',
marginBottom: '24px',
},
formGroup: {
marginBottom: '16px',
},
formLabel: {
display: 'block',
fontSize: '13px',
fontWeight: '500',
color: 'var(--text-secondary)',
marginBottom: '6px',
},
formInput: {
width: '100%',
padding: '10px 12px',
fontSize: '14px',
border: '1px solid var(--border)',
borderRadius: '8px',
outline: 'none',
},
modalActions: {
display: 'flex',
gap: '12px',
justifyContent: 'flex-end',
marginTop: '24px',
},
cancelBtn: {
padding: '10px 20px',
fontSize: '14px',
color: 'var(--text-secondary)',
background: 'transparent',
border: '1px solid var(--border)',
borderRadius: '8px',
cursor: 'pointer',
},
submitBtn: {
padding: '10px 20px',
fontSize: '14px',
fontWeight: '600',
color: 'white',
background: 'var(--primary)',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
},
};