387 lines
17 KiB
TypeScript
387 lines
17 KiB
TypeScript
|
|
import React from "react";
|
||
|
|
import { OrderItem } from "../../types";
|
||
|
|
|
||
|
|
interface CheckoutProductsTableProps {
|
||
|
|
cart: OrderItem[];
|
||
|
|
onEdit?: (item: OrderItem) => void;
|
||
|
|
onDiscount?: (item: OrderItem) => void;
|
||
|
|
onRemove?: (item: OrderItem) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
const CheckoutProductsTable: React.FC<CheckoutProductsTableProps> = ({
|
||
|
|
cart,
|
||
|
|
onEdit,
|
||
|
|
onDiscount,
|
||
|
|
onRemove,
|
||
|
|
}) => {
|
||
|
|
// Renderizar badge de condição
|
||
|
|
const renderConditionBadge = (item: OrderItem) => {
|
||
|
|
if (item.discount && item.discount > 0) {
|
||
|
|
return (
|
||
|
|
<span className="bg-[#cc4b5c] text-white px-2 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Em promoção
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Renderizar badge de tipo de entrega
|
||
|
|
const renderDeliveryTypeBadge = (item: OrderItem) => {
|
||
|
|
if (item.deliveryType === "RI") {
|
||
|
|
return (
|
||
|
|
<span className="bg-[#385942] text-white px-2 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Retira imediata
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if (item.deliveryType === "EN") {
|
||
|
|
return (
|
||
|
|
<span className="bg-[#cc4b5c] text-white px-2 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Entrega
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if (item.deliveryType === "RP") {
|
||
|
|
return (
|
||
|
|
<span className="bg-[#ef7d00] text-white px-2 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Retira posterior
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if (item.deliveryType === "EF") {
|
||
|
|
return (
|
||
|
|
<span className="bg-[#5a3d7a] text-white px-2 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Encomenda
|
||
|
|
</span>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden mb-8">
|
||
|
|
{/* Cards View - Mobile/Tablet */}
|
||
|
|
<div className="lg:hidden">
|
||
|
|
{cart.length === 0 ? (
|
||
|
|
<div className="p-8 text-center text-slate-400 italic font-medium">
|
||
|
|
Nenhum item adicionado ao pedido.
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div className="divide-y divide-slate-100">
|
||
|
|
{cart.map((item, idx) => (
|
||
|
|
<div
|
||
|
|
key={item.id}
|
||
|
|
className="p-4 hover:bg-slate-50/50 transition-colors"
|
||
|
|
>
|
||
|
|
{/* Header do Card */}
|
||
|
|
<div className="flex items-start justify-between mb-3">
|
||
|
|
<div className="flex-1">
|
||
|
|
<div className="flex items-center gap-2 mb-2">
|
||
|
|
<span className="text-xs font-bold text-slate-400">
|
||
|
|
#{idx + 1}
|
||
|
|
</span>
|
||
|
|
<span className="text-xs font-medium text-slate-500">
|
||
|
|
Cód: {item.code}
|
||
|
|
</span>
|
||
|
|
{renderConditionBadge(item)}
|
||
|
|
</div>
|
||
|
|
<h3 className="font-bold text-sm text-[#002147] leading-tight mb-2">
|
||
|
|
{item.name}
|
||
|
|
</h3>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Informações do Produto */}
|
||
|
|
<div className="space-y-2 mb-3">
|
||
|
|
<div className="flex items-center justify-between text-xs">
|
||
|
|
<span className="text-slate-500">Marca:</span>
|
||
|
|
<span className="font-medium text-slate-700 uppercase">
|
||
|
|
{item.mark || "-"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center justify-between text-xs">
|
||
|
|
<span className="text-slate-500">Desconto:</span>
|
||
|
|
<span className="font-semibold text-slate-700">
|
||
|
|
{item.discount ? `${item.discount.toFixed(2)}%` : "0,00%"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center justify-between text-xs">
|
||
|
|
<span className="text-slate-500">F.Retira:</span>
|
||
|
|
<span className="font-medium text-slate-700">
|
||
|
|
{item.stockStore ? `Loja ${item.stockStore}` : "-"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center justify-between text-xs">
|
||
|
|
<span className="text-slate-500">Tipo de entrega:</span>
|
||
|
|
{renderDeliveryTypeBadge(item)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Valores */}
|
||
|
|
<div className="bg-slate-50 rounded-lg p-3 mb-3">
|
||
|
|
<div className="flex items-center justify-between mb-2">
|
||
|
|
<span className="text-xs text-slate-500">Preço unitário:</span>
|
||
|
|
<span className="font-bold text-sm text-slate-700">
|
||
|
|
R$ {item.price.toFixed(2)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center justify-between mb-2">
|
||
|
|
<span className="text-xs text-slate-500">Quantidade:</span>
|
||
|
|
<span className="font-bold text-sm text-slate-700">
|
||
|
|
{item.quantity.toFixed(2)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center justify-between pt-2 border-t border-slate-200">
|
||
|
|
<span className="text-xs font-bold text-slate-600">
|
||
|
|
Valor total:
|
||
|
|
</span>
|
||
|
|
<span className="font-black text-base text-[#002147]">
|
||
|
|
R$ {(item.price * item.quantity).toFixed(2)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Ações */}
|
||
|
|
<div className="flex items-center justify-end gap-2 pt-2 border-t border-slate-100">
|
||
|
|
<button
|
||
|
|
onClick={() => onEdit && onEdit(item)}
|
||
|
|
className="flex items-center gap-1.5 px-3 py-2 bg-emerald-50 text-emerald-600 rounded-lg hover:bg-emerald-100 transition-colors text-xs font-bold touch-manipulation"
|
||
|
|
title="Editar"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
Editar
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => onDiscount && onDiscount(item)}
|
||
|
|
className="flex items-center gap-1.5 px-3 py-2 bg-orange-50 text-orange-500 rounded-lg hover:bg-orange-100 transition-colors text-xs font-bold touch-manipulation"
|
||
|
|
title="Desconto"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
Desconto
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => onRemove && onRemove(item)}
|
||
|
|
className="flex items-center gap-1.5 px-3 py-2 bg-red-50 text-red-500 rounded-lg hover:bg-red-100 transition-colors text-xs font-bold touch-manipulation"
|
||
|
|
title="Remover"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
Remover
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Table View - Desktop */}
|
||
|
|
<div className="hidden lg:block overflow-x-auto custom-scrollbar">
|
||
|
|
<table className="w-full text-left text-xs border-collapse">
|
||
|
|
<thead>
|
||
|
|
<tr className="bg-slate-50 text-slate-500 font-bold uppercase border-b border-slate-200">
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Seq</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Código</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200 min-w-[300px]">
|
||
|
|
Produto
|
||
|
|
</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200 text-center">
|
||
|
|
Condição
|
||
|
|
</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Marca</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Descon</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">F.Retira</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">
|
||
|
|
Tipo de entre.
|
||
|
|
</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Preço</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">Qtde</th>
|
||
|
|
<th className="px-4 py-4 border-r border-slate-200">
|
||
|
|
Valor total
|
||
|
|
</th>
|
||
|
|
<th className="px-4 py-4 text-center">Ações</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody className="divide-y divide-slate-100">
|
||
|
|
{cart.length === 0 ? (
|
||
|
|
<tr>
|
||
|
|
<td
|
||
|
|
colSpan={12}
|
||
|
|
className="px-4 py-10 text-center text-slate-400 italic font-medium"
|
||
|
|
>
|
||
|
|
Nenhum item adicionado ao pedido.
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
) : (
|
||
|
|
cart.map((item, idx) => (
|
||
|
|
<tr
|
||
|
|
key={item.id}
|
||
|
|
className="hover:bg-slate-50/50 transition-colors"
|
||
|
|
>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-medium">
|
||
|
|
{idx + 1}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 text-slate-600">
|
||
|
|
{item.code}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-bold text-[#002147]">
|
||
|
|
{item.name}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 text-center">
|
||
|
|
{item.discount && item.discount > 0 && (
|
||
|
|
<span className="bg-[#cc4b5c] text-white px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Em promoção
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 text-slate-600 font-medium uppercase">
|
||
|
|
{item.mark || "-"}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-semibold text-slate-500">
|
||
|
|
{item.discount ? `${item.discount.toFixed(2)}%` : "0,00%"}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-medium text-slate-600">
|
||
|
|
{item.stockStore ? `Loja ${item.stockStore}` : "-"}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 text-center">
|
||
|
|
{item.deliveryType === "RI" && (
|
||
|
|
<span className="bg-[#385942] text-white px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Retira imediata
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
{item.deliveryType === "EN" && (
|
||
|
|
<span className="bg-[#cc4b5c] text-white px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Entrega
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
{item.deliveryType === "RP" && (
|
||
|
|
<span className="bg-[#ef7d00] text-white px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Retira posterior
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
{item.deliveryType === "EF" && (
|
||
|
|
<span className="bg-[#5a3d7a] text-white px-3 py-1 rounded-full text-[9px] font-bold uppercase tracking-tight">
|
||
|
|
Encomenda
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-bold text-slate-700">
|
||
|
|
R$ {item.price.toFixed(2)}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-bold text-slate-700">
|
||
|
|
{item.quantity.toFixed(2)}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4 border-r border-slate-100 font-black text-[#002147]">
|
||
|
|
R$ {(item.price * item.quantity).toFixed(2)}
|
||
|
|
</td>
|
||
|
|
<td className="px-4 py-4">
|
||
|
|
<div className="flex items-center justify-center space-x-1.5">
|
||
|
|
<button
|
||
|
|
onClick={() => onEdit && onEdit(item)}
|
||
|
|
className="p-1.5 bg-slate-100 text-emerald-600 rounded hover:bg-emerald-50 transition-colors"
|
||
|
|
title="Editar"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => onDiscount && onDiscount(item)}
|
||
|
|
className="p-1.5 bg-slate-100 text-orange-500 rounded hover:bg-orange-50 transition-colors"
|
||
|
|
title="Desconto"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => onRemove && onRemove(item)}
|
||
|
|
className="p-1.5 bg-slate-100 text-red-500 rounded hover:bg-red-50 transition-colors"
|
||
|
|
title="Remover"
|
||
|
|
>
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
stroke="currentColor"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth="2.5"
|
||
|
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
))
|
||
|
|
)}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default CheckoutProductsTable;
|
||
|
|
|
||
|
|
|