Prima implementazione pagina "Attività"

This commit is contained in:
2026-06-08 09:25:29 +02:00
parent 4661922633
commit b7955f0e1f
34 changed files with 1582 additions and 266 deletions
@@ -0,0 +1,126 @@
@page "/attivita"
@rendermode @(InteractiveServer)
@inject MockAttivitaService MockService
<div class="attivita-page">
<div class="page-header">
<div>
<h1 class="page-title">Attività</h1>
<span class="page-date">@DateTime.Today.ToString("dddd d MMMM", new System.Globalization.CultureInfo("it-IT"))</span>
</div>
<div class="page-header-actions">
<span class="counter-badge">@_attivita.Count(a => a.Stato == StatoAttivita.Aperta) aperte</span>
<button type="button" class="btn-fine-viaggio" @onclick="FineViaggio">
<i class="ri-flag-2-line"></i>
Fine Viaggio
</button>
</div>
</div>
@if (!_attivita.Any())
{
<NoDataAvailable
ImageSource="_content/Fixiy.Shared/images/empty-state.svg"
Text="Nessuna attività per oggi" />
}
else
{
<div class="attivita-list">
@foreach (var item in AttivitaOrdinata)
{
<AttivitaCard
Attivita="item"
OnChiudi="ApriChiusura"
OnVisualizzaAllegati="ApriAllegati"
OnDragStart="OnDragStart"
OnDrop="OnDrop" />
}
</div>
}
</div>
<ChiusuraModal
Attivita="_attivitaSelezionata"
Visible="_chiusuraVisible"
OnClosed="() => _chiusuraVisible = false"
OnConferma="OnConfermaChiusura" />
<AllegatiModal
Attivita="_attivitaSelezionata"
Visible="_allegatiVisible"
OnClosed="() => _allegatiVisible = false" />
@code {
List<AttivitaItem> _attivita = [];
AttivitaItem? _attivitaSelezionata;
bool _chiusuraVisible;
bool _allegatiVisible;
AttivitaItem? _dragSource;
IEnumerable<AttivitaItem> AttivitaOrdinata =>
_attivita.OrderBy(a => a.Priorita switch
{
PrioritaAttivita.Emergenza => 0,
PrioritaAttivita.Alta => 1,
_ => 2
})
.ThenBy(a => a.Ordine);
protected override void OnInitialized()
{
_attivita = MockService.GetAttivitaOggi();
}
void ApriChiusura(AttivitaItem item)
{
_attivitaSelezionata = item;
_chiusuraVisible = true;
}
void ApriAllegati(AttivitaItem item)
{
_attivitaSelezionata = item;
_allegatiVisible = true;
}
void OnConfermaChiusura((AttivitaItem item, StatoAttivita stato) args)
{
var idx = _attivita.IndexOf(args.item);
if (idx >= 0)
_attivita[idx] = args.item with { Stato = args.stato };
_chiusuraVisible = false;
}
void OnDragStart(AttivitaItem item)
{
if (!item.IsLocked)
_dragSource = item;
}
void OnDrop(AttivitaItem target)
{
if (_dragSource is null || _dragSource == target || target.IsLocked)
return;
var srcIdx = _attivita.IndexOf(_dragSource);
var tgtIdx = _attivita.IndexOf(target);
if (srcIdx < 0 || tgtIdx < 0) return;
_attivita.RemoveAt(srcIdx);
_attivita.Insert(tgtIdx, _dragSource);
for (int i = 0; i < _attivita.Count; i++)
_attivita[i] = _attivita[i] with { Ordine = i };
_dragSource = null;
}
void FineViaggio()
{
// TODO: generare e inviare PDF/CSV via email
}
}
@@ -0,0 +1,81 @@
.attivita-page {
padding: 0;
padding-top: calc(0.75rem + env(safe-area-inset-top, 0px));
}
.page-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.75rem;
margin-bottom: 1.4rem;
}
.page-header-actions {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.5rem;
flex-shrink: 0;
}
.page-date {
font-size: 0.78rem;
color: #999;
text-transform: capitalize;
margin-top: 0.15rem;
}
.counter-badge {
background: var(--primary-color);
color: #fff;
font-size: 0.72rem;
font-weight: 700;
padding: 0.3rem 0.85rem;
border-radius: 100px;
white-space: nowrap;
box-shadow: 0 4px 12px rgba(83, 82, 237, 0.28);
}
.attivita-list {
display: flex;
flex-direction: column;
gap: 1rem;
/* spazio per la bottom nav */
padding-bottom: 7rem;
}
/* Bottone "Fine Viaggio" integrato nell'header */
.btn-fine-viaggio {
background: linear-gradient(135deg, #5352ed, #3f3bc4);
color: #fff;
border: none;
border-radius: 100px;
padding: 0.5rem 1.1rem;
font-family: inherit;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.01em;
white-space: nowrap;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
box-shadow: 0 5px 16px rgba(83, 82, 237, 0.32);
cursor: pointer;
transition: box-shadow 0.18s ease, transform 0.15s ease;
-webkit-tap-highlight-color: transparent;
}
.btn-fine-viaggio i {
font-size: 1.05rem;
line-height: 1;
}
.btn-fine-viaggio:hover {
box-shadow: 0 7px 20px rgba(83, 82, 237, 0.42);
}
.btn-fine-viaggio:active {
transform: scale(0.97);
}
@@ -0,0 +1,11 @@
@page "/scheda-viaggi"
<div class="page-header">
<h1 class="page-title">Scheda Viaggi</h1>
</div>
<div class="page-content">
<NoDataAvailable
ImageSource="_content/Fixiy.Shared/images/empty-state.svg"
Text="Nessun viaggio disponibile" />
</div>