Vendaweb-portal/components/checkout/DeliveryAvailabilityStatus.tsx

256 lines
8.4 KiB
TypeScript

import React from "react";
import { CheckCircle, XCircle, AlertCircle, Loader2 } from "lucide-react";
import { shippingService, DeliveryScheduleItem } from "../../src/services/shipping.service";
export interface DeliveryAvailabilityStatusProps {
selectedDate: Date | null;
orderWeight: number; // Peso do pedido em toneladas
isLoading?: boolean;
}
export interface DeliveryAvailabilityResult {
available: boolean;
capacity: number;
currentLoad: number;
availableCapacity: number;
occupancy: number;
message: string;
}
const DeliveryAvailabilityStatus: React.FC<DeliveryAvailabilityStatusProps> = ({
selectedDate,
orderWeight,
isLoading = false,
}) => {
const [availability, setAvailability] = React.useState<DeliveryAvailabilityResult | null>(null);
const [checking, setChecking] = React.useState(false);
React.useEffect(() => {
const checkAvailability = async () => {
if (!selectedDate || orderWeight <= 0) {
setAvailability(null);
return;
}
try {
setChecking(true);
// Formatar data para DD/MM/YYYY (formato usado pelo Baldinho)
const formattedDate = selectedDate.toLocaleDateString("pt-BR", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
console.log("📦 [DELIVERY_AVAILABILITY] Verificando disponibilidade:");
console.log("📦 [DELIVERY_AVAILABILITY] Data selecionada:", formattedDate);
console.log("📦 [DELIVERY_AVAILABILITY] Peso do pedido:", orderWeight, "Ton");
// Buscar dados do agendamento
const response = await shippingService.getScheduleDelivery();
if (!response || !response.deliveries || !Array.isArray(response.deliveries)) {
console.warn("📦 [DELIVERY_AVAILABILITY] Resposta inválida da API");
setAvailability({
available: false,
capacity: 0,
currentLoad: 0,
availableCapacity: 0,
occupancy: 100,
message: "Não foi possível verificar a disponibilidade",
});
return;
}
console.log("📦 [DELIVERY_AVAILABILITY] Itens recebidos:", response.deliveries.length);
// Encontrar o item correspondente à data selecionada
const deliveryItem = response.deliveries.find((item: DeliveryScheduleItem) => {
const itemDate = new Date(item.dateDelivery);
const itemFormatted = itemDate.toLocaleDateString("pt-BR", {
day: "2-digit",
month: "2-digit",
year: "numeric",
timeZone: "UTC",
});
console.log("📦 [DELIVERY_AVAILABILITY] Comparando:", itemFormatted, "com", formattedDate);
return itemFormatted === formattedDate;
});
if (!deliveryItem) {
setAvailability({
available: false,
capacity: 0,
currentLoad: 0,
availableCapacity: 0,
occupancy: 100,
message: "Data não encontrada no agendamento",
});
return;
}
// Verificar disponibilidade
const capacity = deliveryItem.deliverySize || 0;
const currentLoad = deliveryItem.saleWeigth || 0;
const availableCapacity = deliveryItem.avaliableDelivery || 0;
const isDeliveryEnabled = deliveryItem.delivery === "S";
const canFit = availableCapacity >= orderWeight;
const occupancy = capacity > 0 ? (currentLoad / capacity) * 100 : 100;
const available = isDeliveryEnabled && canFit;
let message = "";
if (!isDeliveryEnabled) {
message = "Entrega não disponível para esta data";
} else if (!canFit) {
message = `Capacidade insuficiente. Disponível: ${availableCapacity.toFixed(3)} Ton, Necessário: ${orderWeight.toFixed(3)} Ton`;
} else {
message = `Entrega disponível. Capacidade restante: ${availableCapacity.toFixed(3)} Ton`;
}
setAvailability({
available,
capacity,
currentLoad,
availableCapacity,
occupancy,
message,
});
} catch (error) {
console.error("Erro ao verificar disponibilidade:", error);
setAvailability({
available: false,
capacity: 0,
currentLoad: 0,
availableCapacity: 0,
occupancy: 100,
message: "Erro ao verificar disponibilidade de entrega",
});
} finally {
setChecking(false);
}
};
checkAvailability();
}, [selectedDate, orderWeight]);
if (!selectedDate || orderWeight <= 0) {
return null;
}
if (checking || isLoading) {
return (
<div className="mt-4 p-4 bg-slate-50 rounded-xl border border-slate-200">
<div className="flex items-center gap-3">
<Loader2 className="w-5 h-5 text-orange-500 animate-spin" />
<span className="text-sm font-medium text-slate-600">
Verificando disponibilidade de entrega...
</span>
</div>
</div>
);
}
if (!availability) {
return null;
}
const isAvailable = availability.available;
const occupancyColor =
availability.occupancy >= 100
? "bg-red-500"
: availability.occupancy >= 85
? "bg-orange-500"
: "bg-emerald-500";
return (
<div
className={`mt-4 p-5 rounded-xl border-2 transition-all duration-300 ${
isAvailable
? "bg-emerald-50 border-emerald-300 shadow-emerald-200/20"
: "bg-red-50 border-red-300 shadow-red-200/20"
}`}
>
<div className="flex items-start gap-4">
{/* Ícone */}
<div
className={`flex-shrink-0 w-12 h-12 rounded-xl flex items-center justify-center ${
isAvailable
? "bg-emerald-500/20"
: "bg-red-500/20"
}`}
>
{isAvailable ? (
<CheckCircle className="w-6 h-6 text-emerald-600" />
) : (
<XCircle className="w-6 h-6 text-red-600" />
)}
</div>
{/* Conteúdo */}
<div className="flex-1">
<div className="flex items-center gap-2 mb-2">
<h4
className={`text-sm font-black ${
isAvailable ? "text-emerald-900" : "text-red-900"
}`}
>
{isAvailable ? "Entrega Disponível" : "Entrega Indisponível"}
</h4>
{availability.occupancy >= 85 && availability.occupancy < 100 && (
<AlertCircle className="w-4 h-4 text-orange-500" />
)}
</div>
<p
className={`text-xs font-medium mb-3 ${
isAvailable ? "text-emerald-700" : "text-red-700"
}`}
>
{availability.message}
</p>
{/* Barra de ocupação */}
<div className="space-y-2">
<div className="flex items-center justify-between text-[10px] font-bold text-slate-600">
<span>Ocupação da Capacidade</span>
<span>{availability.occupancy.toFixed(1)}%</span>
</div>
<div className="w-full h-2 bg-slate-200 rounded-full overflow-hidden shadow-inner">
<div
className={`h-full transition-all duration-1000 ${occupancyColor}`}
style={{
width: `${Math.min(availability.occupancy, 100)}%`,
}}
></div>
</div>
<div className="grid grid-cols-3 gap-2 text-[10px] font-medium text-slate-600 mt-2">
<div>
<span className="block text-slate-400 mb-0.5">Capacidade</span>
<span className="font-black">{availability.capacity.toFixed(3)} Ton</span>
</div>
<div>
<span className="block text-slate-400 mb-0.5">Carga Atual</span>
<span className="font-black">{availability.currentLoad.toFixed(3)} Ton</span>
</div>
<div>
<span className="block text-slate-400 mb-0.5">Disponível</span>
<span className={`font-black ${
availability.availableCapacity >= orderWeight
? "text-emerald-600"
: "text-red-600"
}`}>
{availability.availableCapacity.toFixed(3)} Ton
</span>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default DeliveryAvailabilityStatus;