Create new services: inventory, recipes, suppliers
This commit is contained in:
@@ -0,0 +1,619 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import {
|
||||
Search,
|
||||
Filter,
|
||||
Plus,
|
||||
Download,
|
||||
RefreshCw,
|
||||
ChevronDown,
|
||||
FileText,
|
||||
TrendingUp,
|
||||
Clock,
|
||||
AlertCircle,
|
||||
Package,
|
||||
DollarSign,
|
||||
Grid3X3,
|
||||
List
|
||||
} from 'lucide-react';
|
||||
|
||||
import {
|
||||
usePurchaseOrders,
|
||||
PurchaseOrder,
|
||||
CreatePurchaseOrderRequest
|
||||
} from '../../api/hooks/useSuppliers';
|
||||
import { useAuth } from '../../api/hooks/useAuth';
|
||||
|
||||
import PurchaseOrderCard from './PurchaseOrderCard';
|
||||
import PurchaseOrderForm from './PurchaseOrderForm';
|
||||
import Card from '../ui/Card';
|
||||
import Button from '../ui/Button';
|
||||
import LoadingSpinner from '../ui/LoadingSpinner';
|
||||
|
||||
interface PurchaseOrderFilters {
|
||||
search: string;
|
||||
supplier_id: string;
|
||||
status: string;
|
||||
priority: string;
|
||||
date_from: string;
|
||||
date_to: string;
|
||||
}
|
||||
|
||||
const PurchaseOrderManagementPage: React.FC = () => {
|
||||
const { user } = useAuth();
|
||||
const {
|
||||
purchaseOrders,
|
||||
purchaseOrder: selectedPurchaseOrder,
|
||||
statistics,
|
||||
ordersRequiringApproval,
|
||||
overdueOrders,
|
||||
isLoading,
|
||||
isCreating,
|
||||
error,
|
||||
pagination,
|
||||
loadPurchaseOrders,
|
||||
loadPurchaseOrder,
|
||||
loadStatistics,
|
||||
loadOrdersRequiringApproval,
|
||||
loadOverdueOrders,
|
||||
createPurchaseOrder,
|
||||
updateOrderStatus,
|
||||
approveOrder,
|
||||
sendToSupplier,
|
||||
cancelOrder,
|
||||
clearError,
|
||||
refresh,
|
||||
setPage
|
||||
} = usePurchaseOrders();
|
||||
|
||||
const [filters, setFilters] = useState<PurchaseOrderFilters>({
|
||||
search: '',
|
||||
supplier_id: '',
|
||||
status: '',
|
||||
priority: '',
|
||||
date_from: '',
|
||||
date_to: ''
|
||||
});
|
||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
const [showPurchaseOrderForm, setShowPurchaseOrderForm] = useState(false);
|
||||
const [selectedOrder, setSelectedOrder] = useState<PurchaseOrder | null>(null);
|
||||
|
||||
// Load initial data
|
||||
useEffect(() => {
|
||||
if (user?.tenant_id) {
|
||||
loadPurchaseOrders();
|
||||
loadStatistics();
|
||||
loadOrdersRequiringApproval();
|
||||
loadOverdueOrders();
|
||||
}
|
||||
}, [user?.tenant_id]);
|
||||
|
||||
// Apply filters
|
||||
useEffect(() => {
|
||||
const searchParams: any = {};
|
||||
|
||||
if (filters.search) {
|
||||
searchParams.search_term = filters.search;
|
||||
}
|
||||
if (filters.supplier_id) {
|
||||
searchParams.supplier_id = filters.supplier_id;
|
||||
}
|
||||
if (filters.status) {
|
||||
searchParams.status = filters.status;
|
||||
}
|
||||
if (filters.priority) {
|
||||
searchParams.priority = filters.priority;
|
||||
}
|
||||
if (filters.date_from) {
|
||||
searchParams.date_from = filters.date_from;
|
||||
}
|
||||
if (filters.date_to) {
|
||||
searchParams.date_to = filters.date_to;
|
||||
}
|
||||
|
||||
loadPurchaseOrders(searchParams);
|
||||
}, [filters]);
|
||||
|
||||
// Status options
|
||||
const statusOptions = [
|
||||
{ value: '', label: 'Todos los estados' },
|
||||
{ value: 'DRAFT', label: 'Borrador' },
|
||||
{ value: 'PENDING_APPROVAL', label: 'Pendiente Aprobación' },
|
||||
{ value: 'APPROVED', label: 'Aprobado' },
|
||||
{ value: 'SENT_TO_SUPPLIER', label: 'Enviado a Proveedor' },
|
||||
{ value: 'CONFIRMED', label: 'Confirmado' },
|
||||
{ value: 'PARTIALLY_RECEIVED', label: 'Recibido Parcial' },
|
||||
{ value: 'COMPLETED', label: 'Completado' },
|
||||
{ value: 'CANCELLED', label: 'Cancelado' },
|
||||
{ value: 'DISPUTED', label: 'En Disputa' }
|
||||
];
|
||||
|
||||
// Priority options
|
||||
const priorityOptions = [
|
||||
{ value: '', label: 'Todas las prioridades' },
|
||||
{ value: 'LOW', label: 'Baja' },
|
||||
{ value: 'NORMAL', label: 'Normal' },
|
||||
{ value: 'HIGH', label: 'Alta' },
|
||||
{ value: 'URGENT', label: 'Urgente' }
|
||||
];
|
||||
|
||||
// Handle purchase order creation
|
||||
const handleCreatePurchaseOrder = async (orderData: CreatePurchaseOrderRequest) => {
|
||||
const order = await createPurchaseOrder(orderData);
|
||||
if (order) {
|
||||
setShowPurchaseOrderForm(false);
|
||||
// Refresh statistics and special lists
|
||||
loadStatistics();
|
||||
if (order.status === 'PENDING_APPROVAL') loadOrdersRequiringApproval();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle order approval
|
||||
const handleApproveOrder = async (
|
||||
order: PurchaseOrder,
|
||||
action: 'approve' | 'reject',
|
||||
notes?: string
|
||||
) => {
|
||||
const updatedOrder = await approveOrder(order.id, action, notes);
|
||||
if (updatedOrder) {
|
||||
// Refresh relevant lists
|
||||
loadOrdersRequiringApproval();
|
||||
loadStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle send to supplier
|
||||
const handleSendToSupplier = async (order: PurchaseOrder, sendEmail: boolean = true) => {
|
||||
const updatedOrder = await sendToSupplier(order.id, sendEmail);
|
||||
if (updatedOrder) {
|
||||
loadStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle cancel order
|
||||
const handleCancelOrder = async (order: PurchaseOrder, reason: string) => {
|
||||
const updatedOrder = await cancelOrder(order.id, reason);
|
||||
if (updatedOrder) {
|
||||
loadStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle clear filters
|
||||
const handleClearFilters = () => {
|
||||
setFilters({
|
||||
search: '',
|
||||
supplier_id: '',
|
||||
status: '',
|
||||
priority: '',
|
||||
date_from: '',
|
||||
date_to: ''
|
||||
});
|
||||
};
|
||||
|
||||
// Format currency
|
||||
const formatCurrency = (amount: number) => {
|
||||
return new Intl.NumberFormat('es-ES', {
|
||||
style: 'currency',
|
||||
currency: 'EUR',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount);
|
||||
};
|
||||
|
||||
// Statistics cards data
|
||||
const statsCards = useMemo(() => {
|
||||
if (!statistics) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
title: 'Total Pedidos',
|
||||
value: statistics.total_orders.toString(),
|
||||
icon: FileText,
|
||||
color: 'blue'
|
||||
},
|
||||
{
|
||||
title: 'Este Mes',
|
||||
value: statistics.this_month_orders.toString(),
|
||||
icon: TrendingUp,
|
||||
color: 'green'
|
||||
},
|
||||
{
|
||||
title: 'Pendientes Aprobación',
|
||||
value: statistics.pending_approval.toString(),
|
||||
icon: Clock,
|
||||
color: 'yellow'
|
||||
},
|
||||
{
|
||||
title: 'Gasto Este Mes',
|
||||
value: formatCurrency(statistics.this_month_spend),
|
||||
icon: DollarSign,
|
||||
color: 'purple'
|
||||
}
|
||||
];
|
||||
}, [statistics]);
|
||||
|
||||
if (isLoading && !purchaseOrders.length) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-64">
|
||||
<LoadingSpinner size="lg" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">Órdenes de Compra</h1>
|
||||
<p className="text-gray-600">Gestiona tus pedidos y compras a proveedores</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={refresh}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<RefreshCw className={`w-4 h-4 mr-2 ${isLoading ? 'animate-spin' : ''}`} />
|
||||
Actualizar
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => setShowPurchaseOrderForm(true)}
|
||||
disabled={isCreating}
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Nueva Orden
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Error display */}
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<AlertCircle className="w-5 h-5 text-red-500" />
|
||||
<span className="text-red-700">{error}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={clearError}
|
||||
className="text-red-500 hover:text-red-700"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Statistics Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{statsCards.map((stat, index) => (
|
||||
<Card key={index} className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-600">{stat.title}</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{stat.value}</p>
|
||||
</div>
|
||||
<div className={`w-12 h-12 rounded-lg flex items-center justify-center ${
|
||||
stat.color === 'blue' ? 'bg-blue-100' :
|
||||
stat.color === 'green' ? 'bg-green-100' :
|
||||
stat.color === 'yellow' ? 'bg-yellow-100' :
|
||||
'bg-purple-100'
|
||||
}`}>
|
||||
<stat.icon className={`w-6 h-6 ${
|
||||
stat.color === 'blue' ? 'text-blue-600' :
|
||||
stat.color === 'green' ? 'text-green-600' :
|
||||
stat.color === 'yellow' ? 'text-yellow-600' :
|
||||
'text-purple-600'
|
||||
}`} />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Quick Lists */}
|
||||
{(ordersRequiringApproval.length > 0 || overdueOrders.length > 0) && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{/* Orders Requiring Approval */}
|
||||
{ordersRequiringApproval.length > 0 && (
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||||
<Clock className="w-5 h-5 text-yellow-500 mr-2" />
|
||||
Requieren Aprobación
|
||||
</h3>
|
||||
<span className="bg-yellow-100 text-yellow-800 px-2 py-1 rounded-full text-sm">
|
||||
{ordersRequiringApproval.length}
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{ordersRequiringApproval.slice(0, 3).map(order => (
|
||||
<PurchaseOrderCard
|
||||
key={order.id}
|
||||
order={order}
|
||||
compact
|
||||
onApprove={handleApproveOrder}
|
||||
onViewDetails={(order) => setSelectedOrder(order)}
|
||||
/>
|
||||
))}
|
||||
{ordersRequiringApproval.length > 3 && (
|
||||
<button
|
||||
onClick={() => setFilters(prev => ({ ...prev, status: 'PENDING_APPROVAL' }))}
|
||||
className="w-full py-2 text-center text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
||||
>
|
||||
Ver {ordersRequiringApproval.length - 3} más...
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Overdue Orders */}
|
||||
{overdueOrders.length > 0 && (
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
|
||||
<AlertCircle className="w-5 h-5 text-red-500 mr-2" />
|
||||
Pedidos Vencidos
|
||||
</h3>
|
||||
<span className="bg-red-100 text-red-800 px-2 py-1 rounded-full text-sm">
|
||||
{overdueOrders.length}
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{overdueOrders.slice(0, 3).map(order => (
|
||||
<PurchaseOrderCard
|
||||
key={order.id}
|
||||
order={order}
|
||||
compact
|
||||
onViewDetails={(order) => setSelectedOrder(order)}
|
||||
/>
|
||||
))}
|
||||
{overdueOrders.length > 3 && (
|
||||
<button
|
||||
onClick={() => {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
setFilters(prev => ({ ...prev, date_to: today }));
|
||||
}}
|
||||
className="w-full py-2 text-center text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
||||
>
|
||||
Ver {overdueOrders.length - 3} más...
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Filters and Search */}
|
||||
<Card>
|
||||
<div className="flex flex-col lg:flex-row lg:items-center justify-between space-y-4 lg:space-y-0">
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Search */}
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Buscar pedidos..."
|
||||
value={filters.search}
|
||||
onChange={(e) => setFilters(prev => ({ ...prev, search: e.target.value }))}
|
||||
className="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 w-64"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Filter Toggle */}
|
||||
<button
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
className={`flex items-center space-x-2 px-3 py-2 border rounded-lg transition-colors ${
|
||||
showFilters ? 'bg-blue-50 border-blue-200 text-blue-700' : 'border-gray-300 text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<Filter className="w-4 h-4" />
|
||||
<span>Filtros</span>
|
||||
<ChevronDown className={`w-4 h-4 transform transition-transform ${showFilters ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
|
||||
{/* Active filters indicator */}
|
||||
{(filters.status || filters.priority || filters.supplier_id || filters.date_from || filters.date_to) && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-sm text-gray-500">Filtros activos:</span>
|
||||
{filters.status && (
|
||||
<span className="px-2 py-1 bg-blue-100 text-blue-800 text-xs rounded-full">
|
||||
{statusOptions.find(opt => opt.value === filters.status)?.label}
|
||||
</span>
|
||||
)}
|
||||
{filters.priority && (
|
||||
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
|
||||
{priorityOptions.find(opt => opt.value === filters.priority)?.label}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
onClick={handleClearFilters}
|
||||
className="text-xs text-red-600 hover:text-red-700"
|
||||
>
|
||||
Limpiar
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-3">
|
||||
{/* View Mode Toggle */}
|
||||
<div className="flex items-center space-x-1 border border-gray-300 rounded-lg p-1">
|
||||
<button
|
||||
onClick={() => setViewMode('grid')}
|
||||
className={`p-2 rounded ${viewMode === 'grid' ? 'bg-blue-100 text-blue-600' : 'text-gray-400 hover:text-gray-600'}`}
|
||||
>
|
||||
<Grid3X3 className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setViewMode('list')}
|
||||
className={`p-2 rounded ${viewMode === 'list' ? 'bg-blue-100 text-blue-600' : 'text-gray-400 hover:text-gray-600'}`}
|
||||
>
|
||||
<List className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Button variant="outline">
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Exportar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expanded Filters */}
|
||||
{showFilters && (
|
||||
<div className="mt-4 pt-4 border-t grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Estado
|
||||
</label>
|
||||
<select
|
||||
value={filters.status}
|
||||
onChange={(e) => setFilters(prev => ({ ...prev, status: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
{statusOptions.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Prioridad
|
||||
</label>
|
||||
<select
|
||||
value={filters.priority}
|
||||
onChange={(e) => setFilters(prev => ({ ...prev, priority: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
{priorityOptions.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Fecha Desde
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={filters.date_from}
|
||||
onChange={(e) => setFilters(prev => ({ ...prev, date_from: e.target.value }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* Purchase Orders List */}
|
||||
<div>
|
||||
{purchaseOrders.length === 0 ? (
|
||||
<Card className="text-center py-12">
|
||||
<Package className="w-16 h-16 text-gray-400 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">No se encontraron pedidos</h3>
|
||||
<p className="text-gray-600 mb-4">
|
||||
{filters.search || filters.status || filters.priority
|
||||
? 'Intenta ajustar tus filtros de búsqueda'
|
||||
: 'Comienza creando tu primera orden de compra'
|
||||
}
|
||||
</p>
|
||||
{!(filters.search || filters.status || filters.priority) && (
|
||||
<Button onClick={() => setShowPurchaseOrderForm(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Nueva Orden
|
||||
</Button>
|
||||
)}
|
||||
</Card>
|
||||
) : (
|
||||
<div className={
|
||||
viewMode === 'grid'
|
||||
? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6'
|
||||
: 'space-y-4'
|
||||
}>
|
||||
{purchaseOrders.map(order => (
|
||||
<PurchaseOrderCard
|
||||
key={order.id}
|
||||
order={order}
|
||||
compact={viewMode === 'list'}
|
||||
onEdit={(order) => {
|
||||
setSelectedOrder(order);
|
||||
setShowPurchaseOrderForm(true);
|
||||
}}
|
||||
onViewDetails={(order) => setSelectedOrder(order)}
|
||||
onApprove={handleApproveOrder}
|
||||
onSendToSupplier={handleSendToSupplier}
|
||||
onCancel={handleCancelOrder}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{purchaseOrders.length > 0 && pagination.totalPages > 1 && (
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="text-sm text-gray-700">
|
||||
Mostrando {((pagination.page - 1) * pagination.limit) + 1} a{' '}
|
||||
{Math.min(pagination.page * pagination.limit, pagination.total)} de{' '}
|
||||
{pagination.total} pedidos
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => setPage(pagination.page - 1)}
|
||||
disabled={pagination.page === 1}
|
||||
className="px-3 py-2 border border-gray-300 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50"
|
||||
>
|
||||
Anterior
|
||||
</button>
|
||||
|
||||
<span className="px-3 py-2 bg-blue-50 text-blue-600 rounded-lg">
|
||||
{pagination.page}
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={() => setPage(pagination.page + 1)}
|
||||
disabled={pagination.page >= pagination.totalPages}
|
||||
className="px-3 py-2 border border-gray-300 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50"
|
||||
>
|
||||
Siguiente
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Purchase Order Form Modal */}
|
||||
{showPurchaseOrderForm && (
|
||||
<PurchaseOrderForm
|
||||
order={selectedOrder}
|
||||
isOpen={showPurchaseOrderForm}
|
||||
isCreating={isCreating}
|
||||
onSubmit={selectedOrder ?
|
||||
(data) => {
|
||||
// Handle update logic here if needed
|
||||
setShowPurchaseOrderForm(false);
|
||||
setSelectedOrder(null);
|
||||
} :
|
||||
handleCreatePurchaseOrder
|
||||
}
|
||||
onClose={() => {
|
||||
setShowPurchaseOrderForm(false);
|
||||
setSelectedOrder(null);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PurchaseOrderManagementPage;
|
||||
Reference in New Issue
Block a user