import { useState } from 'react';
import { Badge, Button, Card, Divider, Group, Stack, Text, Tooltip } from '@mantine/core';
import { PackagePlus, Train as TrainIcon, Warehouse as WarehouseIcon } from 'lucide-react';
import { useQuery } from '@tanstack/react-query';
import { api } from '@/services/api';
import { InventoryStatusBadge } from './badges';
import { FreightVisual } from './FreightVisual';
import { formatDate } from './options';
import { ReceiveInventoryModal } from './ReceiveInventoryModal';
interface WarehouseInfoCardProps {
bookingId: string;
bookingReference?: string;
/**
* Booking payment status. Export cargo is received into the warehouse only
* after the booking is paid — receiving an unpaid booking starts storage and
* GRN against cargo the customer has not settled. Optional so existing callers
* that do not have the booking to hand keep their current behaviour.
*/
paymentStatus?: string | null;
/**
* IMPORT | EXPORT | DOMESTIC. The payment gate is export-only: import cargo
* arrives OFF a train, so blocking its receive would strand cargo already at
* the yard.
*/
tradeDirection?: string | null;
}
function Row({ label, value }: { label: string; value: React.ReactNode }) {
return (
{label}
{value}
);
}
export function WarehouseInfoCard({
bookingId,
bookingReference,
paymentStatus,
tradeDirection,
}: WarehouseInfoCardProps) {
const [modalOpen, setModalOpen] = useState(false);
const { data, isLoading } = useQuery(
api.warehouses.listInventory.queryOptions({ input: { filter: { bookingId } } }),
);
const { data: scheduleView } = useQuery(
api.warehouses.bookingSchedule.queryOptions({
input: { bookingId },
enabled: Boolean(bookingId),
}),
);
const items = data ?? [];
const latest = items[0];
const schedule = scheduleView?.schedule;
const wagon = scheduleView?.wagon;
const isLoadedOrDispatched =
latest?.status === 'LOADED' || latest?.status === 'DISPATCHED';
// Export only, and only when we were actually told the status — an absent prop
// means the caller cannot answer, and guessing "unpaid" would disable a valid
// action. Mirrors the server guard on receive().
const awaitingPayment =
tradeDirection?.toUpperCase() === 'EXPORT' &&
paymentStatus != null &&
paymentStatus.toUpperCase() !== 'PAID';
return (
Warehouse Information
{items.length > 0 && (
{items.length} item{items.length > 1 ? 's' : ''}
)}
{isLoading ? (
Loading…
) : !latest ? (
This booking has not been received at any warehouse yet.
) : (
} />
{isLoadedOrDispatched && (
<>
>
)}
)}
{schedule && (
<>
Train schedule (read-only)
}
labelPosition="left"
/>
{schedule.status}
}
/>
{wagon?.wagonNumber &&
}
{wagon?.sequenceNo != null &&
}
>
)}
{/* span wrapper so the tooltip still fires on the disabled button */}
}
onClick={() => setModalOpen(true)}
fullWidth
disabled={Boolean(latest) || awaitingPayment}
>
{latest ? 'Received At Warehouse' : 'Receive At Warehouse'}
setModalOpen(false)}
bookingId={bookingId}
bookingLabel={bookingReference}
/>
);
}