@using DeepDrftModels.DTOs @using DeepDrftModels.Enums @using DeepDrftPublic.Client.Helpers @using DeepDrftPublic.Client.Services @implements IDisposable
@* Studio Cuts — primary figure is the total Cut-medium track count; the secondary breakdown lists per-ReleaseType Cut release counts, zero-count types already suppressed server-side. *@
@_stats.CutTrackCount
Studio Cuts
@if (_stats.CutReleaseTypeCounts.Count > 0) {
@foreach (var row in _stats.CutReleaseTypeCounts) { @row.Count @PluralizeReleaseType(row.ReleaseType, row.Count) }
}
@* Mixes — primary figure is the Mix release count labelled "Sets"; the secondary figure is total mix runtime as hh:mm. *@
@_stats.MixReleaseCount
Sets
@RuntimeFormat.ToHoursMinutes(_stats.MixRuntimeSeconds) runtime
@* Plays — live site-wide play total in the odometer (the "90s visitor counter" aesthetic is the intended treatment). Secondary line is unique anonymous listeners (Phase 16 D7). Both read from the same HomeStatsDto round-trip the other two cards use — no extra fetch. Reads zero until the play-telemetry migration is applied. *@
@_stats.TotalPlays
Plays
@_stats.UniqueListeners listeners
@code { [Inject] public required IStatsDataService StatsData { get; set; } [Inject] public required PersistentComponentState PersistentState { get; set; } private const string PersistKey = "home-stats"; private HomeStatsDto _stats = new(); private bool _loaded; private PersistingComponentStateSubscription _persistingSubscription; protected override async Task OnInitializedAsync() { _persistingSubscription = PersistentState.RegisterOnPersisting(Persist); // Bridge the prerendered fetch across the prerender -> WASM seam so the WASM boot does not // re-fetch and flicker the figures (the TracksView persistent-state seam, applied to stats). if (PersistentState.TryTakeFromJson(PersistKey, out var restored) && restored is not null) { _stats = restored; _loaded = true; return; } var result = await StatsData.GetHomeStats(); if (result is { Success: true, Value: { } stats }) { _stats = stats; _loaded = true; } } // Only bridge a successful fetch. If prerender failed, persist nothing so the WASM pass re-fetches // rather than restoring zeros — mirrors the guard on the medium-browse persist path. private Task Persist() { if (_loaded) PersistentState.PersistAsJson(PersistKey, _stats); return Task.CompletedTask; } private static string PluralizeReleaseType(ReleaseType type, int count) { var label = type switch { ReleaseType.Single => "Single", ReleaseType.EP => "EP", ReleaseType.Album => "Album", _ => type.ToString() }; // EP pluralizes as "EPs"; Single/Album take a plain trailing s. return count == 1 ? label : label + "s"; } public void Dispose() => _persistingSubscription.Dispose(); }