'use client'; import React, { useState, useEffect, useRef } from 'react'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { InputText } from 'primereact/inputtext'; import { Card } from 'primereact/card'; import { Dialog } from 'primereact/dialog'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Tag } from 'primereact/tag'; import { InputNumber } from 'primereact/inputnumber'; import { Dropdown } from 'primereact/dropdown'; import { Calendar } from 'primereact/calendar'; import { InputTextarea } from 'primereact/inputtextarea'; import { AutoComplete } from 'primereact/autocomplete'; import { confirmDialog } from 'primereact/confirmdialog'; import { ConfirmDialog } from 'primereact/confirmdialog'; import { Chart } from 'primereact/chart'; import { ActionButtonGroup, ViewButton, EditButton, DeleteButton, ActionButton } from '../../../../components/ui/ActionButton'; interface StockItem { id: string; reference: string; nom: string; stockDisponible: number; unite: string; emplacement: string; } interface MaterialExit { id: string; numero: string; dateCreation: Date; dateSortie: Date; chantier: string; responsable: string; statut: 'BROUILLON' | 'VALIDEE' | 'SORTIE' | 'RETOURNEE'; motif: string; articles: ExitItem[]; commentaires: string; signature?: string; dateRetourPrevue?: Date; dateRetourEffective?: Date; } interface ExitItem { id: string; articleId: string; reference: string; nom: string; quantiteSortie: number; quantiteRetournee: number; unite: string; etat: 'BON' | 'ABIME' | 'PERDU'; commentaire: string; } const SortiesPage = () => { const [exits, setExits] = useState([]); const [stockItems, setStockItems] = useState([]); const [selectedExits, setSelectedExits] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [exitDialog, setExitDialog] = useState(false); const [itemDialog, setItemDialog] = useState(false); const [returnDialog, setReturnDialog] = useState(false); const [deleteExitDialog, setDeleteExitDialog] = useState(false); const [exit, setExit] = useState({ id: '', numero: '', dateCreation: new Date(), dateSortie: new Date(), chantier: '', responsable: '', statut: 'BROUILLON', motif: '', articles: [], commentaires: '' }); const [currentItem, setCurrentItem] = useState({ id: '', articleId: '', reference: '', nom: '', quantiteSortie: 0, quantiteRetournee: 0, unite: '', etat: 'BON', commentaire: '' }); const [filteredStockItems, setFilteredStockItems] = useState([]); const [submitted, setSubmitted] = useState(false); const toast = useRef(null); const dt = useRef>(null); const chantiers = [ { label: 'Chantier Dupont - Paris 15ème', value: 'chantier-dupont' }, { label: 'Rénovation Mairie - Lyon', value: 'chantier-mairie-lyon' }, { label: 'Construction Villa - Marseille', value: 'chantier-villa-marseille' }, { label: 'Bureau Central - Maintenance', value: 'bureau-maintenance' } ]; const responsables = [ { label: 'Jean Martin', value: 'jean.martin' }, { label: 'Marie Dubois', value: 'marie.dubois' }, { label: 'Pierre Durand', value: 'pierre.durand' }, { label: 'Sophie Bernard', value: 'sophie.bernard' } ]; const motifs = [ { label: 'Utilisation chantier', value: 'utilisation-chantier' }, { label: 'Prêt temporaire', value: 'pret-temporaire' }, { label: 'Maintenance', value: 'maintenance' }, { label: 'Formation', value: 'formation' }, { label: 'Démonstration', value: 'demonstration' } ]; const statuts = [ { label: 'Brouillon', value: 'BROUILLON' }, { label: 'Validée', value: 'VALIDEE' }, { label: 'Sortie', value: 'SORTIE' }, { label: 'Retournée', value: 'RETOURNEE' } ]; const etats = [ { label: 'Bon état', value: 'BON' }, { label: 'Abîmé', value: 'ABIME' }, { label: 'Perdu', value: 'PERDU' } ]; useEffect(() => { loadData(); }, []); const loadData = async () => { try { setLoading(true); // Données mockées stock const mockStockItems: StockItem[] = [ { id: '1', reference: 'CIM-001', nom: 'Ciment Portland', stockDisponible: 150, unite: 'sac', emplacement: 'entrepot-a' }, { id: '2', reference: 'OUT-002', nom: 'Perceuse électrique', stockDisponible: 5, unite: 'unité', emplacement: 'magasin' }, { id: '3', reference: 'SEC-003', nom: 'Casque de sécurité', stockDisponible: 8, unite: 'unité', emplacement: 'bureau' }, { id: '4', reference: 'OUT-004', nom: 'Visseuse sans fil', stockDisponible: 3, unite: 'unité', emplacement: 'magasin' }, { id: '5', reference: 'MAT-005', nom: 'Échafaudage mobile', stockDisponible: 2, unite: 'unité', emplacement: 'entrepot-b' } ]; // Données mockées sorties const mockExits: MaterialExit[] = [ { id: '1', numero: 'SOR-2024-001', dateCreation: new Date('2024-01-15'), dateSortie: new Date('2024-01-16'), chantier: 'chantier-dupont', responsable: 'jean.martin', statut: 'SORTIE', motif: 'utilisation-chantier', articles: [ { id: '1', articleId: '2', reference: 'OUT-002', nom: 'Perceuse électrique', quantiteSortie: 2, quantiteRetournee: 0, unite: 'unité', etat: 'BON', commentaire: '' } ], commentaires: 'Matériel pour travaux de perçage', dateRetourPrevue: new Date('2024-01-30') }, { id: '2', numero: 'SOR-2024-002', dateCreation: new Date('2024-01-20'), dateSortie: new Date('2024-01-20'), chantier: 'chantier-mairie-lyon', responsable: 'marie.dubois', statut: 'RETOURNEE', motif: 'utilisation-chantier', articles: [ { id: '2', articleId: '3', reference: 'SEC-003', nom: 'Casque de sécurité', quantiteSortie: 5, quantiteRetournee: 4, unite: 'unité', etat: 'BON', commentaire: '1 casque perdu' } ], commentaires: 'EPI pour équipe de 5 personnes', dateRetourPrevue: new Date('2024-01-25'), dateRetourEffective: new Date('2024-01-24') }, { id: '3', numero: 'SOR-2024-003', dateCreation: new Date(), dateSortie: new Date(), chantier: 'chantier-villa-marseille', responsable: 'pierre.durand', statut: 'BROUILLON', motif: 'utilisation-chantier', articles: [ { id: '3', articleId: '5', reference: 'MAT-005', nom: 'Échafaudage mobile', quantiteSortie: 1, quantiteRetournee: 0, unite: 'unité', etat: 'BON', commentaire: '' } ], commentaires: 'Échafaudage pour travaux en hauteur', dateRetourPrevue: new Date('2024-02-15') } ]; setStockItems(mockStockItems); setExits(mockExits); } catch (error) { console.error('Erreur lors du chargement:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les données', life: 3000 }); } finally { setLoading(false); } }; const openNew = () => { setExit({ id: '', numero: '', dateCreation: new Date(), dateSortie: new Date(), chantier: '', responsable: '', statut: 'BROUILLON', motif: '', articles: [], commentaires: '' }); setSubmitted(false); setExitDialog(true); }; const hideDialog = () => { setSubmitted(false); setExitDialog(false); }; const hideItemDialog = () => { setSubmitted(false); setItemDialog(false); }; const hideReturnDialog = () => { setReturnDialog(false); }; const hideDeleteExitDialog = () => { setDeleteExitDialog(false); }; const saveExit = () => { setSubmitted(true); if (exit.chantier && exit.responsable && exit.motif && exit.articles.length > 0) { let updatedExits = [...exits]; if (exit.id) { // Mise à jour const index = exits.findIndex(e => e.id === exit.id); updatedExits[index] = exit; toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Sortie mise à jour', life: 3000 }); } else { // Création const newExit = { ...exit, id: Date.now().toString(), numero: `SOR-${new Date().getFullYear()}-${String(exits.length + 1).padStart(3, '0')}` }; updatedExits.push(newExit); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Sortie créée', life: 3000 }); } setExits(updatedExits); setExitDialog(false); } }; const editExit = (exit: MaterialExit) => { setExit({ ...exit }); setExitDialog(true); }; const confirmDeleteExit = (exit: MaterialExit) => { setExit(exit); setDeleteExitDialog(true); }; const deleteExit = () => { const updatedExits = exits.filter(e => e.id !== exit.id); setExits(updatedExits); setDeleteExitDialog(false); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Sortie supprimée', life: 3000 }); }; const validateExit = (exit: MaterialExit) => { const updatedExits = exits.map(e => e.id === exit.id ? { ...e, statut: 'VALIDEE' as const } : e ); setExits(updatedExits); toast.current?.show({ severity: 'info', summary: 'Sortie validée', detail: `Sortie ${exit.numero} validée`, life: 3000 }); }; const processExit = (exit: MaterialExit) => { const updatedExits = exits.map(e => e.id === exit.id ? { ...e, statut: 'SORTIE' as const, dateSortie: new Date() } : e ); setExits(updatedExits); toast.current?.show({ severity: 'success', summary: 'Sortie effectuée', detail: `Matériel sorti pour ${exit.numero}`, life: 3000 }); }; const openReturn = (exit: MaterialExit) => { setExit({ ...exit }); setReturnDialog(true); }; const processReturn = () => { const updatedExits = exits.map(e => e.id === exit.id ? { ...e, statut: 'RETOURNEE' as const, dateRetourEffective: new Date() } : e ); setExits(updatedExits); setReturnDialog(false); toast.current?.show({ severity: 'success', summary: 'Retour traité', detail: `Matériel retourné pour ${exit.numero}`, life: 3000 }); }; const addItem = () => { setCurrentItem({ id: '', articleId: '', reference: '', nom: '', quantiteSortie: 0, quantiteRetournee: 0, unite: '', etat: 'BON', commentaire: '' }); setSubmitted(false); setItemDialog(true); }; const saveItem = () => { setSubmitted(true); if (currentItem.articleId && currentItem.quantiteSortie > 0) { const item = { ...currentItem, id: currentItem.id || Date.now().toString() }; let updatedItems = [...exit.articles]; if (currentItem.id) { // Mise à jour const index = exit.articles.findIndex(i => i.id === currentItem.id); updatedItems[index] = item; } else { // Ajout updatedItems.push(item); } setExit({ ...exit, articles: updatedItems }); setItemDialog(false); } }; const editItem = (item: ExitItem) => { setCurrentItem({ ...item }); setItemDialog(true); }; const deleteItem = (itemId: string) => { const updatedItems = exit.articles.filter(i => i.id !== itemId); setExit({ ...exit, articles: updatedItems }); }; const searchStockItems = (event: any) => { const query = event.query.toLowerCase(); const filtered = stockItems.filter(item => item.nom.toLowerCase().includes(query) || item.reference.toLowerCase().includes(query) ); setFilteredStockItems(filtered); }; const onStockItemSelect = (item: StockItem) => { setCurrentItem({ ...currentItem, articleId: item.id, reference: item.reference, nom: item.nom, unite: item.unite }); }; const exportCSV = () => { dt.current?.exportCSV(); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (