@page "/cms/tracks/{Id:long}" @using DeepDrftManager.Services @attribute [HierarchicalRoleAuthorize([SystemRoleConstants.Admin])] @inject ITrackService TrackService @inject ICmsTrackService CmsTrackService @inject ISnackbar Snackbar @inject IDialogService DialogService @inject NavigationManager Nav @inject ILogger Logger Edit Track — DeepDrft CMS Back to tracks @if (_loading) { } else if (_track is null) { Track not found. } else { Edit Track @_track.EntryKey Vault reference — not editable. Delete Save Changes } @code { [Parameter] public long Id { get; set; } private TrackEntity? _track; private TrackEditForm _form = new(); private bool _loading = true; private bool _busy; private bool CanSave => !string.IsNullOrWhiteSpace(_form.TrackName) && !string.IsNullOrWhiteSpace(_form.Artist); protected override async Task OnInitializedAsync() { await LoadAsync(); } private async Task LoadAsync() { _loading = true; var result = await TrackService.GetById(Id); _track = result.Success ? result.Value : null; if (_track is not null) { _form = TrackEditForm.From(_track); } _loading = false; } private async Task SaveAsync() { if (_track is null || !CanSave) return; _busy = true; try { // Re-fetch under the current scope so we mutate the DB-authoritative entity, not // the copy loaded at OnInitialized. Metadata-only update — EntryKey is immutable. var lookup = await TrackService.GetById(Id); if (!lookup.Success || lookup.Value is null) { Snackbar.Add("Save failed — track could not be loaded.", Severity.Error); return; } var track = lookup.Value; track.TrackName = _form.TrackName; track.Artist = _form.Artist; track.Album = string.IsNullOrWhiteSpace(_form.Album) ? null : _form.Album; track.Genre = string.IsNullOrWhiteSpace(_form.Genre) ? null : _form.Genre; track.ReleaseDate = _form.ReleaseDate is { } d ? DateOnly.FromDateTime(d) : null; var updated = await TrackService.Update(track); if (updated.Success) { Snackbar.Add("Track updated.", Severity.Success); await LoadAsync(); } else { var error = updated.Messages.FirstOrDefault()?.Message ?? "Unknown error"; Snackbar.Add($"Save failed: {error}", Severity.Error); } } catch (Exception ex) { Logger.LogError(ex, "Save failed for track {TrackId}", Id); Snackbar.Add("Save failed — please try again.", Severity.Error); } finally { _busy = false; } } private async Task ConfirmDelete() { if (_track is null) return; var confirmed = await DialogService.ShowMessageBox( "Delete track", $"Permanently delete \"{_track.TrackName}\" by {_track.Artist}? This cannot be undone.", yesText: "Delete", cancelText: "Cancel"); if (confirmed != true) return; _busy = true; try { var result = await CmsTrackService.DeleteTrackAsync(Id); if (result.Success) { Snackbar.Add("Track deleted.", Severity.Success); Nav.NavigateTo("/cms/tracks"); } else { var error = result.Messages.FirstOrDefault()?.Message ?? "Unknown error"; Snackbar.Add($"Delete failed: {error}", Severity.Error); _busy = false; } } catch (Exception ex) { Logger.LogError(ex, "Delete failed for track {TrackId}", Id); Snackbar.Add("Delete failed — please try again.", Severity.Error); _busy = false; } } private sealed class TrackEditForm { public string TrackName { get; set; } = string.Empty; public string Artist { get; set; } = string.Empty; public string? Album { get; set; } public string? Genre { get; set; } public DateTime? ReleaseDate { get; set; } public static TrackEditForm From(TrackEntity track) => new() { TrackName = track.TrackName, Artist = track.Artist, Album = track.Album, Genre = track.Genre, ReleaseDate = track.ReleaseDate is { } d ? d.ToDateTime(TimeOnly.MinValue) : null }; } }