import { Component, effect, inject } from '@angular/core'; import { AsyncPipe } from '@angular/common'; import { map, Observable, startWith } from 'rxjs'; import { ShowService } from '../services/show.service'; import { Show } from '../interfaces/show'; import { StationConfigService } from '../services/station-config.service'; import { StructuredDataService } from '../services/structured-data.service'; import { SortSchedulesPipe } from '../pipes/sort-schedules.pipe'; import { resolveImageUrl } from '../services/app-config.service'; interface ScheduleState { loading: boolean; shows: Show[]; } @Component({ selector: 'app-schedule', standalone: true, imports: [AsyncPipe, SortSchedulesPipe], templateUrl: './schedule.component.html', styleUrl: './schedule.component.scss', }) export class ScheduleComponent { private showService = inject(ShowService); readonly config = inject(StationConfigService).config; private structuredData = inject(StructuredDataService); /** ID of the currently expanded show card — null means none. */ expandedShowId: number | null = null; /** Toggle expansion: clicking the active card collapses it; clicking another expands it. */ toggleShow(showId: number): void { this.expandedShowId = this.expandedShowId === showId ? null : showId; } /** Async pipe drives the template — guarantees change detection on every emission. */ readonly schedule$: Observable = this.showService.getShows().pipe( map((shows) => ({ loading: false, shows })), startWith({ loading: true, shows: [] }), ); /** Resolve a relative uploads/… path to an absolute URL for image rendering. */ resolveAsset(url: string | null): string { return resolveImageUrl(url ?? ''); } resolveImageUrl(url: string): string { return resolveImageUrl(url); } constructor() { // Feed active shows to structured data for RadioSeason schema injection. effect(() => { const snapshot = this.showService.getShows(); snapshot.subscribe((shows) => { this.structuredData.activeShows.set(shows); }); }); } }