@page "/tire-storage" @implements IAsyncDisposable @inject ITireStackService TireStackService @inject IStorageLocationService StorageLocationService @inject ICatalogService CatalogService @inject UserSessionService UserSession @inject IJSRuntime JS @using Lagerbestand.Components.Shared Lagerübersicht - Reifen Späth Lagerverwaltung @if (!UserSession.IsWorkerOrAdmin) { } else {
@* Statistics *@
@stats.TotalStacksStored Stapel (@stats.TotalTiresStored Reifen)
@stats.CustomerStackCount Kundenstapel
@stats.InventoryStackCount Lagerbestand
@stats.AvailableLocations Freie Plätze
@* Type Filter (Customer vs Inventory) *@ @* View Toggle (List / Rack Grid) *@ @* Search & Filter *@
Durchsucht Namen, Fahrzeuge, Kategorien und Ticket-Nummern
Nach Saison filtern
@* Category Filter (only when showing inventory) *@ @if (typeFilter == true && categories.Count > 0) {
} @* Tire Stacks List *@ @if (isLoading) {
Lade Daten...
} else if (showGridView) {
@foreach (var area in new[] { AreaType.Werkstatt, AreaType.Lager }) {

@area.GetBuildingLabel()

@for (int row = StorageLocation.MinRow; row <= area.GetMaxRow(); row++) { var currentRow = row;

Reihe @currentRow

@foreach (var side in new[] { "Links", "Rechts" }) {
@side @foreach (var pos in ShelfPositionExtensions.All.Where(p => p.IsLeft() == (side == "Links")).OrderByDescending(p => p.IsTop())) {
@(pos.IsTop() ? "Oben" : "Unten")
@for (int slot = StorageLocation.MinSlot; slot <= StorageLocation.MaxSlot; slot++) { var loc = GetLocation(area, currentRow, pos, slot); var cellClass = loc == null ? "missing" : !loc.IsAvailable ? "blocked" : loc.IsOccupied ? "occupied" : "free"; }
}
}
}
} @if (selectedLocation != null) { }
} else if (filteredTireStacks.Count == 0) {

Keine Einträge

@(string.IsNullOrEmpty(searchTerm) ? "Noch keine Reifenstapel eingelagert." : "Keine Ergebnisse für Ihre Suche.")

@if (string.IsNullOrEmpty(searchTerm)) { Reifenstapel einlagern }
} else {
@foreach (var ts in filteredTireStacks) {
@(ts.Season == TireSeason.Sommer ? "☀️" : ts.Season == TireSeason.Winter ? "❄️" : "🔄")
@if (ts.IsInventory) { @(ts.CatalogItem?.Name ?? "Lagerbestand") } else { @ts.Customer?.FullName } 1 Stapel (@TireStack.TiresPerStack Reifen) @(ts.TireSize != null ? $"| {ts.TireSize}" : "") @(ts.WithRims ? "| mit Felgen" : "")
@(ts.StorageLocation?.Code ?? "-") @if (!ts.IsInventory && ts.Vehicle != null) { @ts.Vehicle.ShortName } @if (ts.IsInventory) { Lager }
@if (expandedId == ts.Id) {
Ticket-Nr.
@ts.TicketNumber
Reifenstapel
1 Stapel (@TireStack.TiresPerStack Reifen)
@if (ts.IsInventory && ts.CatalogItem != null) {
Kategorie
@ts.CatalogItem.Name
}
Marke
@(ts.TireBrand ?? "-")
Modell
@(ts.TireModel ?? "-")
Zustand
@ts.ConditionText
Eingelagert
Dauer
@ts.DaysStored Tage
@if (!string.IsNullOrEmpty(ts.Notes)) {
Notizen: @ts.Notes
}
}
}
} @* Expiring Pickups Warning (only for customer stacks) *@ @if (expiringPickups.Count > 0) { }
} @code { private List allTireStacks = new(); private List filteredTireStacks = new(); private List expiringPickups = new(); private List categories = new(); private StorageStatistics stats = new(); private string searchTerm = ""; private TireSeason? seasonFilter; private bool? typeFilter; // null = all, false = customer, true = inventory private string selectedCategoryId = ""; private Guid? expandedId; private bool isLoading = true; private bool showGridView; private List allLocations = new(); private Dictionary<(AreaType, int, ShelfPosition, int), StorageLocation> locationLookup = new(); private StorageLocation? selectedLocation; protected override async Task OnInitializedAsync() { if (UserSession.IsWorkerOrAdmin) { await LoadData(); } } private DotNetObjectReference? _visibilityRef; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && UserSession.IsWorkerOrAdmin) { _visibilityRef = DotNetObjectReference.Create(this); await VisibilityRefresh.RegisterAsync(JS, _visibilityRef, nameof(OnVisibilityReturn), 120); } } [JSInvokable] public async Task OnVisibilityReturn(int hiddenSeconds) { if (!UserSession.IsWorkerOrAdmin) return; await LoadData(); await InvokeAsync(StateHasChanged); } public async ValueTask DisposeAsync() { await VisibilityRefresh.UnregisterAsync(JS); _visibilityRef?.Dispose(); } private async Task LoadData() { isLoading = true; StateHasChanged(); try { allTireStacks = await TireStackService.GetAllAsync(TireStackStatus.Stored); stats = await TireStackService.GetStatisticsAsync(); expiringPickups = await TireStackService.GetExpiringPickupsAsync(); categories = await CatalogService.GetAllAsync(); allLocations = await StorageLocationService.GetAllAsync(); locationLookup = allLocations.ToDictionary(l => (l.Area, l.Row, l.Position, l.SlotNumber)); if (selectedLocation != null) { selectedLocation = allLocations.FirstOrDefault(l => l.Id == selectedLocation.Id); } ApplyFilters(); } finally { isLoading = false; } } private void FilterTireStacks() { ApplyFilters(); } private void SetSeasonFilter(TireSeason? season) { seasonFilter = season; ApplyFilters(); } private void SetTypeFilter(bool? isInventory) { typeFilter = isInventory; selectedCategoryId = ""; // Reset category filter when changing type ApplyFilters(); } private void ApplyFilters() { var query = allTireStacks.AsEnumerable(); // Type filter (customer vs inventory) if (typeFilter.HasValue) { if (typeFilter.Value) query = query.Where(ts => ts.CustomerId == null); else query = query.Where(ts => ts.CustomerId != null); } // Season filter if (seasonFilter.HasValue) { query = query.Where(ts => ts.Season == seasonFilter.Value); } // Category filter (for inventory) if (!string.IsNullOrEmpty(selectedCategoryId) && Guid.TryParse(selectedCategoryId, out var catId)) { query = query.Where(ts => ts.CatalogItemId == catId); } // Search term if (!string.IsNullOrWhiteSpace(searchTerm)) { var term = searchTerm.ToLower(); query = query.Where(ts => (ts.Customer?.FullName?.ToLower().Contains(term) ?? false) || (ts.Vehicle?.Make?.ToLower().Contains(term) ?? false) || (ts.Vehicle?.Model?.ToLower().Contains(term) ?? false) || (ts.Customer?.CustomerNumber?.ToLower().Contains(term) ?? false) || (ts.CatalogItem?.Name?.ToLower().Contains(term) ?? false) || (ts.StorageLocation?.Code?.ToLower().Contains(term) ?? false) || ts.TicketNumber.ToLower().Contains(term) || (ts.TireBrand?.ToLower().Contains(term) ?? false) || (ts.TireSize?.ToLower().Contains(term) ?? false) ); } filteredTireStacks = query.OrderBy(ts => ts.StorageLocation?.Code).ToList(); } private void ToggleDetails(Guid id) { expandedId = expandedId == id ? null : id; } private StorageLocation? GetLocation(AreaType area, int row, ShelfPosition pos, int slot) { return locationLookup.TryGetValue((area, row, pos, slot), out var loc) ? loc : null; } private void SelectLocation(StorageLocation? location) { if (location == null) return; selectedLocation = selectedLocation?.Id == location.Id ? null : location; } private string GetCellTooltip(StorageLocation? loc, AreaType area, int row, ShelfPosition pos, int slot) { var baseText = $"{area.GetDisplayName()}, Reihe {row}, {pos.GetDisplayName()}, Platz {slot}"; if (loc == null) return $"{baseText} – nicht angelegt"; if (!loc.IsAvailable) return $"{baseText} – gesperrt"; if (loc.IsOccupied) { var stack = loc.OccupiedTireStack; var who = stack == null ? "belegt" : stack.IsInventory ? stack.CatalogItem?.Name ?? "Lagerbestand" : stack.Customer?.FullName ?? "belegt"; return $"{baseText} – {who}"; } return $"{baseText} – frei"; } }