vat_wms/resources/js/Components/WarehouseExpediceDialog.tsx

266 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleInfo, faCubesStacked, faXmark } from "@fortawesome/free-solid-svg-icons";
import { ShipmentRequest } from "@/interfaces/interfaces";
import ShipmentItemsAccordion from "@/Components/ShipmentItemsAccordion";
import axios from "axios";
interface WarehouseExpediceDialogProps {
selectedShipment: ShipmentRequest;
isDialogOpen: boolean;
closeDialog: () => void;
handleDialogProcess: () => void;
dialogToggleClose: () => void;
selectedType: "parcels" | "processed" | null;
buttonStates: { [itemId: number]: any };
setButtonStates: React.Dispatch<React.SetStateAction<{ [itemId: number]: any }>>;
}
export default function WarehouseExpediceDialog({
selectedShipment,
isDialogOpen,
closeDialog,
handleDialogProcess,
dialogToggleClose,
selectedType,
buttonStates,
setButtonStates,
}: WarehouseExpediceDialogProps) {
// Track which tab is active: "stock" or "details"
const [activeTab, setActiveTab] = useState<"stock" | "details">("stock");
const [imageArray, setImageArray] = useState<Record<number, { url: string }>>({});
const fetchItemImages = () => {
axios
.get("/api/expediceListWMS/getImage", {
params: { selectedShipmentID: selectedShipment.id },
})
.then((response) => {
setImageArray(response.data.imageArray || {});
})
.catch((error) => {
console.error("Error fetching image:", error);
});
};
// Whenever user clicks the Details tab, fetch images
const handleDetailsClick = () => {
setActiveTab("details");
fetchItemImages();
};
return (
<div className={`modal ${isDialogOpen ? "modal-open" : ""}`}>
{/* Modal backdrop + box */}
<div className="modal-box max-w-4xl max-h-[90vh] overflow-hidden p-0">
{/* Header with Tabs and Close button */}
<div className="flex items-center justify-between border-b border-base-300 px-4 py-3">
<div className="tabs">
<a
className={`tab ${activeTab === "stock" ? "tab-active" : ""}`}
onClick={() => setActiveTab("stock")}
>
<div className="flex items-center gap-2">
<FontAwesomeIcon icon={faCubesStacked} />
<span>Items</span>
</div>
</a>
<a
className={`tab ${activeTab === "details" ? "tab-active" : ""}`}
onClick={handleDetailsClick}
>
<div className="flex items-center gap-2">
<FontAwesomeIcon icon={faCircleInfo} />
<span>Details</span>
</div>
</a>
</div>
<button
onClick={closeDialog}
className="btn btn-ghost btn-circle text-base-content hover:text-error"
>
<FontAwesomeIcon icon={faXmark} size="lg" />
</button>
</div>
{/* Body */}
<div className="overflow-y-auto p-4 bg-base-100">
{activeTab === "details" && (
<div className="space-y-6">
{/* Reference */}
<div>
<h2 className="text-2xl font-semibold text-base-content">
Ref. # {selectedShipment.shipment_reference}
</h2>
</div>
{/* Items Section */}
<div className="bg-base-200 p-4 rounded-lg shadow">
<h3 className="text-lg font-semibold text-base-content mb-2">Items</h3>
{selectedShipment.items.map((item) => (
<div key={item.id} className="collapse collapse-arrow border border-base-300 rounded-lg mb-4">
<input type="checkbox" className="peer" />
<div className="collapse-title flex items-center justify-between bg-base-100 text-base-content px-4 py-2">
<div className="flex items-center gap-4">
<a
href={imageArray[item.id]?.url || "#"}
target="_blank"
rel="noopener noreferrer"
className="w-24 h-36 bg-base-300 rounded overflow-hidden flex-shrink-0 flex items-center justify-center"
>
{imageArray[item.id]?.url ? (
<img src={imageArray[item.id].url} alt="Item" className="w-full h-full object-center" />
) : (
<div className="w-auto h-full bg-base-200 flex items-center justify-center text-sm text-base-content">
No Image
</div>
)}
</a>
<div>
<p className="font-bold">{item.quantity}× {item.name}</p>
</div>
</div>
<div className="text-sm text-base-content">
{(item.price / item.quantity).toFixed(2)} {selectedShipment.currency}
</div>
</div>
<div className="collapse-content bg-base-100 text-base-content p-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<p className="font-semibold">Model Number:</p>
<p>{item.model_number}</p>
</div>
<div>
<p className="font-semibold">Origin:</p>
<p>{item.originCountry}</p>
</div>
<div>
<p className="font-semibold">Weight:</p>
<p>{item.weight}</p>
</div>
</div>
{item.stockData && Object.keys(item.stockData).length > 0 && (
<div className="mt-4">
<p className="font-semibold mb-2">Stock Information:</p>
{Object.entries(item.stockData).flatMap(([stockName, stockArray]) =>
stockArray.map((stock, idx) => (
<div
key={`${stockName}-${idx}`}
className="border-b border-base-300 pb-2 mb-2 last:border-0"
>
<p className="font-bold">{stockName}</p>
<p>Location: {stock.location}</p>
<p>Count: {stock.count} ks</p>
</div>
))
)}
</div>
)}
</div>
</div>
))}
</div>
{/* Delivery Address */}
<div className="bg-base-200 p-4 rounded-lg shadow">
<h3 className="text-lg font-semibold text-base-content mb-2">Delivery Address</h3>
<div className="space-y-1 text-base-content">
<p>
<span className="font-semibold">Name:</span> {selectedShipment.delivery_address_name}
</p>
{selectedShipment.delivery_address_company_name && (
<p>
<span className="font-semibold">Company:</span> {selectedShipment.delivery_address_company_name}
</p>
)}
<p>
<span className="font-semibold">Street:</span> {selectedShipment.delivery_address_street_name}{" "}
{selectedShipment.delivery_address_street_number}
</p>
<p>
<span className="font-semibold">City:</span> {selectedShipment.delivery_address_city}
</p>
<p>
<span className="font-semibold">ZIP:</span> {selectedShipment.delivery_address_zip}
</p>
{selectedShipment.delivery_address_state_iso && (
<p>
<span className="font-semibold">State:</span> {selectedShipment.delivery_address_state_iso}
</p>
)}
<p>
<span className="font-semibold">Country:</span> {selectedShipment.delivery_address_country_iso}
</p>
</div>
</div>
{/* Carrier & Shipment Info */}
<div className="bg-base-200 p-4 rounded-lg shadow">
<h3 className="text-lg font-semibold text-base-content mb-2">Carrier & Shipment Info</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-base-content">
<div>
<p className="font-semibold">Carrier:</p>
<p>{selectedShipment.carrier.carrier_name}</p>
</div>
<div>
<p className="font-semibold">Tracking Number:</p>
<p>{selectedShipment.shipment?.tracking_number || ""}</p>
</div>
<div>
<p className="font-semibold">Shipment Price:</p>
<p>
{selectedShipment.currency} {selectedShipment.shipment_price}
</p>
</div>
<div>
<p className="font-semibold">Shipment Value:</p>
<p>{selectedShipment.shipment_value}</p>
</div>
<div>
<p className="font-semibold">Weight:</p>
<p>{selectedShipment.weight}</p>
</div>
<div>
<p className="font-semibold">Dimensions:</p>
<p>
{selectedShipment.length} × {selectedShipment.width} × {selectedShipment.height}
</p>
</div>
</div>
</div>
</div>
)}
{activeTab === "stock" && (
<div className="text-base-content">
<ShipmentItemsAccordion
selectedShipment={selectedShipment}
buttonStates={buttonStates}
setButtonStates={setButtonStates}
parentModalHandle={dialogToggleClose}
/>
</div>
)}
</div>
{/* Footer with action button */}
<div className="modal-action border-t border-base-300 p-4 flex justify-end gap-2">
{selectedType === "parcels" && (
<button className="btn btn-primary" onClick={handleDialogProcess}>
Mark as Processed
</button>
)}
{selectedType === "processed" && (
<button className="btn btn-error" onClick={handleDialogProcess}>
Mark as Unprocessed
</button>
)}
<button className="btn btn-ghost" onClick={closeDialog}>
Close
</button>
</div>
</div>
</div>
);
}