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.
This commit is contained in:
NotII
2025-09-22 00:45:29 +01:00
parent 8554481282
commit 74b7aa4877
6 changed files with 121 additions and 14 deletions

View File

@@ -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" && (
<Button
className="w-full"
onClick={handleMarkAsShipped}
onClick={() => setShowShippingDialog(true)}
disabled={isMarkingShipped}
>
{isMarkingShipped ? "Processing..." : "Mark as Shipped"}
@@ -1082,6 +1132,41 @@ export default function OrderDetailsPage() {
)}
</div>
</div>
{/* Shipping Dialog */}
<AlertDialog open={showShippingDialog} onOpenChange={setShowShippingDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Mark Order as Shipped</AlertDialogTitle>
<AlertDialogDescription>
Mark this order as shipped. You can optionally add a tracking number.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="space-y-4 py-4">
<div>
<Label htmlFor="shipping-tracking">Tracking Number (Optional)</Label>
<Input
id="shipping-tracking"
value={shippingTrackingNumber}
onChange={(e) => setShippingTrackingNumber(e.target.value)}
placeholder="Enter tracking number"
className="mt-1"
/>
</div>
</div>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleShippingDialogCancel}>
Cancel
</AlertDialogCancel>
<AlertDialogAction
onClick={handleShippingDialogConfirm}
disabled={isMarkingShipped}
>
{isMarkingShipped ? "Processing..." : "Mark as Shipped"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</Layout>
);