correzione ArticleCard, creazione MacchineTree
All checks were successful
Deploy to VPS / build (push) Successful in 37s
Deploy to VPS / deploy (push) Successful in 26s

This commit is contained in:
AV77web 2026-05-28 22:21:52 +02:00
parent 33ecedfe33
commit be228bca5c
5 changed files with 326 additions and 177 deletions

View file

@ -1,21 +1,56 @@
export default function ArticoliPage() { "use client";
return (
<div className="flex flex-1 flex-col bg-zinc-50 p-6 dark:bg-black">
<div className="mx-auto w-full max-w-6xl">
<header className="mb-8">
<h1 className="text-3xl font-semibold text-zinc-950 dark:text-zinc-50">
Articoli
</h1>
<p className="mt-2 text-zinc-600 dark:text-zinc-400">
Catalogo ricambi e componenti
</p>
</header>
<div className="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-800 dark:bg-zinc-900"> import { useState } from "react";
<p className="text-zinc-600 dark:text-zinc-400"> import type { Stabilimento } from "@/src/types/stabilimento";
Contenuto della pagina articoli in arrivo... import StabilimentoSelector from "@/src/components/StabilimentoSelector";
</p> import ArticlesGrid from "@/src/components/ArticlesGrid";
export default function ArticoliPage() {
const [selectedStabilimento, setSelectedStabilimento] = useState<Stabilimento | null>(null);
return (
<div className="min-h-screen bg-black">
<div className="max-w-7xl mx-auto px-4 py-6">
{/* Header */}
<div className="mb-6">
<h1 className="text-2xl font-bold text-white">Articoli</h1>
<p className="text-sm text-zinc-500">Catalogo ricambi e componenti</p>
</div> </div>
{/* Selezione stabilimento */}
<div className="mb-6 p-4 rounded-lg bg-zinc-900 border border-zinc-800">
<div className="flex items-center justify-between mb-3">
<p className="text-sm text-zinc-400">Stabilimento:</p>
{selectedStabilimento && (
<button
onClick={() => setSelectedStabilimento(null)}
className="text-xs text-zinc-500 hover:text-white transition-colors"
>
Cambia
</button>
)}
</div>
{selectedStabilimento ? (
<p className="font-medium text-white">{selectedStabilimento.descrizione}</p>
) : (
<StabilimentoSelector
selectedId={null}
onSelect={setSelectedStabilimento}
/>
)}
</div>
{/* Contenuto */}
{selectedStabilimento ? (
<ArticlesGrid stabilimento={selectedStabilimento} />
) : (
<div className="flex flex-col items-center justify-center py-20 text-center">
<svg className="w-16 h-16 text-zinc-800 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
<p className="text-zinc-500">Seleziona uno stabilimento per visualizzare gli articoli</p>
</div>
)}
</div> </div>
</div> </div>
); );

View file

@ -3,72 +3,70 @@
import { useState } from "react"; import { useState } from "react";
import type { Stabilimento } from "@/src/types/stabilimento"; import type { Stabilimento } from "@/src/types/stabilimento";
import StabilimentoSelector from "@/src/components/StabilimentoSelector"; import StabilimentoSelector from "@/src/components/StabilimentoSelector";
import ArticlesGrid from "@/src/components/ArticlesGrid"; import ArticlesList from "@/src/components/ArticlesList";
import MacchineTree from "@/src/components/MacchineTree";
export default function Home() { export default function Home() {
const [selectedStabilimento, setSelectedStabilimento] = useState<Stabilimento | null>(null); const [selectedStabilimento, setSelectedStabilimento] = useState<Stabilimento | null>(null);
return ( return (
<div className="min-h-screen bg-black"> <div className="flex flex-col h-[calc(100vh-64px)] bg-black">
<div className="max-w-7xl mx-auto px-4 py-8"> <div className="flex-1 flex flex-col max-w-7xl mx-auto w-full px-4 py-6 overflow-hidden">
{/* Header */} {/* Header + Selezione stabilimento */}
<div className="mb-8"> <div className="mb-6 flex-shrink-0">
<h1 className="text-3xl font-bold text-white mb-2"> <div className="flex items-center justify-between mb-4">
MagRicambi <div>
</h1> <h1 className="text-2xl font-bold text-white">MagRicambi</h1>
<p className="text-zinc-400"> <p className="text-sm text-zinc-500">Gestione magazzino ricambi</p>
Gestione magazzino ricambi </div>
</p> {selectedStabilimento && (
</div> <div className="flex items-center gap-2 text-sm">
<span className="text-zinc-500">Stabilimento:</span>
{/* Selezione stabilimento */} <span className="font-medium text-white">{selectedStabilimento.descrizione}</span>
<div className="mb-8"> <button
<h2 className="text-lg font-medium text-zinc-300 mb-4"> onClick={() => setSelectedStabilimento(null)}
Seleziona stabilimento className="text-zinc-500 hover:text-white transition-colors"
</h2> >
<StabilimentoSelector <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
selectedId={selectedStabilimento?.id ?? null} <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
onSelect={setSelectedStabilimento} </svg>
/> </button>
</div> </div>
)}
{/* Contenuto principale */} </div>
{selectedStabilimento ? (
<div> {!selectedStabilimento && (
<div className="flex items-center gap-3 mb-6"> <div className="p-4 rounded-lg bg-zinc-900 border border-zinc-800">
<h2 className="text-xl font-semibold text-white"> <p className="text-sm text-zinc-400 mb-3">Seleziona uno stabilimento per iniziare:</p>
Articoli - {selectedStabilimento.descrizione} <StabilimentoSelector
</h2> selectedId={null}
<button onSelect={setSelectedStabilimento}
onClick={() => setSelectedStabilimento(null)} />
className="text-sm text-zinc-500 hover:text-white transition-colors" </div>
> )}
(cambia) </div>
</button>
{/* Contenuto principale: split 50/50 */}
{selectedStabilimento ? (
<div className="flex-1 grid grid-cols-2 gap-6 min-h-0">
{/* Colonna sinistra: Articoli */}
<div className="flex flex-col min-h-0 p-4 rounded-xl bg-zinc-900/50 border border-zinc-800">
<ArticlesList stabilimento={selectedStabilimento} />
</div>
{/* Colonna destra: Macchine */}
<div className="flex flex-col min-h-0 p-4 rounded-xl bg-zinc-900/50 border border-zinc-800">
<MacchineTree stabilimento={selectedStabilimento} />
</div> </div>
<ArticlesGrid stabilimento={selectedStabilimento} />
</div> </div>
) : ( ) : (
<div className="flex flex-col items-center justify-center py-20 text-center"> <div className="flex-1 flex items-center justify-center">
<svg <div className="text-center">
className="w-20 h-20 text-zinc-800 mb-6" <svg className="w-16 h-16 mx-auto text-zinc-800 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
fill="none" <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
stroke="currentColor" </svg>
viewBox="0 0 24 24" <p className="text-zinc-500">Seleziona uno stabilimento per visualizzare articoli e macchine</p>
> </div>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
/>
</svg>
<h3 className="text-xl font-medium text-zinc-400 mb-2">
Nessuno stabilimento selezionato
</h3>
<p className="text-zinc-600 max-w-md">
Seleziona uno stabilimento dalla lista sopra per visualizzare e gestire gli articoli del magazzino.
</p>
</div> </div>
)} )}
</div> </div>

View file

@ -10,30 +10,21 @@ interface ArticleCardProps {
} }
export default function ArticleCard({ article, onEdit, onDelete }: ArticleCardProps) { export default function ArticleCard({ article, onEdit, onDelete }: ArticleCardProps) {
const [showActions, setShowActions] = useState(false);
const [deleting, setDeleting] = useState(false); const [deleting, setDeleting] = useState(false);
const isSottoScorta = article.quantita < article.quantita_minima; const isSottoScorta = article.quantita < article.quantita_minima;
const disponibile = article.quantita - article.assegnata_macchine; const disponibile = article.quantita - article.assegnata_macchine;
const handleDelete = async () => { const handleDelete = async () => {
if (!confirm(`Sei sicuro di voler eliminare l'articolo "${article.descrizione}"?`)) { if (!confirm(`Eliminare "${article.descrizione}"?`)) return;
return;
}
setDeleting(true); setDeleting(true);
try { try {
const res = await fetch(`/api/articoli/${article.id}`, { const res = await fetch(`/api/articoli/${article.id}`, { method: "DELETE" });
method: "DELETE", if (!res.ok) throw new Error("Errore durante l'eliminazione");
});
if (!res.ok) {
throw new Error("Errore durante l'eliminazione");
}
onDelete(article); onDelete(article);
} catch (error) { } catch (error) {
alert(error instanceof Error ? error.message : "Errore durante l'eliminazione"); alert(error instanceof Error ? error.message : "Errore");
} finally { } finally {
setDeleting(false); setDeleting(false);
} }
@ -42,98 +33,44 @@ export default function ArticleCard({ article, onEdit, onDelete }: ArticleCardPr
return ( return (
<div <div
className={` className={`
relative bg-zinc-900 rounded-xl border transition-all duration-200 flex items-center gap-3 p-3 rounded-lg border bg-zinc-900 transition-colors hover:bg-zinc-800
hover:shadow-lg hover:shadow-black/20 hover:-translate-y-1
${isSottoScorta ? "border-red-500/50" : "border-zinc-800"} ${isSottoScorta ? "border-red-500/50" : "border-zinc-800"}
`} `}
onMouseEnter={() => setShowActions(true)}
onMouseLeave={() => setShowActions(false)}
> >
{/* Header */} {/* Indicatore sotto scorta */}
<div className="p-4 border-b border-zinc-800"> {isSottoScorta && (
<div className="flex items-start justify-between gap-2"> <div className="w-2 h-2 rounded-full bg-red-500 flex-shrink-0" title="Sotto scorta" />
<div className="flex-1 min-w-0"> )}
<h3 className="font-semibold text-white truncate" title={article.descrizione}>
{article.descrizione}
</h3>
<p className="text-sm text-zinc-500 font-mono">{article.codice}</p>
</div>
{/* Badge famiglia */} {/* Info articolo */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="font-medium text-white truncate text-sm" title={article.descrizione}>
{article.descrizione}
</span>
{article.famiglia && ( {article.famiglia && (
<span className="px-2 py-1 text-xs font-medium rounded-full bg-zinc-800 text-zinc-400 whitespace-nowrap"> <span className="px-1.5 py-0.5 text-[10px] rounded bg-zinc-800 text-zinc-500 flex-shrink-0">
{article.famiglia} {article.famiglia}
</span> </span>
)} )}
</div> </div>
</div> <div className="flex items-center gap-3 text-xs text-zinc-500 mt-0.5">
<span className="font-mono">{article.codice}</span>
{/* Body */} <span>
<div className="p-4 space-y-3"> Qta: <span className={isSottoScorta ? "text-red-400" : "text-white"}>{article.quantita}</span>
{/* Quantità */} {isSottoScorta && <span className="text-red-400"> (min {article.quantita_minima})</span>}
<div className="grid grid-cols-2 gap-3"> </span>
<div> <span>
<p className="text-xs text-zinc-500 uppercase tracking-wider">Quantità</p> Disp: <span className={disponibile <= 0 ? "text-yellow-400" : "text-green-400"}>{disponibile}</span>
<p className={`text-lg font-bold ${isSottoScorta ? "text-red-400" : "text-white"}`}> </span>
{article.quantita}
{isSottoScorta && (
<span className="ml-2 text-xs font-normal text-red-400">
(min: {article.quantita_minima})
</span>
)}
</p>
</div>
<div>
<p className="text-xs text-zinc-500 uppercase tracking-wider">Disponibile</p>
<p className={`text-lg font-bold ${disponibile <= 0 ? "text-yellow-400" : "text-green-400"}`}>
{disponibile}
</p>
</div>
</div> </div>
{/* Assegnate a macchine */}
{article.assegnata_macchine > 0 && (
<div className="flex items-center gap-2 text-sm">
<svg className="w-4 h-4 text-zinc-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
<span className="text-zinc-400">
{article.assegnata_macchine} assegnate a macchine
</span>
</div>
)}
{/* Prezzo */}
{article.prezzo > 0 && (
<div className="flex items-center justify-between pt-2 border-t border-zinc-800">
<span className="text-sm text-zinc-500">Prezzo</span>
<span className="font-semibold text-white">
{article.prezzo.toFixed(2)}
</span>
</div>
)}
{/* Barcode */}
{article.barcode && (
<div className="flex items-center gap-2 text-xs text-zinc-500">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z" />
</svg>
<span className="font-mono">{article.barcode}</span>
</div>
)}
</div> </div>
{/* Action buttons (hover) */} {/* Azioni */}
<div <div className="flex items-center gap-1 flex-shrink-0">
className={`
absolute top-2 right-2 flex gap-1 transition-opacity duration-200
${showActions ? "opacity-100" : "opacity-0"}
`}
>
<button <button
onClick={() => onEdit(article)} onClick={() => onEdit(article)}
className="p-2 rounded-lg bg-zinc-800 text-zinc-400 hover:bg-blue-600 hover:text-white transition-colors" className="p-1.5 rounded text-zinc-500 hover:text-blue-400 hover:bg-zinc-700 transition-colors"
title="Modifica" title="Modifica"
> >
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -143,13 +80,13 @@ export default function ArticleCard({ article, onEdit, onDelete }: ArticleCardPr
<button <button
onClick={handleDelete} onClick={handleDelete}
disabled={deleting} disabled={deleting}
className="p-2 rounded-lg bg-zinc-800 text-zinc-400 hover:bg-red-600 hover:text-white transition-colors disabled:opacity-50" className="p-1.5 rounded text-zinc-500 hover:text-red-400 hover:bg-zinc-700 transition-colors disabled:opacity-50"
title="Elimina" title="Elimina"
> >
{deleting ? ( {deleting ? (
<svg className="w-4 h-4 animate-spin" viewBox="0 0 24 24"> <svg className="w-4 h-4 animate-spin" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" /> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg> </svg>
) : ( ) : (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@ -158,15 +95,6 @@ export default function ArticleCard({ article, onEdit, onDelete }: ArticleCardPr
)} )}
</button> </button>
</div> </div>
{/* Sotto scorta indicator */}
{isSottoScorta && (
<div className="absolute top-0 left-4 -translate-y-1/2">
<span className="px-2 py-0.5 text-xs font-bold rounded-full bg-red-500 text-white shadow-lg">
SOTTO SCORTA
</span>
</div>
)}
</div> </div>
); );
} }

View file

@ -0,0 +1,148 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import type { Article, ArticleFamily } from "@/src/types/article";
import type { Stabilimento } from "@/src/types/stabilimento";
import ArticleCard from "./ArticleCard";
import ArticleModal from "./ArticleModal";
interface ArticlesListProps {
stabilimento: Stabilimento;
}
export default function ArticlesList({ stabilimento }: ArticlesListProps) {
const [articles, setArticles] = useState<Article[]>([]);
const [families, setFamilies] = useState<ArticleFamily[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [search, setSearch] = useState("");
const [showModal, setShowModal] = useState(false);
const [editingArticle, setEditingArticle] = useState<Article | null>(null);
const fetchArticles = useCallback(async () => {
setLoading(true);
setError(null);
try {
const params = new URLSearchParams();
params.set("stabilimentoId", stabilimento.id.toString());
if (search) params.set("search", search);
const res = await fetch(`/api/articoli?${params}`);
if (!res.ok) throw new Error("Errore nel caricamento");
const data = await res.json();
setArticles(data.articles);
setFamilies(data.families);
} catch (err) {
setError(err instanceof Error ? err.message : "Errore sconosciuto");
} finally {
setLoading(false);
}
}, [stabilimento.id, search]);
useEffect(() => {
fetchArticles();
}, [fetchArticles]);
const handleEdit = (article: Article) => {
setEditingArticle(article);
setShowModal(true);
};
const handleDelete = (deleted: Article) => {
setArticles((prev) => prev.filter((a) => a.id !== deleted.id));
};
const handleSave = (saved: Article) => {
if (editingArticle) {
setArticles((prev) => prev.map((a) => (a.id === saved.id ? saved : a)));
} else {
setArticles((prev) => [saved, ...prev]);
}
setShowModal(false);
setEditingArticle(null);
};
const sottoScorta = articles.filter((a) => a.quantita < a.quantita_minima).length;
return (
<div className="flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between gap-4 mb-4">
<div>
<h2 className="text-lg font-semibold text-white">Articoli</h2>
<p className="text-xs text-zinc-500">
{articles.length} articoli {sottoScorta > 0 && <span className="text-red-400">({sottoScorta} sotto scorta)</span>}
</p>
</div>
<button
onClick={() => { setEditingArticle(null); setShowModal(true); }}
className="p-2 rounded-lg bg-blue-600 text-white hover:bg-blue-500 transition-colors"
title="Nuovo articolo"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
</button>
</div>
{/* Ricerca */}
<div className="relative mb-4">
<svg className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-zinc-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Cerca articoli..."
className="w-full pl-9 pr-3 py-2 text-sm rounded-lg bg-zinc-900 border border-zinc-800 text-white placeholder-zinc-500 focus:outline-none focus:border-blue-500"
/>
</div>
{/* Lista articoli */}
<div className="flex-1 overflow-y-auto space-y-2 pr-1">
{loading ? (
<div className="flex items-center justify-center py-8 text-zinc-500 text-sm">
<svg className="w-5 h-5 animate-spin mr-2" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
Caricamento...
</div>
) : error ? (
<div className="text-center py-8">
<p className="text-red-400 text-sm mb-2">{error}</p>
<button onClick={fetchArticles} className="text-xs text-blue-400 hover:underline">Riprova</button>
</div>
) : articles.length === 0 ? (
<div className="text-center py-8 text-zinc-500 text-sm">
{search ? "Nessun articolo trovato" : "Nessun articolo in questo stabilimento"}
</div>
) : (
articles.map((article) => (
<ArticleCard
key={article.id}
article={article}
onEdit={handleEdit}
onDelete={handleDelete}
/>
))
)}
</div>
{/* Modal */}
{showModal && (
<ArticleModal
article={editingArticle}
families={families}
stabilimentoId={stabilimento.id}
onClose={() => { setShowModal(false); setEditingArticle(null); }}
onSave={handleSave}
/>
)}
</div>
);
}

View file

@ -0,0 +1,40 @@
"use client";
import type { Stabilimento } from "@/src/types/stabilimento";
interface MacchineTreeProps {
stabilimento: Stabilimento;
}
export default function MacchineTree({ stabilimento }: MacchineTreeProps) {
return (
<div className="flex flex-col h-full">
{/* Header */}
<div className="flex items-center justify-between gap-4 mb-4">
<div>
<h2 className="text-lg font-semibold text-white">Macchine</h2>
<p className="text-xs text-zinc-500">Albero macchine e parti</p>
</div>
<button
className="p-2 rounded-lg bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white transition-colors"
title="Nuova macchina"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
</button>
</div>
{/* Placeholder contenuto */}
<div className="flex-1 flex flex-col items-center justify-center text-center p-8 border-2 border-dashed border-zinc-800 rounded-lg">
<svg className="w-12 h-12 text-zinc-700 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
<p className="text-zinc-500 text-sm mb-2">Albero macchine</p>
<p className="text-zinc-600 text-xs">
Trascina gli articoli qui per assegnarli alle macchine
</p>
</div>
</div>
);
}