Vendaweb-portal/components/ProductStoreDeliveryModal.tsx

259 lines
8.4 KiB
TypeScript
Raw Normal View History

2026-01-08 12:09:16 +00:00
import React, { useState, useEffect } from "react";
import { Product } from "../types";
import { productService } from "../src/services/product.service";
import { authService } from "../src/services/auth.service";
import FilialSelector from "./FilialSelector";
import { X } from "lucide-react";
interface Stock {
store: string;
storeName: string;
quantity: number;
work: boolean;
blocked: string;
breakdown: number;
transfer: number;
allowDelivery: number;
}
interface ProductStoreDeliveryModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm: (stockStore: string, deliveryType: string) => void;
product: Product | null;
quantity?: number;
}
const ProductStoreDeliveryModal: React.FC<ProductStoreDeliveryModalProps> = ({
isOpen,
onClose,
onConfirm,
product,
quantity = 1,
}) => {
const [selectedStore, setSelectedStore] = useState<string>("");
const [deliveryType, setDeliveryType] = useState<string>("");
const [stocks, setStocks] = useState<Stock[]>([]);
const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState<{
stockStore?: string;
deliveryType?: string;
}>({});
// Tipos de entrega - seguindo EXATAMENTE o padrão do Angular
const deliveryTypes = [
{ type: "RI", description: "Retira Imediata" },
{ type: "RP", description: "Retira Posterior" },
{ type: "EN", description: "Entrega" },
{ type: "EF", description: "Encomenda" },
];
// Carregar estoques quando o modal abrir
useEffect(() => {
if (isOpen && product?.code) {
loadStocks();
} else {
// Resetar estados quando fechar
setSelectedStore("");
setDeliveryType("");
setStocks([]);
setErrors({});
}
}, [isOpen, product]);
const loadStocks = async () => {
if (!product?.code) return;
try {
setLoading(true);
const store = authService.getStore();
if (!store) {
throw new Error("Loja não encontrada. Faça login novamente.");
}
const productId = parseInt(product.code);
if (isNaN(productId)) {
throw new Error("ID do produto inválido");
}
const stocksData = await productService.getProductStocks(store, productId);
setStocks(stocksData);
// Selecionar a primeira loja por padrão se houver apenas uma
if (stocksData.length === 1) {
setSelectedStore(stocksData[0].store);
}
} catch (err: any) {
console.error("Erro ao carregar estoques:", err);
setErrors({ stockStore: "Erro ao carregar lojas de estoque" });
} finally {
setLoading(false);
}
};
const handleConfirm = () => {
const newErrors: { stockStore?: string; deliveryType?: string } = {};
// Validar loja de estoque
if (!selectedStore) {
newErrors.stockStore = "Selecione uma loja de estoque";
}
// Validar tipo de entrega
if (!deliveryType) {
newErrors.deliveryType = "Selecione um tipo de entrega";
}
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors);
return;
}
// Se tudo estiver válido, confirmar
onConfirm(selectedStore, deliveryType);
onClose();
};
if (!isOpen || !product) return null;
return (
<div className="fixed inset-0 z-[200] flex items-center justify-center">
{/* Overlay */}
<div
className="absolute inset-0 bg-[#001f3f]/60 backdrop-blur-sm"
onClick={onClose}
/>
{/* Modal */}
<div className="relative bg-white rounded-3xl shadow-2xl max-w-md w-full mx-4 max-h-[90vh] flex flex-col">
{/* Header */}
<div className="p-4 lg:p-6 bg-[#002147] text-white rounded-t-3xl relative overflow-hidden flex items-center justify-between">
<div className="flex-1 pr-4">
<h3 className="text-lg font-black leading-tight">
{product.code} - {product.name}
</h3>
</div>
<button
onClick={onClose}
className="p-2 text-white/70 hover:text-white hover:bg-white/10 rounded-lg transition-colors touch-manipulation flex-shrink-0"
title="Fechar"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Content */}
<div className="p-4 lg:p-6 overflow-y-auto flex-1">
<div className="mb-6">
<h4 className="text-base font-black text-orange-600 mb-4">
Selecione a loja de estoque e forma de entrega
</h4>
</div>
{/* LOCAL DE ESTOQUE */}
<div className="mb-6">
<label className="block text-xs font-bold text-slate-700 uppercase tracking-wide mb-2">
LOCAL DE ESTOQUE
</label>
{loading ? (
<div className="flex items-center justify-center py-8">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-orange-500"></div>
<span className="ml-2 text-sm text-slate-500">
Carregando lojas...
</span>
</div>
) : stocks.length > 0 ? (
<FilialSelector
stocks={stocks}
value={selectedStore}
onValueChange={(value) => {
setSelectedStore(value);
if (errors.stockStore) {
setErrors((prev) => ({ ...prev, stockStore: undefined }));
}
}}
placeholder="Selecione a loja..."
label=""
className="w-full"
/>
) : (
<div className="p-4 bg-slate-50 border border-slate-200 rounded-lg">
<p className="text-sm text-slate-600">
Nenhuma loja de estoque disponível
</p>
</div>
)}
{errors.stockStore && (
<div className="flex items-center gap-1 mt-1 text-red-600 text-xs">
<span>{errors.stockStore}</span>
</div>
)}
</div>
{/* TIPO DE ENTREGA */}
<div className="mb-6">
<label className="block text-xs font-bold text-slate-700 uppercase tracking-wide mb-3">
TIPO DE ENTREGA
</label>
<div className="space-y-3">
{deliveryTypes.map((dt) => (
<label
key={dt.type}
className="flex items-center p-3 border border-slate-200 rounded-lg cursor-pointer hover:bg-slate-50 transition-colors group"
>
<input
type="radio"
name="deliveryType"
value={dt.type}
checked={deliveryType === dt.type}
onChange={(e) => {
setDeliveryType(e.target.value);
if (errors.deliveryType) {
setErrors((prev) => ({
...prev,
deliveryType: undefined,
}));
}
}}
className="w-4 h-4 text-orange-500 border-slate-300 focus:ring-orange-500 focus:ring-2 cursor-pointer"
/>
<span className="ml-3 text-sm font-medium text-slate-700 group-hover:text-slate-900">
{dt.description}
</span>
</label>
))}
</div>
{errors.deliveryType && (
<div className="flex items-center gap-1 mt-2 text-red-600 text-xs">
<span>{errors.deliveryType}</span>
</div>
)}
<p className="text-xs text-slate-500 mt-3">
Informe a forma de entrega do produto
</p>
</div>
</div>
{/* Actions */}
<div className="p-4 lg:p-6 pt-0 flex gap-3">
<button
onClick={onClose}
className="flex-1 py-3 px-4 bg-white border-2 border-slate-300 text-slate-700 font-bold uppercase text-xs tracking-wider rounded-xl hover:bg-slate-50 transition-all"
>
Cancelar
</button>
<button
onClick={handleConfirm}
className="flex-1 py-3 px-4 bg-blue-600 text-white font-bold uppercase text-xs tracking-wider rounded-xl hover:bg-blue-700 transition-all shadow-lg"
>
Gravar
</button>
</div>
</div>
</div>
);
};
export default ProductStoreDeliveryModal;