selettore stabilimento unico per macchine e articoli
This commit is contained in:
parent
50c18f0913
commit
c66ee44f36
6 changed files with 252 additions and 146 deletions
|
|
@ -3,6 +3,7 @@ import { redirect } from "next/navigation";
|
||||||
import { auth } from "@/src/auth";
|
import { auth } from "@/src/auth";
|
||||||
import SignOutButton from "@/src/components/auth/SignOutButton";
|
import SignOutButton from "@/src/components/auth/SignOutButton";
|
||||||
import Navbar from "@/src/components/Navbar";
|
import Navbar from "@/src/components/Navbar";
|
||||||
|
import { StabilimentoProvider } from "@/src/contexts/StabilimentoContext";
|
||||||
|
|
||||||
export default async function MainLayout({
|
export default async function MainLayout({
|
||||||
children,
|
children,
|
||||||
|
|
@ -17,9 +18,11 @@ export default async function MainLayout({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<StabilimentoProvider>
|
||||||
<Navbar actions={<SignOutButton />} />
|
<div>
|
||||||
<main>{children}</main>
|
<Navbar actions={<SignOutButton />} />
|
||||||
</div>
|
<main>{children}</main>
|
||||||
|
</div>
|
||||||
|
</StabilimentoProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import type { Article, ArticleFamily } from "@/src/types/article";
|
import type { Article, ArticleFamily } from "@/src/types/article";
|
||||||
import type { Stabilimento, Magazzino } from "@/src/types/stabilimento";
|
|
||||||
import type { GiacenzePerArticolo } from "@/src/types/giacenza";
|
import type { GiacenzePerArticolo } from "@/src/types/giacenza";
|
||||||
import type { TipoMovimento } from "@/src/types/movimento";
|
import type { TipoMovimento } from "@/src/types/movimento";
|
||||||
import ArticleCard from "./ArticleCard";
|
import ArticleCard from "./ArticleCard";
|
||||||
import ArticleModal from "./ArticleModal";
|
import ArticleModal from "./ArticleModal";
|
||||||
import MovimentoModal from "./MovimentoModal";
|
import MovimentoModal from "./MovimentoModal";
|
||||||
import StabilimentoMagazzinoSelector from "./StabilimentoMagazzinoSelector";
|
import { useStabilimento } from "@/src/contexts/StabilimentoContext";
|
||||||
|
|
||||||
export default function ArticlesList() {
|
export default function ArticlesList() {
|
||||||
const [articles, setArticles] = useState<Article[]>([]);
|
const [articles, setArticles] = useState<Article[]>([]);
|
||||||
|
|
@ -25,8 +24,7 @@ export default function ArticlesList() {
|
||||||
const [movimentoArticle, setMovimentoArticle] = useState<Article | null>(null);
|
const [movimentoArticle, setMovimentoArticle] = useState<Article | null>(null);
|
||||||
const [movimentoTipo, setMovimentoTipo] = useState<TipoMovimento>("carico");
|
const [movimentoTipo, setMovimentoTipo] = useState<TipoMovimento>("carico");
|
||||||
|
|
||||||
const [selectedStabilimento, setSelectedStabilimento] = useState<Stabilimento | null>(null);
|
const { selectedStabilimento, selectedMagazzino } = useStabilimento();
|
||||||
const [selectedMagazzino, setSelectedMagazzino] = useState<Magazzino | null>(null);
|
|
||||||
|
|
||||||
const fetchArticles = useCallback(async () => {
|
const fetchArticles = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -79,14 +77,6 @@ export default function ArticlesList() {
|
||||||
fetchGiacenze();
|
fetchGiacenze();
|
||||||
}, [fetchGiacenze]);
|
}, [fetchGiacenze]);
|
||||||
|
|
||||||
const handleSelectionChange = ({ stabilimento, magazzino }: {
|
|
||||||
stabilimento: Stabilimento | null;
|
|
||||||
magazzino: Magazzino | null
|
|
||||||
}) => {
|
|
||||||
setSelectedStabilimento(stabilimento);
|
|
||||||
setSelectedMagazzino(magazzino);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEdit = (article: Article) => {
|
const handleEdit = (article: Article) => {
|
||||||
setEditingArticle(article);
|
setEditingArticle(article);
|
||||||
setShowModal(true);
|
setShowModal(true);
|
||||||
|
|
@ -156,10 +146,15 @@ export default function ArticlesList() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Selettore Stabilimento/Magazzino */}
|
{/* Info selezione corrente */}
|
||||||
<div className="mb-4 p-3 rounded-lg bg-zinc-800/50 border border-zinc-800">
|
{selectedStabilimento && (
|
||||||
<StabilimentoMagazzinoSelector onSelectionChange={handleSelectionChange} />
|
<div className="mb-3 px-3 py-2 rounded-lg bg-blue-900/20 border border-blue-700/30 text-xs text-blue-300">
|
||||||
</div>
|
Filtro: {selectedMagazzino
|
||||||
|
? `${selectedStabilimento.descrizione} → ${selectedMagazzino.descrizione}`
|
||||||
|
: `${selectedStabilimento.descrizione} (tutti i magazzini)`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Ricerca */}
|
{/* Ricerca */}
|
||||||
<div className="relative mb-4">
|
<div className="relative mb-4">
|
||||||
|
|
|
||||||
105
src/components/GlobalStabilimentoSelector.tsx
Normal file
105
src/components/GlobalStabilimentoSelector.tsx
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useStabilimento } from "@/src/contexts/StabilimentoContext";
|
||||||
|
|
||||||
|
export default function GlobalStabilimentoSelector() {
|
||||||
|
const {
|
||||||
|
stabilimenti,
|
||||||
|
selectedStabilimento,
|
||||||
|
selectedMagazzino,
|
||||||
|
filteredMagazzini,
|
||||||
|
loading,
|
||||||
|
setSelectedStabilimento,
|
||||||
|
setSelectedMagazzino,
|
||||||
|
resetSelection,
|
||||||
|
} = useStabilimento();
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 text-zinc-500 text-sm">
|
||||||
|
<svg className="animate-spin h-4 w-4" 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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{/* Stabilimenti */}
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<button
|
||||||
|
onClick={() => resetSelection()}
|
||||||
|
className={`
|
||||||
|
px-2.5 py-1 text-xs rounded-md font-medium transition-all
|
||||||
|
${!selectedStabilimento
|
||||||
|
? "bg-blue-600 text-white"
|
||||||
|
: "bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white"
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Tutti
|
||||||
|
</button>
|
||||||
|
{stabilimenti.map((stab) => (
|
||||||
|
<button
|
||||||
|
key={stab.id}
|
||||||
|
onClick={() => setSelectedStabilimento(
|
||||||
|
selectedStabilimento?.id === stab.id ? null : stab
|
||||||
|
)}
|
||||||
|
className={`
|
||||||
|
px-2.5 py-1 text-xs rounded-md font-medium transition-all
|
||||||
|
${selectedStabilimento?.id === stab.id
|
||||||
|
? "bg-blue-600 text-white"
|
||||||
|
: "bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white"
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{stab.descrizione}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Separatore */}
|
||||||
|
{selectedStabilimento && filteredMagazzini.length > 0 && (
|
||||||
|
<div className="w-px h-5 bg-zinc-700" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Magazzini */}
|
||||||
|
{selectedStabilimento && filteredMagazzini.length > 0 && (
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<span className="text-xs text-zinc-500 mr-1">Mag:</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedMagazzino(null)}
|
||||||
|
className={`
|
||||||
|
px-2.5 py-1 text-xs rounded-md font-medium transition-all
|
||||||
|
${!selectedMagazzino
|
||||||
|
? "bg-green-600 text-white"
|
||||||
|
: "bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white"
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Tutti
|
||||||
|
</button>
|
||||||
|
{filteredMagazzini.map((mag) => (
|
||||||
|
<button
|
||||||
|
key={mag.id}
|
||||||
|
onClick={() => setSelectedMagazzino(
|
||||||
|
selectedMagazzino?.id === mag.id ? null : mag
|
||||||
|
)}
|
||||||
|
className={`
|
||||||
|
px-2.5 py-1 text-xs rounded-md font-medium transition-all
|
||||||
|
${selectedMagazzino?.id === mag.id
|
||||||
|
? "bg-green-600 text-white"
|
||||||
|
: "bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white"
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{mag.descrizione}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,18 +2,17 @@
|
||||||
|
|
||||||
import { useState, useEffect, useCallback, useMemo } from "react";
|
import { useState, useEffect, useCallback, useMemo } from "react";
|
||||||
import type { MacchinaWithDetails, ArticoliPerMacchina } from "@/src/types/macchina";
|
import type { MacchinaWithDetails, ArticoliPerMacchina } from "@/src/types/macchina";
|
||||||
import type { Stabilimento } from "@/src/types/stabilimento";
|
|
||||||
import TreeNode from "./TreeNode";
|
import TreeNode from "./TreeNode";
|
||||||
import MacchinaModal from "./MacchinaModal";
|
import MacchinaModal from "./MacchinaModal";
|
||||||
|
import { useStabilimento } from "@/src/contexts/StabilimentoContext";
|
||||||
|
|
||||||
export default function MacchineTree() {
|
export default function MacchineTree() {
|
||||||
const [nodes, setNodes] = useState<MacchinaWithDetails[]>([]);
|
const [nodes, setNodes] = useState<MacchinaWithDetails[]>([]);
|
||||||
const [stabilimenti, setStabilimenti] = useState<Stabilimento[]>([]);
|
|
||||||
const [articlesByMacchina, setArticlesByMacchina] = useState<ArticoliPerMacchina>({});
|
const [articlesByMacchina, setArticlesByMacchina] = useState<ArticoliPerMacchina>({});
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const [selectedStabilimento, setSelectedStabilimento] = useState<Stabilimento | null>(null);
|
const { selectedStabilimento, stabilimenti } = useStabilimento();
|
||||||
|
|
||||||
const [copiedNodeId, setCopiedNodeId] = useState<number | null>(null);
|
const [copiedNodeId, setCopiedNodeId] = useState<number | null>(null);
|
||||||
const [isCloning, setIsCloning] = useState(false);
|
const [isCloning, setIsCloning] = useState(false);
|
||||||
|
|
@ -38,23 +37,12 @@ export default function MacchineTree() {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchStabilimenti = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
const res = await fetch("/api/stabilimenti");
|
|
||||||
if (!res.ok) throw new Error("Errore nel caricamento stabilimenti");
|
|
||||||
const data = await res.json();
|
|
||||||
setStabilimenti(data.stabilimenti || []);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Errore stabilimenti:", err);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const loadInitialData = useCallback(async () => {
|
const loadInitialData = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
await Promise.all([fetchNodes(), fetchStabilimenti()]);
|
await fetchNodes();
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [fetchNodes, fetchStabilimenti]);
|
}, [fetchNodes]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadInitialData();
|
loadInitialData();
|
||||||
|
|
@ -238,39 +226,12 @@ export default function MacchineTree() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filtro Stabilimento */}
|
{/* Info selezione corrente */}
|
||||||
<div className="mb-4 p-3 rounded-lg bg-zinc-800/50 border border-zinc-800">
|
{selectedStabilimento && (
|
||||||
<label className="block text-xs font-medium text-zinc-400 mb-2">
|
<div className="mb-3 px-3 py-2 rounded-lg bg-blue-900/20 border border-blue-700/30 text-xs text-blue-300">
|
||||||
Filtra per stabilimento
|
Filtro attivo: {selectedStabilimento.descrizione}
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
<button
|
|
||||||
onClick={() => setSelectedStabilimento(null)}
|
|
||||||
className={`px-3 py-1.5 text-xs font-medium rounded-lg transition-all
|
|
||||||
${!selectedStabilimento
|
|
||||||
? "bg-blue-600 text-white"
|
|
||||||
: "bg-zinc-700 text-zinc-300 hover:bg-zinc-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
Tutti
|
|
||||||
</button>
|
|
||||||
{stabilimenti.map((stab) => (
|
|
||||||
<button
|
|
||||||
key={stab.id}
|
|
||||||
onClick={() => setSelectedStabilimento(
|
|
||||||
selectedStabilimento?.id === stab.id ? null : stab
|
|
||||||
)}
|
|
||||||
className={`px-3 py-1.5 text-xs font-medium rounded-lg transition-all
|
|
||||||
${selectedStabilimento?.id === stab.id
|
|
||||||
? "bg-blue-600 text-white"
|
|
||||||
: "bg-zinc-700 text-zinc-300 hover:bg-zinc-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{stab.descrizione}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
{/* Indicatore clonazione */}
|
{/* Indicatore clonazione */}
|
||||||
{isCloning && (
|
{isCloning && (
|
||||||
|
|
|
||||||
|
|
@ -7,46 +7,26 @@
|
||||||
"use client"
|
"use client"
|
||||||
import { useState , MouseEvent, ReactNode} from "react";
|
import { useState , MouseEvent, ReactNode} from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import GlobalStabilimentoSelector from "./GlobalStabilimentoSelector";
|
||||||
|
|
||||||
interface NavLink {
|
interface NavLink {
|
||||||
href: string;
|
href: string;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServiceLink {
|
|
||||||
href: string;
|
|
||||||
label: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const navLinks: NavLink[] = [
|
const navLinks: NavLink[] = [
|
||||||
{ href: "/", label: "Home"},
|
{ href: "/", label: "Home"},
|
||||||
{ href: "/movimenti", label: "Movimenti"},
|
{ href: "/movimenti", label: "Movimenti"},
|
||||||
{ href: "/articoli", label: "Articoli"},
|
{ href: "/articoli", label: "Articoli"},
|
||||||
{ href: "/macchine", label: "Macchine"},
|
{ href: "/macchine", label: "Macchine"},
|
||||||
{ href: "/utenti", label: "Utenti"},
|
{ href: "/utenti", label: "Utenti"},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const serviceLinks: ServiceLink[] = [
|
|
||||||
{ href: "/services/web", label: "Web Development"},
|
|
||||||
{ href: "/services/mobile", label: "Mobile Development"},
|
|
||||||
{ href: "/services/consulting", label: "Consulting"},
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function Navbar({ actions }: { actions?: ReactNode }) {
|
export default function Navbar({ actions }: { actions?: ReactNode }) {
|
||||||
|
return (
|
||||||
const [ isServicesOpen, setIsServicesOpen] = useState<boolean>(false);
|
<nav className="border-b border-zinc-800 bg-black">
|
||||||
|
<div className="max-w-7xl mx-auto px-4">
|
||||||
const toggleServices = ( e: MouseEvent<HTMLButtonElement>) => {
|
<div className="flex items-center justify-between h-14">
|
||||||
e.preventDefault();
|
|
||||||
setIsServicesOpen(!isServicesOpen);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<nav className="border-b border-zinc-800 bg-black">
|
|
||||||
<div className="max-w-4xl mx-auto px-4">
|
|
||||||
<div className="flex justify-between h-16">
|
|
||||||
|
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
|
|
@ -55,69 +35,25 @@ export default function Navbar({ actions }: { actions?: ReactNode }) {
|
||||||
LOGO
|
LOGO
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation Links */}
|
||||||
<div className="flex items-center space-x-8">
|
<div className="flex items-center space-x-6">
|
||||||
|
|
||||||
{/* Link normali */}
|
|
||||||
{navLinks.map((link) => (
|
{navLinks.map((link) => (
|
||||||
<Link
|
<Link
|
||||||
key={link.href}
|
key={link.href}
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="flex items-center text-zinc-300 hover:text-zinc-100 transition-colors"
|
className="text-sm text-zinc-300 hover:text-zinc-100 transition-colors"
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Dropdown menu */}
|
|
||||||
<div className="relative flex items-center">
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="flex items-center text-zinc-300 hover:text-zinc-100 transition-colors"
|
|
||||||
onClick={toggleServices}
|
|
||||||
aria-expanded={isServicesOpen}
|
|
||||||
aria-label="Toggle services menu"
|
|
||||||
>
|
|
||||||
Services
|
|
||||||
|
|
||||||
<svg
|
|
||||||
className={`ml-1 h-4 w-4 transition-transform duration-300 ${isServicesOpen ? "rotate-180" : ""
|
|
||||||
}`}
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M19 9l-7 7-7-7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* Menu dropdown */}
|
|
||||||
{isServicesOpen && (
|
|
||||||
<div
|
|
||||||
className="absolute top-full mt-2 w-48 bg-zinc-800 rounded-md shadow-lg py-1 border border-zinc-700"
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
>
|
|
||||||
{serviceLinks.map((service) => (
|
|
||||||
<Link
|
|
||||||
key={service.href}
|
|
||||||
href={service.href}
|
|
||||||
className="block px-4 py-2 text-zinc-300 hover:bg-zinc-700 hover:text-zinc-100 transition-colors"
|
|
||||||
>
|
|
||||||
{service.label}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Stabilimento Selector */}
|
||||||
|
<div className="flex-1 flex justify-center px-4">
|
||||||
|
<GlobalStabilimentoSelector />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
{actions ? (
|
{actions ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{actions}
|
{actions}
|
||||||
|
|
|
||||||
106
src/contexts/StabilimentoContext.tsx
Normal file
106
src/contexts/StabilimentoContext.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useCallback,
|
||||||
|
type ReactNode,
|
||||||
|
} from "react";
|
||||||
|
import type { Stabilimento, Magazzino } from "@/src/types/stabilimento";
|
||||||
|
|
||||||
|
interface StabilimentoContextValue {
|
||||||
|
stabilimenti: Stabilimento[];
|
||||||
|
magazzini: Magazzino[];
|
||||||
|
selectedStabilimento: Stabilimento | null;
|
||||||
|
selectedMagazzino: Magazzino | null;
|
||||||
|
loading: boolean;
|
||||||
|
setSelectedStabilimento: (stabilimento: Stabilimento | null) => void;
|
||||||
|
setSelectedMagazzino: (magazzino: Magazzino | null) => void;
|
||||||
|
filteredMagazzini: Magazzino[];
|
||||||
|
resetSelection: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StabilimentoContext = createContext<StabilimentoContextValue | null>(null);
|
||||||
|
|
||||||
|
export function StabilimentoProvider({ children }: { children: ReactNode }) {
|
||||||
|
const [stabilimenti, setStabilimenti] = useState<Stabilimento[]>([]);
|
||||||
|
const [magazzini, setMagazzini] = useState<Magazzino[]>([]);
|
||||||
|
const [selectedStabilimento, setSelectedStabilimentoState] = useState<Stabilimento | null>(null);
|
||||||
|
const [selectedMagazzino, setSelectedMagazzinoState] = useState<Magazzino | null>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
try {
|
||||||
|
const [stabRes, magRes] = await Promise.all([
|
||||||
|
fetch("/api/stabilimenti"),
|
||||||
|
fetch("/api/magazzini"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (stabRes.ok) {
|
||||||
|
const stabData = await stabRes.json();
|
||||||
|
setStabilimenti(stabData.stabilimenti || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (magRes.ok) {
|
||||||
|
const magData = await magRes.json();
|
||||||
|
setMagazzini(magData.magazzini || []);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Errore caricamento stabilimenti/magazzini:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setSelectedStabilimento = useCallback((stabilimento: Stabilimento | null) => {
|
||||||
|
setSelectedStabilimentoState(stabilimento);
|
||||||
|
setSelectedMagazzinoState(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setSelectedMagazzino = useCallback((magazzino: Magazzino | null) => {
|
||||||
|
setSelectedMagazzinoState(magazzino);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resetSelection = useCallback(() => {
|
||||||
|
setSelectedStabilimentoState(null);
|
||||||
|
setSelectedMagazzinoState(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const filteredMagazzini = selectedStabilimento
|
||||||
|
? magazzini.filter((m) => m.id_stabilimento === selectedStabilimento.id)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StabilimentoContext.Provider
|
||||||
|
value={{
|
||||||
|
stabilimenti,
|
||||||
|
magazzini,
|
||||||
|
selectedStabilimento,
|
||||||
|
selectedMagazzino,
|
||||||
|
loading,
|
||||||
|
setSelectedStabilimento,
|
||||||
|
setSelectedMagazzino,
|
||||||
|
filteredMagazzini,
|
||||||
|
resetSelection,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</StabilimentoContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useStabilimento() {
|
||||||
|
const context = useContext(StabilimentoContext);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useStabilimento deve essere usato dentro StabilimentoProvider");
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue