From 74b7aa4877163453683751c4690472182822cd09 Mon Sep 17 00:00:00 2001 From: NotII <46204250+NotII@users.noreply.github.com> Date: Mon, 22 Sep 2025 00:45:29 +0100 Subject: [PATCH] Add shipping dialog with tracking number to order page Introduces a shipping dialog to the order details page, allowing users to optionally enter a tracking number when marking an order as shipped. Updates API client logic to better handle HTTP-only authentication cookies. Improves broadcast dialog validation and message handling. --- app/dashboard/orders/[id]/page.tsx | 89 +++++++++++++++++++++++++- components/modals/broadcast-dialog.tsx | 9 ++- components/tables/order-table.tsx | 1 + docs/README.md | 1 + lib/api-client.ts | 31 +++++++-- public/git-info.json | 4 +- 6 files changed, 121 insertions(+), 14 deletions(-) diff --git a/app/dashboard/orders/[id]/page.tsx b/app/dashboard/orders/[id]/page.tsx index fcadd39..f72aacd 100644 --- a/app/dashboard/orders/[id]/page.tsx +++ b/app/dashboard/orders/[id]/page.tsx @@ -158,6 +158,8 @@ export default function OrderDetailsPage() { const [isAcknowledging, setIsAcknowledging] = useState(false); const [isCancelling, setIsCancelling] = useState(false); const [refreshTrigger, setRefreshTrigger] = useState(0); + const [showShippingDialog, setShowShippingDialog] = useState(false); + const [shippingTrackingNumber, setShippingTrackingNumber] = useState(""); const router = useRouter(); const params = useParams(); @@ -262,7 +264,7 @@ export default function OrderDetailsPage() { } }; - const handleMarkAsShipped = async () => { + const handleMarkAsShipped = async (trackingNumber?: string) => { try { setIsMarkingShipped(true); @@ -274,6 +276,12 @@ export default function OrderDetailsPage() { if (response && response.message === "Order status updated successfully") { setOrder((prevOrder) => prevOrder ? { ...prevOrder, status: "shipped" } : null); + + // If tracking number is provided, add it + if (trackingNumber && trackingNumber.trim()) { + await handleAddTrackingNumber(trackingNumber.trim()); + } + toast.success("Order marked as shipped successfully!"); } else { throw new Error(response.error || "Failed to mark order as shipped"); @@ -286,6 +294,48 @@ export default function OrderDetailsPage() { } }; + const handleAddTrackingNumber = async (trackingNumber: string) => { + try { + const authToken = document.cookie.split("Authorization=")[1]; + + const response = await fetchData( + `${process.env.NEXT_PUBLIC_API_URL}/orders/${orderId}/tracking`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${authToken}`, + }, + body: JSON.stringify({ trackingNumber }), + } + ); + + if (response.error) throw new Error(response.error); + + // Update the local state + setOrder(prevOrder => prevOrder ? { + ...prevOrder, + trackingNumber: trackingNumber + } : null); + + toast.success("Tracking number added successfully!"); + } catch (err: any) { + console.error("Failed to add tracking number:", err); + toast.error(err.message || "Failed to add tracking number"); + } + }; + + const handleShippingDialogConfirm = async () => { + await handleMarkAsShipped(shippingTrackingNumber); + setShowShippingDialog(false); + setShippingTrackingNumber(""); + }; + + const handleShippingDialogCancel = () => { + setShowShippingDialog(false); + setShippingTrackingNumber(""); + }; + const handleMarkAsAcknowledged = async () => { try { setIsAcknowledging(true); @@ -922,7 +972,7 @@ export default function OrderDetailsPage() { {order?.status === "acknowledged" && ( + ); diff --git a/docs/README.md b/docs/README.md index 7c89b95..c9abc51 100644 --- a/docs/README.md +++ b/docs/README.md @@ -49,3 +49,4 @@ When adding new documentation: - **🔧 Configuration** - Environment variables, API setup - **🐛 Troubleshooting** - Common issues and fixes + diff --git a/lib/api-client.ts b/lib/api-client.ts index 93a837f..6e34363 100644 --- a/lib/api-client.ts +++ b/lib/api-client.ts @@ -151,14 +151,32 @@ function normalizeApiUrl(url: string): string { /** * Get the authentication token from cookies or localStorage + * Note: HTTP-only cookies cannot be read by JavaScript, so we return null + * and rely on the browser to automatically include them in requests */ export function getAuthToken(): string | null { if (typeof document === 'undefined') return null; // Guard for SSR - return document.cookie + // Try localStorage first (for non-HTTP-only tokens) + const localToken = localStorage.getItem('Authorization'); + if (localToken) { + return localToken; + } + + // For HTTP-only cookies, we can't read them from JavaScript + // The browser will automatically include them in requests + // Check if the cookie exists (we can't read its value) + const hasAuthCookie = document.cookie .split('; ') - .find(row => row.startsWith('Authorization=')) - ?.split('=')[1] || localStorage.getItem('Authorization'); + .some(row => row.startsWith('Authorization=')); + + if (hasAuthCookie) { + // Return a special marker to indicate the cookie exists + // The actual token will be sent automatically by the browser + return 'HTTP_ONLY_COOKIE'; + } + + return null; } /** @@ -188,9 +206,11 @@ function createApiHeaders(token?: string | null, customHeaders: Record( ...(headers as Record), }; - if (authToken) { + if (authToken && authToken !== 'HTTP_ONLY_COOKIE') { // Backend expects "Bearer TOKEN" format requestHeaders['Authorization'] = `Bearer ${authToken}`; } + // For HTTP_ONLY_COOKIE, the browser will automatically include the cookie const fetchOptions: RequestInit = { method, diff --git a/public/git-info.json b/public/git-info.json index 0fab168..ba3d780 100644 --- a/public/git-info.json +++ b/public/git-info.json @@ -1,4 +1,4 @@ { - "commitHash": "a10b9e0", - "buildTime": "2025-08-31T17:56:33.446Z" + "commitHash": "8554481", + "buildTime": "2025-09-17T17:02:11.044Z" } \ No newline at end of file