37980-vm/frontend/src/pages/order-details.tsx
2026-01-30 17:40:21 +00:00

194 lines
7.8 KiB
TypeScript

import { mdiPackageVariantClosed, mdiArrowLeft } from '@mdi/js';
import Head from 'next/head';
import React, { ReactElement, useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import CardBox from '../components/CardBox';
import LayoutAuthenticated from '../layouts/Authenticated';
import SectionMain from '../components/SectionMain';
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
import { getPageTitle } from '../config';
import axios from 'axios';
import BaseButton from '../components/BaseButton';
import { useTranslation } from 'next-i18next';
import Link from 'next/link';
const OrderDetailsPage = () => {
const router = useRouter();
const { id } = router.query;
const { t } = useTranslation('common');
const [order, setOrder] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!id) return;
const fetchOrder = async () => {
try {
const response = await axios.get(`/orders/${id}`);
setOrder(response.data);
} catch (error) {
console.error('Error fetching order:', error);
} finally {
setLoading(false);
}
};
fetchOrder();
}, [id]);
if (loading) {
return (
<LayoutAuthenticated>
<SectionMain>
<div className="text-center py-10">Loading order details...</div>
</SectionMain>
</LayoutAuthenticated>
);
}
if (!order) {
return (
<LayoutAuthenticated>
<SectionMain>
<div className="text-center py-10">Order not found.</div>
</SectionMain>
</LayoutAuthenticated>
);
}
return (
<>
<Head>
<title>{getPageTitle(`Order #${order.order_number || order.id.slice(0, 8)}`)}</title>
</Head>
<SectionMain>
<SectionTitleLineWithButton
icon={mdiPackageVariantClosed}
title={`Order #${order.order_number || order.id.slice(0, 8)}`}
main
>
<Link href="/my-orders">
<BaseButton icon={mdiArrowLeft} label="Back to Orders" color="white" small />
</Link>
</SectionTitleLineWithButton>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Order Summary */}
<div className="lg:col-span-2 space-y-6">
<CardBox title="Items Ordered">
<div className="divide-y">
{order.order_items_order?.map((item: any) => (
<div key={item.id} className="py-4 flex items-center">
<div className="h-16 w-16 bg-gray-100 rounded overflow-hidden flex-shrink-0">
{item.product?.image && item.product.image.length > 0 ? (
<img
src={item.product.image[0].downloadUrl || item.product.image[0].publicUrl}
alt={item.product.name}
className="h-full w-full object-cover"
/>
) : (
<div className="h-full w-full flex items-center justify-center text-gray-400">
No Image
</div>
)}
</div>
<div className="ml-4 flex-grow">
<h4 className="font-semibold">{item.product?.name || 'Unknown Product'}</h4>
<p className="text-sm text-gray-500">Qty: {item.quantity}</p>
</div>
<div className="text-right">
<p className="font-bold">${parseFloat(item.price).toFixed(2)}</p>
<p className="text-xs text-gray-500">ea</p>
</div>
</div>
))}
</div>
<div className="mt-6 border-t pt-4 space-y-2">
<div className="flex justify-between">
<span className="text-gray-600">Subtotal</span>
<span className="font-medium">${parseFloat(order.total).toFixed(2)}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-600">Shipping</span>
<span className="font-medium text-green-600">Free</span>
</div>
<div className="flex justify-between border-t pt-2 text-xl">
<span className="font-bold">Total</span>
<span className="font-bold">${parseFloat(order.total).toFixed(2)}</span>
</div>
</div>
</CardBox>
<CardBox title="Delivery Information">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h4 className="font-bold text-gray-700 mb-2 uppercase text-xs tracking-wider">Shipping Address</h4>
<p className="text-gray-600 whitespace-pre-wrap">{order.shipping_address}</p>
</div>
<div>
<h4 className="font-bold text-gray-700 mb-2 uppercase text-xs tracking-wider">Order Status</h4>
<div className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold uppercase ${
order.status === 'delivered' ? 'bg-green-100 text-green-800' :
order.status === 'cancelled' ? 'bg-red-100 text-red-800' :
'bg-blue-100 text-blue-800'
}`}>
{order.status || 'Pending'}
</div>
<div className="mt-4">
<h4 className="font-bold text-gray-700 mb-2 uppercase text-xs tracking-wider">Placed On</h4>
<p className="text-gray-600">{new Date(order.createdAt).toLocaleString()}</p>
</div>
</div>
</div>
</CardBox>
</div>
{/* Side Info */}
<div className="space-y-6">
<CardBox title="Payment Details">
<div className="space-y-4">
<div>
<h4 className="font-bold text-gray-700 mb-1 uppercase text-xs tracking-wider">Payment Status</h4>
<div className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-bold uppercase ${
order.payment_status === 'paid' ? 'bg-green-100 text-green-700' :
'bg-yellow-100 text-yellow-700'
}`}>
{order.payment_status || 'Unpaid'}
</div>
</div>
{order.payments_order?.[0] && (
<div>
<h4 className="font-bold text-gray-700 mb-1 uppercase text-xs tracking-wider">Payment Method</h4>
<p className="text-gray-600">
Stripe Payment
</p>
</div>
)}
<div>
<h4 className="font-bold text-gray-700 mb-1 uppercase text-xs tracking-wider">Billing Address</h4>
<p className="text-gray-600 text-sm whitespace-pre-wrap">{order.billing_address || order.shipping_address}</p>
</div>
</div>
</CardBox>
<CardBox className="bg-blue-50 dark:bg-dark-700">
<h4 className="font-bold mb-2">Need Help?</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
If you have any questions about your order, please contact our support team.
</p>
<BaseButton color="info" label="Contact Support" small outline block />
</CardBox>
</div>
</div>
</SectionMain>
</>
);
};
OrderDetailsPage.getLayout = function getLayout(page: ReactElement) {
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
};
export default OrderDetailsPage;