import { Component, inject, signal, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { NzTableModule } from 'ng-zorro-antd/table'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzIconModule } from 'ng-zorro-antd/icon'; import { NzTagModule } from 'ng-zorro-antd/tag'; import { NzEmptyModule } from 'ng-zorro-antd/empty'; import { NzCardModule } from 'ng-zorro-antd/card'; import { NzTabsModule } from 'ng-zorro-antd/tabs'; import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; import { NzModalModule } from 'ng-zorro-antd/modal'; import { NzFormModule } from 'ng-zorro-antd/form'; import { NzInputModule } from 'ng-zorro-antd/input'; import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { NzAlertModule } from 'ng-zorro-antd/alert'; import { ApiService } from '../../../core/services/api.service'; import { AuthService } from '../../../core/services/auth.service'; import { NotificationService } from '../../../core/services/notification.service'; import { UserCacheService, ResolvedUser } from '../../../core/services/user-cache.service'; import { Subscription, SubscriptionFilter } from '../../../core/models'; import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe'; type SubscriptionTab = 'all' | 'own' | 'deactivated' | 'external' | 'incoming'; interface TabConfig { filter: SubscriptionFilter; } const TAB_CONFIGS: Record = { all: { filter: {} }, own: { filter: { direction: 'outgoing', confirmation: 'confirmed', external: 'false' } }, deactivated: { filter: { direction: 'outgoing', confirmation: 'unconfirmed', external: 'false' } }, external: { filter: { direction: 'outgoing', confirmation: 'all', external: 'true' } }, incoming: { filter: { direction: 'incoming', confirmation: 'all', external: 'true' } }, }; @Component({ selector: 'app-subscription-list', standalone: true, imports: [ CommonModule, FormsModule, NzTableModule, NzButtonModule, NzIconModule, NzTagModule, NzEmptyModule, NzCardModule, NzTabsModule, NzPopconfirmModule, NzModalModule, NzFormModule, NzInputModule, NzToolTipModule, NzAlertModule, RelativeTimePipe, ], templateUrl: './subscription-list.component.html', styleUrl: './subscription-list.component.scss' }) export class SubscriptionListComponent implements OnInit { private apiService = inject(ApiService); private authService = inject(AuthService); private notification = inject(NotificationService); private userCacheService = inject(UserCacheService); subscriptions = signal([]); userNames = signal>(new Map()); loading = signal(false); activeTab: SubscriptionTab = 'all'; // Create subscription modal showCreateModal = signal(false); newChannelOwner = ''; newChannelName = ''; creating = signal(false); ngOnInit(): void { this.loadSubscriptions(); } loadSubscriptions(): void { const userId = this.authService.getUserId(); if (!userId) return; this.loading.set(true); const filter = TAB_CONFIGS[this.activeTab].filter; this.apiService.getSubscriptions(userId, filter).subscribe({ next: (response) => { this.subscriptions.set(response.subscriptions); this.loading.set(false); this.resolveUserNames(response.subscriptions); }, error: () => { this.loading.set(false); } }); } private resolveUserNames(subscriptions: Subscription[]): void { const userIds = new Set(); for (const sub of subscriptions) { userIds.add(sub.subscriber_user_id); userIds.add(sub.channel_owner_user_id); } for (const id of userIds) { this.userCacheService.resolveUser(id).subscribe(resolved => { this.userNames.update(map => new Map(map).set(id, resolved)); }); } } getUserDisplayName(userId: string): string { const resolved = this.userNames().get(userId); return resolved?.displayName || userId; } onTabChange(index: number): void { const tabs: SubscriptionTab[] = ['all', 'own', 'deactivated', 'external', 'incoming']; this.activeTab = tabs[index]; this.loadSubscriptions(); } isOutgoing(sub: Subscription): boolean { const userId = this.authService.getUserId(); return sub.subscriber_user_id === userId; } isOwner(sub: Subscription): boolean { const userId = this.authService.getUserId(); return sub.channel_owner_user_id === userId; } // Actions acceptSubscription(sub: Subscription): void { const userId = this.authService.getUserId(); if (!userId) return; this.apiService.confirmSubscription(userId, sub.subscription_id, { confirmed: true }).subscribe({ next: () => { this.notification.success('Subscription accepted'); this.loadSubscriptions(); } }); } denySubscription(sub: Subscription): void { const userId = this.authService.getUserId(); if (!userId) return; this.apiService.deleteSubscription(userId, sub.subscription_id).subscribe({ next: () => { this.notification.success('Subscription denied'); this.loadSubscriptions(); } }); } revokeSubscription(sub: Subscription): void { const userId = this.authService.getUserId(); if (!userId) return; this.apiService.deleteSubscription(userId, sub.subscription_id).subscribe({ next: () => { this.notification.success('Subscription revoked'); this.loadSubscriptions(); } }); } // Create subscription openCreateModal(): void { this.newChannelOwner = ''; this.newChannelName = ''; this.showCreateModal.set(true); } closeCreateModal(): void { this.showCreateModal.set(false); } createSubscription(): void { const userId = this.authService.getUserId(); if (!userId || !this.newChannelOwner.trim() || !this.newChannelName.trim()) return; this.creating.set(true); this.apiService.createSubscription(userId, { channel_owner_user_id: this.newChannelOwner.trim(), channel_internal_name: this.newChannelName.trim() }).subscribe({ next: () => { this.notification.success('Subscription request sent'); this.closeCreateModal(); this.creating.set(false); this.loadSubscriptions(); }, error: () => { this.creating.set(false); } }); } getStatusInfo(sub: Subscription): { label: string; color: string } { if (sub.confirmed) { return { label: 'Confirmed', color: 'green' }; } return { label: 'Pending', color: 'orange' }; } getTypeLabel(sub: Subscription): { label: string; color: string } { const userId = this.authService.getUserId(); if (sub.subscriber_user_id === sub.channel_owner_user_id) { return { label: 'Own', color: 'green' }; } if (sub.subscriber_user_id === userId) { return { label: 'External', color: 'blue' }; } return { label: 'Incoming', color: 'purple' }; } getTabDescription(): string | null { switch (this.activeTab) { case 'own': return 'Active subscriptions to your channels.'; case 'deactivated': return 'Deactivated subscriptions to your channels. These can be reactivated by you.'; case 'external': return 'Your subscriptions to channels owned by other users.'; case 'incoming': return 'Subscription from other users to your channels.'; default: return null; } } }