Rimetti i reparti richiudibili e il "+" sul reparto
Le schede di un reparto erano un elenco fisso: con quattro reparti aperti
la pagina diventava un rotolo, e per aggiungere una scheda a un reparto
preciso bisognava passare dal comando generale e ridichiarare il reparto.
La testata del reparto torna a essere un comando: si tocca per richiudere
il gruppo, e la freccia dice da che parte sta. I conteggi salgono nella
testata ("3 schede · 1 da inviare · 1 da completare") invece di stare nel
corpo: un reparto compattato non deve nascondere quello che gli manca.
Accanto torna il "+", che apre la scheda nuova con il reparto gia'
scelto. E' l'unica differenza con il "+" della barra, ed e' quella che
toglie un passaggio a chi sta lavorando su un reparto alla volta.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -151,49 +151,64 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@* Un reparto per volta: la testata si tocca per richiudere il
|
||||
gruppo, e i conteggi restano scritti li' anche da chiuso — un
|
||||
reparto compattato non deve nascondere quello che gli manca. *@
|
||||
@foreach (var group in SchedeGrouped)
|
||||
{
|
||||
var reparto = group.Key;
|
||||
var chiuso = IsCollapsed(reparto);
|
||||
var daInviare = group.Value.CountDaInviare();
|
||||
var daCompletare = group.Value.CountBozze();
|
||||
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<div class="section-header__text">
|
||||
<h2 class="section-header__title">@group.Key.Descrizione</h2>
|
||||
<p class="section-header__desc">
|
||||
@(group.Value.Count == 1 ? "1 scheda" : $"{group.Value.Count} schede")
|
||||
</p>
|
||||
<section class="reparto @(chiuso ? "reparto--collapsed" : "")">
|
||||
<div class="reparto__head">
|
||||
<button type="button" class="reparto__toggle" @onclick="@(() => Toggle(reparto))"
|
||||
aria-expanded="@((!chiuso).ToString().ToLowerInvariant())">
|
||||
<i class="reparto__chevron ri-arrow-down-s-line" aria-hidden="true"></i>
|
||||
<span class="reparto__text">
|
||||
<span class="reparto__title">@reparto.Descrizione</span>
|
||||
<span class="reparto__meta">@Conteggi(group.Value)</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div class="reparto__actions">
|
||||
@if (!IsCompleted)
|
||||
{
|
||||
@* Da qui la scheda nasce gia' con il suo reparto: e'
|
||||
l'unica differenza con il "+" della barra. *@
|
||||
<button type="button" class="reparto__add"
|
||||
disabled="@(!NetworkService.IsNetworkAvailable())"
|
||||
aria-label="@($"Nuova scheda nel reparto {reparto.Descrizione}")"
|
||||
title="@($"Nuova scheda in {reparto.Descrizione}")"
|
||||
@onclick="@(() => CreateNewScheda(reparto))">
|
||||
<i class="ri-add-line" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@if (NetworkService.IsNetworkAvailable() && daInviare > 0)
|
||||
{
|
||||
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||
StartIcon="@Icons.Material.Rounded.CloudUpload"
|
||||
aria-label="@($"Invia le schede del reparto {reparto.Descrizione}")"
|
||||
OnClick="@(() => ExportReparto(reparto))">
|
||||
Invia @daInviare
|
||||
</MudButton>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!IsCompleted && NetworkService.IsNetworkAvailable() && daInviare > 0)
|
||||
{
|
||||
<div class="section-header__aside">
|
||||
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||
StartIcon="@Icons.Material.Rounded.CloudUpload"
|
||||
aria-label="@($"Invia le schede del reparto {group.Key.Descrizione}")"
|
||||
OnClick="@(() => ExportReparto(group.Key))">
|
||||
Invia @daInviare
|
||||
</MudButton>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (daCompletare > 0)
|
||||
@if (!chiuso)
|
||||
{
|
||||
<div class="badge-row" style="margin-bottom: var(--space-10);">
|
||||
<Badge Spec="@SyncState.Bozza.ToBadge()" Text="@($"{daCompletare} da completare")"/>
|
||||
<div class="card-list reparto__body">
|
||||
@foreach (var scheda in group.Value)
|
||||
{
|
||||
<SchedaCard Scheda="scheda" Ispezione="Ispezione"
|
||||
OnSchedaDeleted="OnSchedaDeleted"
|
||||
OnSchedaModified="OnSchedaModified"
|
||||
OnBusyChanged="@(b => VisibleOverlay = b)"/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="card-list">
|
||||
@foreach (var scheda in group.Value)
|
||||
{
|
||||
<SchedaCard Scheda="scheda" Ispezione="Ispezione"
|
||||
OnSchedaDeleted="OnSchedaDeleted"
|
||||
OnSchedaModified="OnSchedaModified"
|
||||
OnBusyChanged="@(b => VisibleOverlay = b)"/>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
}
|
||||
@@ -296,6 +311,43 @@
|
||||
if (modal is { Canceled: false }) LoadSchede();
|
||||
}
|
||||
|
||||
/// Stessa scheda nuova, ma con il reparto gia' scelto: partendo da un
|
||||
/// reparto non ha senso richiederlo.
|
||||
private async Task CreateNewScheda(JtbFasiDto reparto)
|
||||
{
|
||||
var modal = await Dialog.OpenFormScheda(
|
||||
Ispezione.CodMdep, Ispezione.Data, true, new Scheda { Reparto = reparto }
|
||||
);
|
||||
|
||||
if (modal is { Canceled: false }) LoadSchede();
|
||||
}
|
||||
|
||||
// I reparti richiusi stanno qui e non nell'entita': e' uno stato della
|
||||
// schermata, non del documento.
|
||||
private readonly HashSet<string> _collapsed = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private bool IsCollapsed(JtbFasiDto reparto) =>
|
||||
reparto.CodJfas is not null && _collapsed.Contains(reparto.CodJfas);
|
||||
|
||||
private void Toggle(JtbFasiDto reparto)
|
||||
{
|
||||
if (reparto.CodJfas is null) return;
|
||||
if (!_collapsed.Remove(reparto.CodJfas)) _collapsed.Add(reparto.CodJfas);
|
||||
}
|
||||
|
||||
private static string Conteggi(List<Scheda> schede)
|
||||
{
|
||||
var parti = new List<string> { schede.Count == 1 ? "1 scheda" : $"{schede.Count} schede" };
|
||||
|
||||
var daInviare = schede.CountDaInviare();
|
||||
if (daInviare > 0) parti.Add($"{daInviare} da inviare");
|
||||
|
||||
var bozze = schede.CountBozze();
|
||||
if (bozze > 0) parti.Add($"{bozze} da completare");
|
||||
|
||||
return string.Join(" · ", parti);
|
||||
}
|
||||
|
||||
private async Task ConfirmCompleteInspection()
|
||||
{
|
||||
_actionsOpen = false;
|
||||
|
||||
@@ -140,6 +140,98 @@
|
||||
|
||||
.section-header__aside { flex: 0 0 auto; }
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Reparto — gruppo di schede richiudibile
|
||||
La testata e' un comando a tutta riga: si tocca ovunque per chiudere il
|
||||
gruppo. I conteggi stanno nella testata e non nel corpo, cosi' restano
|
||||
leggibili anche da chiuso.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
.reparto__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.reparto__toggle {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
min-height: var(--touch-min);
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.reparto__chevron {
|
||||
flex: 0 0 auto;
|
||||
font-size: 24px;
|
||||
color: var(--ink-muted);
|
||||
transition: transform var(--duration-base) var(--ease-out);
|
||||
}
|
||||
|
||||
.reparto--collapsed .reparto__chevron { transform: rotate(-90deg); }
|
||||
|
||||
.reparto__text {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.reparto__title {
|
||||
display: block;
|
||||
font-size: var(--title-lg-size);
|
||||
line-height: var(--title-lg-height);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.reparto__meta {
|
||||
display: block;
|
||||
margin-top: var(--space-2);
|
||||
font-size: var(--body-md-size);
|
||||
line-height: var(--body-md-height);
|
||||
font-weight: 400;
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.reparto__actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
/* Il "+" del reparto non porta l'accento: l'accento e' del comando principale
|
||||
della schermata, e qui i bottoni sono due in fila. */
|
||||
.reparto__add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--touch-min);
|
||||
height: var(--touch-min);
|
||||
flex: 0 0 auto;
|
||||
border: 1px solid var(--divider);
|
||||
border-radius: var(--radius-pill);
|
||||
background-color: var(--surface);
|
||||
color: var(--ink);
|
||||
font-size: 22px;
|
||||
transition: transform var(--duration-fast) var(--ease-out),
|
||||
background-color var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
.reparto__add:active { transform: scale(0.94); background-color: var(--surface-muted); }
|
||||
.reparto__add:disabled { color: var(--ink-muted); background-color: var(--surface-muted); }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.reparto__add:active { transform: none; }
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
§6.4 Badge — stato in pillola
|
||||
Mai il solo colore: sempre icona + etichetta.
|
||||
|
||||
Reference in New Issue
Block a user