Add a ne model and card design across pages
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Plus, Search, Download, ShoppingCart, Truck, DollarSign, Calendar, Clock, CheckCircle, AlertCircle, Package, Eye, Edit } from 'lucide-react';
|
||||
import { Button, Input, Card, Badge, StatsGrid } from '../../../../components/ui';
|
||||
import { Button, Input, Card, Badge, StatsGrid, StatusCard, getStatusColor, StatusModal } from '../../../../components/ui';
|
||||
import { formatters } from '../../../../components/ui/Stats/StatsPresets';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
|
||||
const ProcurementPage: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState('orders');
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [modalMode, setModalMode] = useState<'view' | 'edit'>('view');
|
||||
const [selectedOrder, setSelectedOrder] = useState<typeof mockPurchaseOrders[0] | null>(null);
|
||||
|
||||
const mockPurchaseOrders = [
|
||||
{
|
||||
@@ -101,42 +104,27 @@ const ProcurementPage: React.FC = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const getStatusBadge = (status: string) => {
|
||||
const getPurchaseStatusConfig = (status: string, paymentStatus: string) => {
|
||||
const statusConfig = {
|
||||
pending: { color: 'warning', text: 'Pendiente', icon: Clock },
|
||||
approved: { color: 'info', text: 'Aprobado', icon: CheckCircle },
|
||||
in_transit: { color: 'secondary', text: 'En Tránsito', icon: Truck },
|
||||
delivered: { color: 'success', text: 'Entregado', icon: CheckCircle },
|
||||
cancelled: { color: 'error', text: 'Cancelado', icon: AlertCircle },
|
||||
pending: { text: 'Pendiente', icon: Clock },
|
||||
approved: { text: 'Aprobado', icon: CheckCircle },
|
||||
in_transit: { text: 'En Tránsito', icon: Truck },
|
||||
delivered: { text: 'Entregado', icon: CheckCircle },
|
||||
cancelled: { text: 'Cancelado', icon: AlertCircle },
|
||||
};
|
||||
|
||||
const config = statusConfig[status as keyof typeof statusConfig];
|
||||
const Icon = config?.icon;
|
||||
return (
|
||||
<Badge
|
||||
variant={config?.color as any}
|
||||
icon={Icon && <Icon size={12} />}
|
||||
text={config?.text || status}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const getPaymentStatusBadge = (status: string) => {
|
||||
const statusConfig = {
|
||||
pending: { color: 'warning', text: 'Pendiente', icon: Clock },
|
||||
paid: { color: 'success', text: 'Pagado', icon: CheckCircle },
|
||||
overdue: { color: 'error', text: 'Vencido', icon: AlertCircle },
|
||||
};
|
||||
const isPaymentPending = paymentStatus === 'pending';
|
||||
const isOverdue = paymentStatus === 'overdue';
|
||||
|
||||
const config = statusConfig[status as keyof typeof statusConfig];
|
||||
const Icon = config?.icon;
|
||||
return (
|
||||
<Badge
|
||||
variant={config?.color as any}
|
||||
icon={Icon && <Icon size={12} />}
|
||||
text={config?.text || status}
|
||||
/>
|
||||
);
|
||||
return {
|
||||
color: getStatusColor(status === 'in_transit' ? 'inTransit' : status),
|
||||
text: config?.text || status,
|
||||
icon: Icon,
|
||||
isCritical: isOverdue,
|
||||
isHighlight: isPaymentPending
|
||||
};
|
||||
};
|
||||
|
||||
const filteredOrders = mockPurchaseOrders.filter(order => {
|
||||
@@ -282,86 +270,52 @@ const ProcurementPage: React.FC = () => {
|
||||
{/* Purchase Orders Grid */}
|
||||
{activeTab === 'orders' && (
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{filteredOrders.map((order) => (
|
||||
<Card key={order.id} className="p-4">
|
||||
<div className="space-y-4">
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 bg-[var(--color-primary)]/10 p-2 rounded-lg">
|
||||
<ShoppingCart className="w-4 h-4 text-[var(--text-tertiary)]" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-mono text-sm font-semibold text-[var(--color-primary)]">
|
||||
{order.id}
|
||||
</div>
|
||||
<span className="font-medium text-[var(--text-primary)]">
|
||||
{order.supplier}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{getStatusBadge(order.status)}
|
||||
</div>
|
||||
|
||||
{/* Key Info */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-right">
|
||||
<div className="text-lg font-bold text-[var(--text-primary)]">
|
||||
{formatters.currency(order.totalAmount)}
|
||||
</div>
|
||||
<div className="text-xs text-[var(--text-tertiary)]">
|
||||
{order.items?.length} artículos
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-sm text-[var(--text-primary)]">
|
||||
{new Date(order.deliveryDate).toLocaleDateString('es-ES')}
|
||||
</div>
|
||||
<div className="text-xs text-[var(--text-tertiary)]">
|
||||
Entrega prevista
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Payment Status */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm text-[var(--text-secondary)]">
|
||||
Estado del pago:
|
||||
</div>
|
||||
{getPaymentStatusBadge(order.paymentStatus)}
|
||||
</div>
|
||||
|
||||
{/* Notes */}
|
||||
{order.notes && (
|
||||
<div className="bg-[var(--bg-secondary)] p-2 rounded text-xs text-[var(--text-secondary)] italic">
|
||||
"{order.notes}"
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-2 pt-2 border-t border-[var(--border-primary)]">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
onClick={() => console.log('View order', order.id)}
|
||||
>
|
||||
<Eye className="w-4 h-4 mr-1" />
|
||||
Ver
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
onClick={() => console.log('Edit order', order.id)}
|
||||
>
|
||||
<Edit className="w-4 h-4 mr-1" />
|
||||
Editar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
{filteredOrders.map((order) => {
|
||||
const statusConfig = getPurchaseStatusConfig(order.status, order.paymentStatus);
|
||||
const paymentNote = order.paymentStatus === 'pending' ? 'Pago pendiente' : order.paymentStatus === 'overdue' ? 'Pago vencido' : '';
|
||||
|
||||
return (
|
||||
<StatusCard
|
||||
key={order.id}
|
||||
id={order.id}
|
||||
statusIndicator={statusConfig}
|
||||
title={order.supplier}
|
||||
subtitle={order.id}
|
||||
primaryValue={formatters.currency(order.totalAmount)}
|
||||
primaryValueLabel={`${order.items?.length} artículos`}
|
||||
secondaryInfo={{
|
||||
label: 'Entrega',
|
||||
value: `${new Date(order.deliveryDate).toLocaleDateString('es-ES')} (pedido: ${new Date(order.orderDate).toLocaleDateString('es-ES')})`
|
||||
}}
|
||||
metadata={[
|
||||
...(order.notes ? [`"${order.notes}"`] : []),
|
||||
...(paymentNote ? [paymentNote] : [])
|
||||
]}
|
||||
actions={[
|
||||
{
|
||||
label: 'Ver',
|
||||
icon: Eye,
|
||||
variant: 'outline',
|
||||
onClick: () => {
|
||||
setSelectedOrder(order);
|
||||
setModalMode('view');
|
||||
setShowForm(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Editar',
|
||||
icon: Edit,
|
||||
variant: 'outline',
|
||||
onClick: () => {
|
||||
setSelectedOrder(order);
|
||||
setModalMode('edit');
|
||||
setShowForm(true);
|
||||
}
|
||||
}
|
||||
]}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -499,6 +453,115 @@ const ProcurementPage: React.FC = () => {
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Purchase Order Modal */}
|
||||
{showForm && selectedOrder && (
|
||||
<StatusModal
|
||||
isOpen={showForm}
|
||||
onClose={() => {
|
||||
setShowForm(false);
|
||||
setSelectedOrder(null);
|
||||
setModalMode('view');
|
||||
}}
|
||||
mode={modalMode}
|
||||
onModeChange={setModalMode}
|
||||
title={selectedOrder.supplier}
|
||||
subtitle={`Orden de Compra ${selectedOrder.id}`}
|
||||
statusIndicator={getPurchaseStatusConfig(selectedOrder.status, selectedOrder.paymentStatus)}
|
||||
size="lg"
|
||||
sections={[
|
||||
{
|
||||
title: 'Información del Proveedor',
|
||||
icon: Package,
|
||||
fields: [
|
||||
{
|
||||
label: 'Proveedor',
|
||||
value: selectedOrder.supplier,
|
||||
highlight: true,
|
||||
editable: true,
|
||||
required: true,
|
||||
placeholder: 'Nombre del proveedor'
|
||||
},
|
||||
{
|
||||
label: 'ID de Orden',
|
||||
value: selectedOrder.id
|
||||
},
|
||||
{
|
||||
label: 'Estado de Pago',
|
||||
value: selectedOrder.paymentStatus === 'paid' ? 'Pagado' : selectedOrder.paymentStatus === 'pending' ? 'Pendiente' : 'Vencido',
|
||||
type: 'status'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Fechas Importantes',
|
||||
icon: Calendar,
|
||||
fields: [
|
||||
{
|
||||
label: 'Fecha de pedido',
|
||||
value: selectedOrder.orderDate,
|
||||
type: 'date',
|
||||
editable: true
|
||||
},
|
||||
{
|
||||
label: 'Fecha de entrega',
|
||||
value: selectedOrder.deliveryDate,
|
||||
type: 'date',
|
||||
highlight: true,
|
||||
editable: true,
|
||||
required: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Información Financiera',
|
||||
icon: DollarSign,
|
||||
fields: [
|
||||
{
|
||||
label: 'Importe total',
|
||||
value: selectedOrder.totalAmount,
|
||||
type: 'currency',
|
||||
highlight: true,
|
||||
editable: true,
|
||||
required: true,
|
||||
placeholder: '0.00'
|
||||
},
|
||||
{
|
||||
label: 'Número de artículos',
|
||||
value: `${selectedOrder.items?.length} productos`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Artículos Pedidos',
|
||||
icon: ShoppingCart,
|
||||
fields: [
|
||||
{
|
||||
label: 'Lista de productos',
|
||||
value: selectedOrder.items?.map(item => `${item.name}: ${item.quantity} ${item.unit} - ${formatters.currency(item.total)}`),
|
||||
type: 'list',
|
||||
span: 2
|
||||
}
|
||||
]
|
||||
},
|
||||
...(selectedOrder.notes ? [{
|
||||
title: 'Notas Adicionales',
|
||||
fields: [
|
||||
{
|
||||
label: 'Observaciones',
|
||||
value: selectedOrder.notes,
|
||||
span: 2 as const,
|
||||
editable: true,
|
||||
placeholder: 'Añadir notas sobre la orden de compra...'
|
||||
}
|
||||
]
|
||||
}] : [])
|
||||
]}
|
||||
onEdit={() => {
|
||||
console.log('Editing purchase order:', selectedOrder.id);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user