import React, { useState } from 'react'; import { Plus, Building2, Phone, Mail, Eye, Edit, CheckCircle, AlertCircle, Timer, Users, Euro, Loader } from 'lucide-react'; import { Button, Badge, StatsGrid, StatusCard, getStatusColor, EditViewModal, SearchAndFilter, type FilterConfig } from '../../../../components/ui'; import { formatters } from '../../../../components/ui/Stats/StatsPresets'; import { PageHeader } from '../../../../components/layout'; import { SupplierStatus, SupplierType, PaymentTerms } from '../../../../api/types/suppliers'; import { useSuppliers, useSupplierStatistics } from '../../../../api/hooks/suppliers'; import { useCurrentTenant } from '../../../../stores/tenant.store'; import { useAuthUser } from '../../../../stores/auth.store'; import { useTranslation } from 'react-i18next'; const SuppliersPage: React.FC = () => { const [activeTab] = useState('all'); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [typeFilter, setTypeFilter] = useState(''); const [showForm, setShowForm] = useState(false); const [modalMode, setModalMode] = useState<'view' | 'edit'>('view'); const [selectedSupplier, setSelectedSupplier] = useState(null); const [isCreating, setIsCreating] = useState(false); // Get tenant ID from tenant store (preferred) or auth user (fallback) const currentTenant = useCurrentTenant(); const user = useAuthUser(); const tenantId = currentTenant?.id || user?.tenant_id || ''; // API hooks const { data: suppliersData, isLoading: suppliersLoading, error: suppliersError } = useSuppliers(tenantId, { search_term: searchTerm || undefined, status: activeTab !== 'all' ? activeTab as any : undefined, limit: 100 }); const { data: statisticsData, isLoading: statisticsLoading, error: statisticsError } = useSupplierStatistics(tenantId); const suppliers = suppliersData || []; const { t } = useTranslation(['suppliers', 'common']); const getSupplierStatusConfig = (status: SupplierStatus) => { const statusConfig = { [SupplierStatus.ACTIVE]: { text: t(`suppliers:status.${status.toLowerCase()}`), icon: CheckCircle }, [SupplierStatus.INACTIVE]: { text: t(`suppliers:status.${status.toLowerCase()}`), icon: Timer }, [SupplierStatus.PENDING_APPROVAL]: { text: t(`suppliers:status.${status.toLowerCase()}`), icon: AlertCircle }, [SupplierStatus.SUSPENDED]: { text: t(`suppliers:status.${status.toLowerCase()}`), icon: AlertCircle }, [SupplierStatus.BLACKLISTED]: { text: t(`suppliers:status.${status.toLowerCase()}`), icon: AlertCircle }, }; const config = statusConfig[status]; const Icon = config?.icon; return { color: getStatusColor(status === SupplierStatus.ACTIVE ? 'completed' : status === SupplierStatus.PENDING_APPROVAL ? 'pending' : 'cancelled'), text: config?.text || status, icon: Icon, isCritical: status === SupplierStatus.BLACKLISTED, isHighlight: status === SupplierStatus.PENDING_APPROVAL }; }; const getSupplierTypeText = (type: SupplierType): string => { return t(`suppliers:types.${type.toLowerCase()}`); }; const getPaymentTermsText = (terms: PaymentTerms): string => { return t(`suppliers:payment_terms.${terms.toLowerCase()}`); }; // Apply additional client-side filtering const filteredSuppliers = suppliers.filter(supplier => { const matchesStatus = !statusFilter || supplier.status === statusFilter; const matchesType = !typeFilter || supplier.supplier_type === typeFilter; return matchesStatus && matchesType; }); const supplierStats = statisticsData || { total_suppliers: 0, active_suppliers: 0, pending_suppliers: 0, avg_quality_rating: 0, avg_delivery_rating: 0, total_spend: 0 }; const stats = [ { title: 'Total Proveedores', value: supplierStats.total_suppliers, variant: 'default' as const, icon: Building2, }, { title: 'Activos', value: supplierStats.active_suppliers, variant: 'success' as const, icon: CheckCircle, }, { title: 'Pendientes', value: supplierStats.pending_suppliers, variant: 'warning' as const, icon: AlertCircle, }, { title: 'Gasto Total', value: formatters.currency(supplierStats.total_spend), variant: 'info' as const, icon: Euro, }, { title: 'Calidad Media', value: supplierStats.avg_quality_rating?.toFixed(1) || '0.0', variant: 'success' as const, icon: CheckCircle, }, { title: 'Entrega Media', value: supplierStats.avg_delivery_rating?.toFixed(1) || '0.0', variant: 'info' as const, icon: Building2, }, ]; // Loading state if (suppliersLoading || statisticsLoading) { return (

Cargando proveedores...

); } // Error state if (suppliersError || statisticsError) { return (

Error al cargar los proveedores

{(suppliersError as any)?.message || (statisticsError as any)?.message || 'Error desconocido'}

); } return (
{ setSelectedSupplier({ name: '', contact_person: '', email: '', phone: '', city: '', country: '', supplier_code: '', supplier_type: SupplierType.INGREDIENTS, payment_terms: PaymentTerms.NET_30, standard_lead_time: 3, minimum_order_amount: 0, credit_limit: 0, currency: 'EUR' }); setIsCreating(true); setModalMode('edit'); setShowForm(true); } } ]} /> {/* Stats Grid */} {/* Search and Filter Controls */} setStatusFilter(value as string), placeholder: 'Todos los estados', options: Object.values(SupplierStatus).map(status => ({ value: status, label: t(`suppliers:status.${status.toLowerCase()}`) })) }, { key: 'type', label: 'Tipo', type: 'dropdown', value: typeFilter, onChange: (value) => setTypeFilter(value as string), placeholder: 'Todos los tipos', options: Object.values(SupplierType).map(type => ({ value: type, label: t(`suppliers:types.${type.toLowerCase()}`) })) } ] as FilterConfig[]} /> {/* Suppliers Grid */}
{filteredSuppliers.map((supplier) => { const statusConfig = getSupplierStatusConfig(supplier.status); return ( { setSelectedSupplier(supplier); setIsCreating(false); setModalMode('view'); setShowForm(true); }} actions={[ // Primary action - View supplier details { label: 'Ver Detalles', icon: Eye, variant: 'primary', priority: 'primary', onClick: () => { setSelectedSupplier(supplier); setIsCreating(false); setModalMode('view'); setShowForm(true); } }, // Secondary action - Edit supplier { label: 'Editar', icon: Edit, priority: 'secondary', onClick: () => { setSelectedSupplier(supplier); setIsCreating(false); setModalMode('edit'); setShowForm(true); } } ]} /> ); })}
{/* Empty State */} {filteredSuppliers.length === 0 && (

No se encontraron proveedores

Intenta ajustar la búsqueda o crear un nuevo proveedor

)} {/* Supplier Details Modal */} {showForm && selectedSupplier && (() => { const sections = [ { title: 'Información de Contacto', icon: Users, fields: [ { label: 'Nombre', value: selectedSupplier.name || '', type: 'text', highlight: true, editable: true, required: true, placeholder: 'Nombre del proveedor' }, { label: 'Persona de Contacto', value: selectedSupplier.contact_person || '', type: 'text', editable: true, placeholder: 'Nombre del contacto' }, { label: 'Email', value: selectedSupplier.email || '', type: 'email', editable: true, placeholder: 'email@ejemplo.com' }, { label: 'Teléfono', value: selectedSupplier.phone || '', type: 'tel', editable: true, placeholder: '+34 123 456 789' }, { label: 'Ciudad', value: selectedSupplier.city || '', type: 'text', editable: true, placeholder: 'Ciudad' }, { label: 'País', value: selectedSupplier.country || '', type: 'text', editable: true, placeholder: 'País' } ] }, { title: 'Información Comercial', icon: Building2, fields: [ { label: 'Código de Proveedor', value: selectedSupplier.supplier_code || '', type: 'text', highlight: true, editable: true, placeholder: 'Código único' }, { label: 'Tipo de Proveedor', value: selectedSupplier.supplier_type || SupplierType.INGREDIENTS, type: 'select', editable: true, options: Object.values(SupplierType).map(value => ({ value, label: t(`suppliers:types.${value.toLowerCase()}`) })) }, { label: 'Condiciones de Pago', value: selectedSupplier.payment_terms || PaymentTerms.NET_30, type: 'select', editable: true, options: Object.values(PaymentTerms).map(value => ({ value, label: t(`suppliers:payment_terms.${value.toLowerCase()}`) })) }, { label: 'Tiempo de Entrega (días)', value: selectedSupplier.standard_lead_time || 3, type: 'number', editable: true, placeholder: '3' }, { label: 'Pedido Mínimo', value: selectedSupplier.minimum_order_amount || 0, type: 'currency', editable: true, placeholder: '0.00' }, { label: 'Límite de Crédito', value: selectedSupplier.credit_limit || 0, type: 'currency', editable: true, placeholder: '0.00' } ] }, { title: 'Rendimiento y Estadísticas', icon: Euro, fields: [ { label: 'Moneda', value: selectedSupplier.currency || 'EUR', type: 'text', editable: true, placeholder: 'EUR' }, { label: 'Fecha de Creación', value: selectedSupplier.created_at, type: 'datetime', highlight: true }, { label: 'Última Actualización', value: selectedSupplier.updated_at, type: 'datetime' } ] }, ...(selectedSupplier.notes ? [{ title: 'Notas', fields: [ { label: 'Observaciones', value: selectedSupplier.notes, type: 'list', span: 2 as const, editable: true, placeholder: 'Notas sobre el proveedor' } ] }] : []) ]; return ( { setShowForm(false); setSelectedSupplier(null); setModalMode('view'); setIsCreating(false); }} mode={modalMode} onModeChange={setModalMode} title={isCreating ? 'Nuevo Proveedor' : selectedSupplier.name || 'Proveedor'} subtitle={isCreating ? 'Crear nuevo proveedor' : `Proveedor ${selectedSupplier.supplier_code || ''}`} statusIndicator={isCreating ? undefined : getSupplierStatusConfig(selectedSupplier.status)} size="lg" sections={sections} showDefaultActions={true} onSave={async () => { // TODO: Implement save functionality console.log('Saving supplier:', selectedSupplier); }} onFieldChange={(sectionIndex, fieldIndex, value) => { // Update the selectedSupplier state when fields change const newSupplier = { ...selectedSupplier }; const section = sections[sectionIndex]; const field = section.fields[fieldIndex]; // Map field labels to supplier properties const fieldMapping: { [key: string]: string } = { 'Nombre': 'name', 'Persona de Contacto': 'contact_person', 'Email': 'email', 'Teléfono': 'phone', 'Ciudad': 'city', 'País': 'country', 'Código de Proveedor': 'supplier_code', 'Tipo de Proveedor': 'supplier_type', 'Condiciones de Pago': 'payment_terms', 'Tiempo de Entrega (días)': 'standard_lead_time', 'Pedido Mínimo': 'minimum_order_amount', 'Límite de Crédito': 'credit_limit', 'Moneda': 'currency', 'Observaciones': 'notes' }; const propertyName = fieldMapping[field.label]; if (propertyName) { newSupplier[propertyName] = value; setSelectedSupplier(newSupplier); } }} /> ); })()}
); }; export default SuppliersPage;