180 lines
5.7 KiB
TypeScript
180 lines
5.7 KiB
TypeScript
import { Component, inject, signal, computed, OnInit } from '@angular/core';
|
|
import { CommonModule, DatePipe } from '@angular/common';
|
|
import { Router, RouterLink } from '@angular/router';
|
|
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 { NzBadgeModule } from 'ng-zorro-antd/badge';
|
|
import { NzEmptyModule } from 'ng-zorro-antd/empty';
|
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
|
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
|
|
import { NzTabsModule } from 'ng-zorro-antd/tabs';
|
|
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 { SettingsService } from '../../../core/services/settings.service';
|
|
import { UserCacheService, ResolvedUser } from '../../../core/services/user-cache.service';
|
|
import { ChannelWithSubscription } from '../../../core/models';
|
|
import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe';
|
|
import { ChannelSubscribersComponent } from '../channel-subscribers/channel-subscribers.component';
|
|
|
|
type ChannelTab = 'all' | 'owned' | 'foreign';
|
|
|
|
@Component({
|
|
selector: 'app-channel-list',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
DatePipe,
|
|
RouterLink,
|
|
NzTableModule,
|
|
NzButtonModule,
|
|
NzIconModule,
|
|
NzTagModule,
|
|
NzBadgeModule,
|
|
NzEmptyModule,
|
|
NzCardModule,
|
|
NzToolTipModule,
|
|
NzTabsModule,
|
|
NzAlertModule,
|
|
RelativeTimePipe,
|
|
ChannelSubscribersComponent,
|
|
],
|
|
templateUrl: './channel-list.component.html',
|
|
styleUrl: './channel-list.component.scss'
|
|
})
|
|
export class ChannelListComponent implements OnInit {
|
|
private apiService = inject(ApiService);
|
|
private authService = inject(AuthService);
|
|
private notification = inject(NotificationService);
|
|
private settingsService = inject(SettingsService);
|
|
private userCacheService = inject(UserCacheService);
|
|
private router = inject(Router);
|
|
|
|
allChannels = signal<ChannelWithSubscription[]>([]);
|
|
ownerNames = signal<Map<string, ResolvedUser>>(new Map());
|
|
loading = signal(false);
|
|
expertMode = this.settingsService.expertMode;
|
|
activeTab = signal<ChannelTab>('all');
|
|
|
|
channels = computed(() => {
|
|
const userId = this.authService.getUserId();
|
|
const all = this.allChannels();
|
|
const tab = this.activeTab();
|
|
|
|
switch (tab) {
|
|
case 'owned':
|
|
return all.filter(c => c.owner_user_id === userId);
|
|
case 'foreign':
|
|
return all.filter(c => c.owner_user_id !== userId);
|
|
default:
|
|
return all;
|
|
}
|
|
});
|
|
|
|
ngOnInit(): void {
|
|
this.loadChannels();
|
|
}
|
|
|
|
loadChannels(): void {
|
|
const userId = this.authService.getUserId();
|
|
if (!userId) return;
|
|
|
|
this.loading.set(true);
|
|
this.apiService.getChannels(userId, 'all_any').subscribe({
|
|
next: (response) => {
|
|
this.allChannels.set(response.channels);
|
|
this.loading.set(false);
|
|
this.resolveOwnerNames(response.channels);
|
|
},
|
|
error: () => {
|
|
this.loading.set(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
onTabChange(index: number): void {
|
|
const tabs: ChannelTab[] = ['all', 'owned', 'foreign'];
|
|
this.activeTab.set(tabs[index]);
|
|
}
|
|
|
|
getTabDescription(): string | null {
|
|
switch (this.activeTab()) {
|
|
case 'owned':
|
|
return 'Channels that you own and can configure.';
|
|
case 'foreign':
|
|
return 'Channels owned by other users that you are subscribed to.';
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private resolveOwnerNames(channels: ChannelWithSubscription[]): void {
|
|
const uniqueOwnerIds = [...new Set(channels.map(c => c.owner_user_id))];
|
|
for (const ownerId of uniqueOwnerIds) {
|
|
this.userCacheService.resolveUser(ownerId).subscribe(resolved => {
|
|
this.ownerNames.update(map => new Map(map).set(ownerId, resolved));
|
|
});
|
|
}
|
|
}
|
|
|
|
getOwnerDisplayName(ownerId: string): string {
|
|
const resolved = this.ownerNames().get(ownerId);
|
|
return resolved?.displayName || ownerId;
|
|
}
|
|
|
|
isOwned(channel: ChannelWithSubscription): boolean {
|
|
return channel.owner_user_id === this.authService.getUserId();
|
|
}
|
|
|
|
viewChannel(channel: ChannelWithSubscription): void {
|
|
this.router.navigate(['/channels', channel.channel_id]);
|
|
}
|
|
|
|
getSubscriptionStatus(channel: ChannelWithSubscription): { label: string; color: string } {
|
|
const userId = this.authService.getUserId();
|
|
|
|
if (channel.owner_user_id === userId) {
|
|
if (channel.subscription) {
|
|
return { label: 'Owned & Subscribed', color: 'green' };
|
|
}
|
|
return { label: 'Owned', color: 'blue' };
|
|
}
|
|
|
|
if (channel.subscription) {
|
|
if (channel.subscription.confirmed) {
|
|
return { label: 'Subscribed', color: 'green' };
|
|
}
|
|
return { label: 'Pending', color: 'orange' };
|
|
}
|
|
|
|
return { label: 'Not Subscribed', color: 'default' };
|
|
}
|
|
|
|
toggleSelfSubscription(channel: ChannelWithSubscription, event: Event): void {
|
|
event.stopPropagation();
|
|
const userId = this.authService.getUserId();
|
|
if (!userId) return;
|
|
|
|
if (channel.subscription) {
|
|
// Unsubscribe
|
|
this.apiService.deleteSubscription(userId, channel.subscription.subscription_id).subscribe({
|
|
next: () => {
|
|
this.notification.success('Unsubscribed from channel');
|
|
this.loadChannels();
|
|
}
|
|
});
|
|
} else {
|
|
// Subscribe
|
|
this.apiService.createSubscription(userId, { channel_id: channel.channel_id }).subscribe({
|
|
next: () => {
|
|
this.notification.success('Subscribed to channel');
|
|
this.loadChannels();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|