import { Component, computed, DestroyRef, inject, input } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatIconButton } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { Router } from '@angular/router'; import { CategoryViewComponent } from '@iptvnator/portal/shared/ui'; import { PlaylistErrorViewComponent } from '@iptvnator/portal/shared/ui'; import { StalkerStore } from '@iptvnator/portal/stalker/data-access'; import { CategoryManagementDialogComponent, CategoryManagementDialogData, } from '@iptvnator/portal/xtream/feature'; import { XtreamStore } from '@iptvnator/portal/xtream/data-access'; type WorkspaceProvider = 'xtreams' | 'stalker' | 'playlists'; interface WorkspaceContextRoute { provider: WorkspaceProvider; playlistId: string; } interface XtreamCategoryLike { id?: number | string; category_id?: string; } @Component({ selector: 'app-workspace-context-panel', imports: [ CategoryViewComponent, PlaylistErrorViewComponent, MatIconButton, MatIcon, MatTooltip, ], templateUrl: './workspace-context-panel.component.html', styleUrl: './workspace-context-panel.component.scss', }) export class WorkspaceContextPanelComponent { private readonly router = inject(Router); private readonly xtreamStore = inject(XtreamStore); private readonly stalkerStore = inject(StalkerStore); private readonly dialog = inject(MatDialog); private readonly destroyRef = inject(DestroyRef); readonly context = input.required(); readonly section = input.required(); readonly isXtreamCategories = computed( () => this.context().provider === 'xtreams' && (this.section() === 'vod' || this.section() === 'series' || this.section() === 'live') ); readonly isStalkerCategories = computed( () => this.context().provider === 'stalker' && (this.section() === 'vod' || this.section() === 'series' || this.section() === 'itv') ); readonly xtreamCategories = this.xtreamStore.getCategoriesBySelectedType; readonly xtreamCategoryItemCounts = this.xtreamStore.getCategoryItemCounts; readonly xtreamSelectedCategoryId = this.xtreamStore.selectedCategoryId; readonly stalkerCategories = this.stalkerStore.getCategoryResource; readonly stalkerSelectedCategoryId = this.stalkerStore.selectedCategoryId; readonly isStalkerCategoryLoading = this.stalkerStore.isCategoryResourceLoading; readonly isStalkerCategoryFailed = this.stalkerStore.isCategoryResourceFailed; readonly skeletonRows = Array.from({ length: 14 }, (_, index) => index); readonly skeletonLabelWidths = [ 78, 66, 74, 59, 83, 69, 76, 62, 81, 64, 72, 67, 79, 61, ]; readonly title = computed(() => { if (this.isXtreamCategories()) { if (this.section() === 'vod') return 'Movie Categories'; if (this.section() === 'series') return 'Series Categories'; return 'Live Categories'; } if (this.isStalkerCategories()) { if (this.section() === 'vod') return 'Movie Categories'; if (this.section() === 'series') return 'Series Categories'; return 'Live Categories'; } return 'Categories'; }); readonly subtitle = computed(() => { if (this.isXtreamCategories()) { return 'Xtream source'; } if (this.isStalkerCategories()) { return 'Stalker portal'; } return ''; }); openManageCategories(): void { const context = this.context(); const section = this.section(); const contentType = section === 'series' ? 'series' : section === 'live' ? 'live' : 'vod'; const dialogRef = this.dialog.open< CategoryManagementDialogComponent, CategoryManagementDialogData, boolean >(CategoryManagementDialogComponent, { data: { playlistId: context.playlistId, contentType, itemCounts: this.xtreamStore.getCategoryItemCounts(), }, width: '500px', maxHeight: '80vh', }); dialogRef .afterClosed() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((result) => { if (result) { this.xtreamStore.reloadCategories(); } }); } onXtreamCategoryClicked(category: XtreamCategoryLike): void { const context = this.context(); const section = this.section(); const rawCategoryId = category.category_id ?? category.id; if (rawCategoryId === undefined || rawCategoryId === null) { return; } const numericCategoryId = Number(rawCategoryId); if (Number.isNaN(numericCategoryId)) { return; } const categoryId = numericCategoryId; this.xtreamStore.setSelectedItem(null); this.xtreamStore.setSelectedCategory(categoryId); if (section === 'live') { return; } this.router.navigate([ '/workspace', 'xtreams', context.playlistId, section, categoryId, ]); } onStalkerCategoryClicked(item: { category_id?: string | number }): void { const context = this.context(); const section = this.section(); const categoryId = String(item.category_id ?? '*'); this.stalkerStore.setSelectedCategory(categoryId); this.stalkerStore.setPage(0); this.stalkerStore.clearSelectedItem(); if (section === 'itv') { return; } if (categoryId === '*') { this.router.navigate([ '/workspace', 'stalker', context.playlistId, section, ]); return; } this.router.navigate([ '/workspace', 'stalker', context.playlistId, section, categoryId, ]); } }