510 lines
15 KiB
Markdown
510 lines
15 KiB
Markdown
|
|
<!-- Generated by SpecStory, Markdown v2.1.0 -->
|
|||
|
|
|
|||
|
|
# 2026-04-28 13:13:46Z
|
|||
|
|
|
|||
|
|
<!-- Cursor IDE Session f2635f9c-fb0d-4e2c-8c03-d1ccaeefd8f1 (2026-04-28 13:13:46Z) -->
|
|||
|
|
|
|||
|
|
_**User**_
|
|||
|
|
|
|||
|
|
Analizza il componente ArticleList.jsx e spiegami perchè pura avendo selezionatoi l magazzino e lo stabilimento non riesco ad effettuare uno scarico dell'articolo?
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Controllo subito `src/ArticleList.jsx` concentrandomi sul flusso di **scarico** e sulle condizioni legate a **magazzino** e **stabilimento**, poi ti spiego esattamente dove si blocca e perché.
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
|||
|
|
<details>
|
|||
|
|
<summary>Tool use: **ripgrep_raw_search**</summary>
|
|||
|
|
|
|||
|
|
|
|||
|
|
Parameters:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"caseInsensitive": true,
|
|||
|
|
"outputMode": "content",
|
|||
|
|
"path": "d:/MagRicambi/src/ArticleList.jsx",
|
|||
|
|
"pattern": "scarico|magazzino|stabilimento|scaricare|warehouse|stabil"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
Additional data:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"isPruned": true,
|
|||
|
|
"outputMode": "content",
|
|||
|
|
"path": "d:/MagRicambi/src/ArticleList.jsx",
|
|||
|
|
"pattern": "scarico|magazzino|stabilimento|scaricare|warehouse|stabil",
|
|||
|
|
"topFiles": [
|
|||
|
|
{
|
|||
|
|
"matchCount": 100,
|
|||
|
|
"uri": "src/ArticleList.jsx"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"totalFiles": 1,
|
|||
|
|
"totalMatches": 100
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
Status: **completed**
|
|||
|
|
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search"><details>
|
|||
|
|
<summary>Tool use: **ripgrep_raw_search**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/ArticleList.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Ho trovato in `ArticleList.jsx` un paio di punti critici; ora apro anche `useStabilimentoMagazzino` e `StabilimentoMagazzinoSelector` perché il blocco sembra legato a come viene davvero salvata la selezione, non solo alla UI.
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/hooks/useStabilimentoMagazzino.js</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/components/StabilimentoMagazzinoSelector.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/modals/MovementModal.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Il problema principale non e` nel backend: e` nel modo in cui `ArticleList` legge la selezione di stabilimento/magazzino.
|
|||
|
|
|
|||
|
|
In `ArticleList` usi un’istanza del hook:
|
|||
|
|
|
|||
|
|
```58:64:src/ArticleList.jsx
|
|||
|
|
const {
|
|||
|
|
selectedStabilimento,
|
|||
|
|
selectedMagazzino,
|
|||
|
|
updateStabilimento,
|
|||
|
|
updateMagazzino,
|
|||
|
|
} = useStabilimentoMagazzino();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Nel selettore `StabilimentoMagazzinoSelector` ne usi **un’altra**, separata:
|
|||
|
|
|
|||
|
|
```12:18:src/components/StabilimentoMagazzinoSelector.jsx
|
|||
|
|
const {
|
|||
|
|
selectedStabilimento,
|
|||
|
|
selectedMagazzino,
|
|||
|
|
updateStabilimento,
|
|||
|
|
updateMagazzino,
|
|||
|
|
resetSelection
|
|||
|
|
} = useStabilimentoMagazzino();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Quindi:
|
|||
|
|
- tu selezioni a video nel `Selector`, ma aggiorni il suo stato locale;
|
|||
|
|
- `ArticleList` continua a usare il **suo** `selectedMagazzino`/`selectedStabilimento` (spesso vuoti o non aggiornati in tempo reale);
|
|||
|
|
- di conseguenza lo scarico resta bloccato (`disabled`, controlli su `!selectedStabilimento || !selectedMagazzino`, giacenze non caricate sul magazzino atteso).
|
|||
|
|
|
|||
|
|
In piu`, nell’`onSelectionChange` di `ArticleList` fai solo log e non sincronizzi niente:
|
|||
|
|
|
|||
|
|
```900:906:src/ArticleList.jsx
|
|||
|
|
onSelectionChange={(stabilimento, magazzino) => {
|
|||
|
|
// La selezione viene gestita automaticamente dal hook
|
|||
|
|
console.log("ArticleList: Selezione aggiornata", {
|
|||
|
|
stabilimento,
|
|||
|
|
magazzino,
|
|||
|
|
});
|
|||
|
|
}}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Per questo “sembra selezionato”, ma lo scarico non parte.
|
|||
|
|
|
|||
|
|
Secondario ma importante: `MovementModal` valida su `movimento.articolo.quantita` (totale), mentre `ArticleList` valida per magazzino (`giacenzePerMagazzino`). Questo puo` creare incoerenze nei messaggi, ma il blocco principale e` la doppia istanza del hook.
|
|||
|
|
|
|||
|
|
Se vuoi, nel prossimo step ti preparo la patch corretta (stato unico in `ArticleList` passato al `Selector` via props, oppure Context condiviso) così lo scarico funziona subito.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
_**User**_
|
|||
|
|
|
|||
|
|
applica uno stato unico in ArticleList passato al Selector via props..
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Perfetto, applico subito la versione “controllata”: stato unico in `ArticleList` e `StabilimentoMagazzinoSelector` pilotato via props, senza hook interno duplicato. Poi faccio un controllo lint rapido sui file toccati.
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/ArticleList.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
|||
|
|
<details><summary>Tool use: **read_file_v2** • Read file: d:/MagRicambi/src/components/StabilimentoMagazzinoSelector.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
|||
|
|
<summary>Tool use: **read_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Sto applicando ora le modifiche ai due file: `Selector` controllato via props e collegamento diretto delle callback in `ArticleList` (`updateStabilimento`, `updateMagazzino`).
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
|
|||
|
|
|
|||
|
|
<details><summary>Tool use: **edit_file_v2** • Edit file: d:/MagRicambi/src/components/StabilimentoMagazzinoSelector.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
|||
|
|
<summary>Tool use: **edit_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
|
|||
|
|
|
|||
|
|
<details><summary>Tool use: **edit_file_v2** • Edit file: d:/MagRicambi/src/ArticleList.jsx</summary>
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
|||
|
|
<summary>Tool use: **edit_file_v2**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="unknown" data-tool-name="read_lints">
|
|||
|
|
<details>
|
|||
|
|
<summary>Tool use: **read_lints**</summary>
|
|||
|
|
|
|||
|
|
|
|||
|
|
Parameters:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"paths": [
|
|||
|
|
"d:/MagRicambi/src/ArticleList.jsx",
|
|||
|
|
"d:/MagRicambi/src/components/StabilimentoMagazzinoSelector.jsx"
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
Result:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"linterErrorsByFile": [
|
|||
|
|
{
|
|||
|
|
"relativeWorkspacePath": "d:/MagRicambi/src/ArticleList.jsx"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"relativeWorkspacePath": "d:/MagRicambi/src/components/StabilimentoMagazzinoSelector.jsx"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
Status: **completed**
|
|||
|
|
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
</tool-use>
|
|||
|
|
|
|||
|
|
<tool-use data-tool-type="unknown" data-tool-name="read_lints"><details>
|
|||
|
|
<summary>Tool use: **read_lints**</summary>
|
|||
|
|
|
|||
|
|
</details></tool-use>
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Fatto: ho applicato lo stato unico in `ArticleList` e reso `StabilimentoMagazzinoSelector` un componente controllato via props.
|
|||
|
|
|
|||
|
|
Cosa ho cambiato:
|
|||
|
|
- In `src/components/StabilimentoMagazzinoSelector.jsx`:
|
|||
|
|
- rimosso `useStabilimentoMagazzino` interno;
|
|||
|
|
- aggiunte props controllate: `selectedStabilimento`, `selectedMagazzino`;
|
|||
|
|
- aggiunte callback: `onStabilimentoChange`, `onMagazzinoChange`, `onReset`;
|
|||
|
|
- il componente ora usa solo i valori/callback passati dal parent.
|
|||
|
|
- In `src/ArticleList.jsx`:
|
|||
|
|
- uso del solo hook locale (`useStabilimentoMagazzino`) come source of truth;
|
|||
|
|
- passato al selector:
|
|||
|
|
- `selectedStabilimento={selectedStabilimento}`
|
|||
|
|
- `selectedMagazzino={selectedMagazzino}`
|
|||
|
|
- `onStabilimentoChange={updateStabilimento}`
|
|||
|
|
- `onMagazzinoChange={updateMagazzino}`
|
|||
|
|
- `onReset={resetSelection}`
|
|||
|
|
|
|||
|
|
Verifica:
|
|||
|
|
- nessun errore lint nei file modificati.
|
|||
|
|
|
|||
|
|
Adesso la selezione che fai nel selector e` la stessa letta da `confermaMovimento`, quindi lo scarico non resta piu` bloccato per disallineamento di stato.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
_**User**_
|
|||
|
|
|
|||
|
|
Da ora lavora, analizza e agisci come un web developer full stack senior di esperienza decennale. Analizza il componente AricleList.js e spiegami il funzionamento in modo dettagliato punto per punto, grazie.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
_**Agent (default)**_
|
|||
|
|
|
|||
|
|
Certo. Ti spiego `ArticleList` come farei in una code review senior, in modo funzionale e operativo.
|
|||
|
|
|
|||
|
|
## Visione generale
|
|||
|
|
|
|||
|
|
`src/ArticleList.jsx` è un componente “orchestratore” di magazzino:
|
|||
|
|
- carica e mostra articoli/famiglie;
|
|||
|
|
- gestisce ricerca, ordinamento, paginazione;
|
|||
|
|
- gestisce i movimenti di carico/scarico;
|
|||
|
|
- coordina il contesto di selezione `stabilimento/magazzino`;
|
|||
|
|
- apre modali per aggiunta, modifica, movimento, barcode, info articolo.
|
|||
|
|
|
|||
|
|
Non è solo una lista UI: contiene una parte consistente di logica business lato frontend.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1) Input (props) e responsabilità
|
|||
|
|
|
|||
|
|
Riceve da parent:
|
|||
|
|
- `stabilimenti`, `magazzini` (anagrafiche già caricate fuori dal componente),
|
|||
|
|
- `currentUser`,
|
|||
|
|
- callback come `onArticleUpdate`,
|
|||
|
|
- filtri esterni (`familyFilterId`, `understockOnly`, `onClearUnderstock`),
|
|||
|
|
- `showHeader`.
|
|||
|
|
|
|||
|
|
Questo design separa bene: anagrafiche da parent, operazioni specifiche in `ArticleList`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2) Stato locale principale
|
|||
|
|
|
|||
|
|
Mantiene molti state con `useState`, raggruppabili in 5 aree:
|
|||
|
|
|
|||
|
|
- **Dati base**: `articles`, `famiglie`
|
|||
|
|
- **UI listato**: `search`, `searchCode`, `sortBy`, `sortOrder`, `page`
|
|||
|
|
- **Workflow modali**: `addingArticle`, `editingArticle`, `movimento`, `barcodeArticle`, `infoArticolo`
|
|||
|
|
- **Movimentazione**: `qtyMovimento`
|
|||
|
|
- **Giacenze**:
|
|||
|
|
- `giacenzeArticoli`: totale per articolo
|
|||
|
|
- `giacenzePerMagazzino`: mappa per magazzino+articolo (chiave annidata)
|
|||
|
|
|
|||
|
|
In più usa `barcodeRef` per generazione barcode nel DOM.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3) Selezione stabilimento/magazzino (core del flusso)
|
|||
|
|
|
|||
|
|
`ArticleList` usa `useStabilimentoMagazzino()` come source of truth:
|
|||
|
|
- `selectedStabilimento`
|
|||
|
|
- `selectedMagazzino`
|
|||
|
|
- `updateStabilimento`
|
|||
|
|
- `updateMagazzino`
|
|||
|
|
- `resetSelection`
|
|||
|
|
|
|||
|
|
E passa questi valori/callback al componente `StabilimentoMagazzinoSelector` (ora controllato da props).
|
|||
|
|
Questa parte è fondamentale perché tutte le abilitazioni scarico/carico dipendono da questa selezione.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4) Caricamento dati iniziale e refresh
|
|||
|
|
|
|||
|
|
Funzione centrale: `loadData()`:
|
|||
|
|
- `Promise.all([fetchFamiglie(), fetchArticles()])`
|
|||
|
|
- aggiorna `famiglie` e `articles`.
|
|||
|
|
|
|||
|
|
`useEffect`:
|
|||
|
|
- al mount: carica dati iniziali;
|
|||
|
|
- su cambio pagina: ricarica (scelta discutibile, ma presente);
|
|||
|
|
- espone `window.articleListRef = { loadData }` quando c’è `onArticleUpdate` (ponte verso componenti esterni).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5) Caricamento giacenze per magazzino selezionato
|
|||
|
|
|
|||
|
|
Quando cambia `selectedMagazzino`:
|
|||
|
|
- chiama `giacenzeApi.getAll({ id_magazzino: selectedMagazzino })`
|
|||
|
|
- costruisce:
|
|||
|
|
- `giacenzePerMagazzinoMap[id_magazzino][articolo_id] = { quantita }`
|
|||
|
|
- `giacenzeTotaliMap[articolo_id] += quantita`
|
|||
|
|
- aggiorna gli state di giacenza.
|
|||
|
|
|
|||
|
|
Questo è il dato usato poi per:
|
|||
|
|
- abilitare/disabilitare scarico,
|
|||
|
|
- mostrare giacenza specifica del magazzino scelto.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6) Aggiunta articolo (`confermaAggiuntaArticolo`)
|
|||
|
|
|
|||
|
|
Flusso:
|
|||
|
|
1. valida campi minimi (`descrizione`, `id_famiglia`);
|
|||
|
|
2. crea articolo via `addArticle(...)`;
|
|||
|
|
3. se quantità iniziale > 0, crea anche movimento automatico `"in"` con causale `"Carico iniziale"` (tracciabilità);
|
|||
|
|
4. reset form + chiusura modal + `loadData()` + `onArticleUpdate?.()`.
|
|||
|
|
|
|||
|
|
Quindi l’inserimento articolo è “event-sourced light”: non solo record articolo ma anche movimento associato.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7) Modifica articolo (`confermaModificaArticolo`)
|
|||
|
|
|
|||
|
|
Flusso:
|
|||
|
|
1. recupera articolo originale da `articles`;
|
|||
|
|
2. calcola delta quantità tra nuovo e vecchio;
|
|||
|
|
3. aggiorna anagrafica articolo (`updateArticle`);
|
|||
|
|
4. se delta ≠ 0 crea movimento automatico:
|
|||
|
|
- `"in"` se aumenta,
|
|||
|
|
- `"out"` se diminuisce,
|
|||
|
|
- quantità assoluta.
|
|||
|
|
|
|||
|
|
Include campi magazzino/stabilimento di appoggio (`id_magazzino_destinazione`, fallback `id_magazzino`), con molti log di debug.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8) Movimento manuale carico/scarico (`confermaMovimento`)
|
|||
|
|
|
|||
|
|
Validazioni:
|
|||
|
|
- blocca se mancano `selectedStabilimento` o `selectedMagazzino`;
|
|||
|
|
- blocca quantità non valida;
|
|||
|
|
- per scarico (`out`) verifica disponibilità **sulla giacenza del magazzino selezionato**.
|
|||
|
|
|
|||
|
|
Payload movimento:
|
|||
|
|
- `id_articolo`, `tipo_movimento`, `quantita`, `causale`,
|
|||
|
|
- `id_stabilimento`, `id_magazzino`,
|
|||
|
|
- campi multi-warehouse:
|
|||
|
|
- `id_magazzino_origine` per `out`,
|
|||
|
|
- `id_magazzino_destinazione` per `in`.
|
|||
|
|
|
|||
|
|
Dopo la chiamata:
|
|||
|
|
- aggiorna ottimisticamente `giacenzePerMagazzino`,
|
|||
|
|
- resetta modal/stato quantità,
|
|||
|
|
- notifica successo e fa `loadData()`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9) Ricerca, filtri, ordinamento
|
|||
|
|
|
|||
|
|
Pipeline dati:
|
|||
|
|
1. `filteredArticles`:
|
|||
|
|
- match descrizione (`search`)
|
|||
|
|
- match codice/barcode (`searchCode`)
|
|||
|
|
- filtro sottoscorta (`understockOnly`)
|
|||
|
|
- filtro famiglia (`familyFilterId`)
|
|||
|
|
2. `sortedArticles`:
|
|||
|
|
- `quantita` ordinata numericamente
|
|||
|
|
- altri campi ordinati lessicograficamente
|
|||
|
|
3. paginazione:
|
|||
|
|
- `paginatedArticles = sortedArticles.slice(...)`
|
|||
|
|
|
|||
|
|
Quando cambiano filtri/ricerche resetta `page` a 1.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10) Rendering item articolo e UX operativa
|
|||
|
|
|
|||
|
|
Per ogni articolo:
|
|||
|
|
- calcola `giacenzaMag` dal magazzino selezionato;
|
|||
|
|
- abilita drag & drop solo se `giacenzaMag > 0` e c’è magazzino selezionato;
|
|||
|
|
- mostra doppia quantità:
|
|||
|
|
- totale articolo,
|
|||
|
|
- quantità nel magazzino selezionato;
|
|||
|
|
- pulsanti azione:
|
|||
|
|
- info,
|
|||
|
|
- modifica,
|
|||
|
|
- carico (`📥`),
|
|||
|
|
- scarico (`📤`, disabilitato se giacenza magazzino <= 0),
|
|||
|
|
- barcode.
|
|||
|
|
|
|||
|
|
Il titolo tooltip cambia in base allo stato (es. “Seleziona Stabilimento e Magazzino”, “Giacenza insufficiente”).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11) Modali usate
|
|||
|
|
|
|||
|
|
- `ArticoliModal`: aggiunta/modifica articolo
|
|||
|
|
- `MovementModal`: conferma carico/scarico con causale/quantità
|
|||
|
|
- `BarcodeModal`: visualizzazione/stampa barcode
|
|||
|
|
- `ArticoloInfoModal`: dettaglio informativo
|
|||
|
|
|
|||
|
|
Il componente funge da “state owner” per tutte.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12) Osservazioni tecniche da senior (importanti)
|
|||
|
|
|
|||
|
|
- **Componente molto grande** (oltre 1200 righe): conviene modularizzare (custom hooks + subcomponenti) per manutenibilità/testabilità.
|
|||
|
|
- **Tanti `console.log`**: utili in debug, ma da ridurre/astrarre (logger con livelli).
|
|||
|
|
- **Doppia fonte quantità** (`article.quantita` vs `giacenzePerMagazzino`): da mantenere coerente sempre, altrimenti UX ambigua.
|
|||
|
|
- **Refresh su cambio pagina**: ricaricare tutto a ogni pagina può costare; meglio paginazione client pura o server-side coerente.
|
|||
|
|
- **Tipizzazione assente** (JS puro): TypeScript ridurrebbe errori su payload movimenti/giacenze.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
Se vuoi, nel prossimo step posso farti una **mappa tecnica completa delle dipendenze** di `ArticleList` (API chiamate, payload attesi, modali collegate, punti esatti da rifattorizzare) e proporti una versione più pulita in 3 hook dedicati.
|