282 lines
7.4 KiB
TypeScript
282 lines
7.4 KiB
TypeScript
import { Component, inject, signal, OnInit } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { Router } from '@angular/router';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { NzTableModule, NzTableFilterList } from 'ng-zorro-antd/table';
|
|
import { NzButtonModule } from 'ng-zorro-antd/button';
|
|
import { NzInputModule } from 'ng-zorro-antd/input';
|
|
import { NzTagModule } from 'ng-zorro-antd/tag';
|
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
import { NzEmptyModule } from 'ng-zorro-antd/empty';
|
|
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
|
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
|
|
import { NzPaginationModule } from 'ng-zorro-antd/pagination';
|
|
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
|
|
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
|
|
import { ApiService } from '../../../core/services/api.service';
|
|
import { AuthService } from '../../../core/services/auth.service';
|
|
import { Message, MessageListParams } from '../../../core/models';
|
|
import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe';
|
|
|
|
@Component({
|
|
selector: 'app-message-list',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
FormsModule,
|
|
NzTableModule,
|
|
NzButtonModule,
|
|
NzInputModule,
|
|
NzTagModule,
|
|
NzIconModule,
|
|
NzEmptyModule,
|
|
NzSpinModule,
|
|
NzToolTipModule,
|
|
NzPaginationModule,
|
|
NzDatePickerModule,
|
|
NzDropDownModule,
|
|
RelativeTimePipe,
|
|
],
|
|
templateUrl: './message-list.component.html',
|
|
styleUrl: './message-list.component.scss'
|
|
})
|
|
export class MessageListComponent implements OnInit {
|
|
private apiService = inject(ApiService);
|
|
private authService = inject(AuthService);
|
|
private router = inject(Router);
|
|
|
|
messages = signal<Message[]>([]);
|
|
loading = signal(false);
|
|
|
|
// Pagination
|
|
currentPage = signal(1);
|
|
pageSize = 50;
|
|
totalCount = signal(0);
|
|
|
|
// Filters
|
|
searchText = '';
|
|
appliedSearchText = '';
|
|
priorityFilter: string[] = [];
|
|
channelFilter: string[] = [];
|
|
senderFilter: string[] = [];
|
|
dateRange: [Date, Date] | null = null;
|
|
dateFilterVisible = false;
|
|
|
|
// Filter options
|
|
priorityFilters: NzTableFilterList = [
|
|
{ text: 'Low', value: '0' },
|
|
{ text: 'Normal', value: '1' },
|
|
{ text: 'High', value: '2' },
|
|
];
|
|
channelFilters = signal<NzTableFilterList>([]);
|
|
senderFilters = signal<NzTableFilterList>([]);
|
|
|
|
ngOnInit(): void {
|
|
this.loadChannels();
|
|
this.loadSenders();
|
|
this.loadMessages();
|
|
}
|
|
|
|
loadChannels(): void {
|
|
const userId = this.authService.getUserId();
|
|
if (!userId) return;
|
|
|
|
this.apiService.getChannels(userId, 'all_any').subscribe({
|
|
next: (response) => {
|
|
this.channelFilters.set(
|
|
response.channels.map(ch => ({
|
|
text: ch.display_name,
|
|
value: ch.channel_id,
|
|
}))
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadSenders(): void {
|
|
this.apiService.getSenderNames().subscribe({
|
|
next: (response) => {
|
|
this.senderFilters.set(
|
|
response.sender_names.map(s => ({
|
|
text: s.name,
|
|
value: s.name,
|
|
}))
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadMessages(): void {
|
|
this.loading.set(true);
|
|
|
|
const params: MessageListParams = {
|
|
page_size: this.pageSize,
|
|
trimmed: true,
|
|
};
|
|
|
|
if (this.appliedSearchText) {
|
|
params.search = this.appliedSearchText;
|
|
}
|
|
if (this.priorityFilter.length > 0) {
|
|
params.priority = this.priorityFilter.map(p => parseInt(p, 10));
|
|
}
|
|
if (this.channelFilter.length > 0) {
|
|
params.channel_id = this.channelFilter;
|
|
}
|
|
if (this.senderFilter.length > 0) {
|
|
params.sender = this.senderFilter;
|
|
}
|
|
if (this.dateRange) {
|
|
params.after = this.dateRange[0].toISOString();
|
|
params.before = this.dateRange[1].toISOString();
|
|
}
|
|
|
|
// Use page-index based pagination: $1 = page 1, $2 = page 2, etc.
|
|
const page = this.currentPage();
|
|
if (page > 1) {
|
|
params.next_page_token = `$${page}`;
|
|
}
|
|
|
|
this.apiService.getMessages(params).subscribe({
|
|
next: (response) => {
|
|
this.messages.set(response.messages);
|
|
this.totalCount.set(response.total_count);
|
|
this.loading.set(false);
|
|
},
|
|
error: () => {
|
|
this.loading.set(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
applyFilters(): void {
|
|
this.appliedSearchText = this.searchText;
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
onPriorityFilterChange(filters: string[] | null): void {
|
|
this.priorityFilter = filters ?? [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
onChannelFilterChange(filters: string[] | null): void {
|
|
this.channelFilter = filters ?? [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
onSenderFilterChange(filters: string[] | null): void {
|
|
this.senderFilter = filters ?? [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearSearch(): void {
|
|
this.searchText = '';
|
|
this.appliedSearchText = '';
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearChannelFilter(): void {
|
|
this.channelFilter = [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
removeChannelFilter(channel: string): void {
|
|
this.channelFilter = this.channelFilter.filter(c => c !== channel);
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearSenderFilter(): void {
|
|
this.senderFilter = [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
removeSenderFilter(sender: string): void {
|
|
this.senderFilter = this.senderFilter.filter(s => s !== sender);
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearPriorityFilter(): void {
|
|
this.priorityFilter = [];
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
onDateRangeChange(dates: [Date, Date] | null): void {
|
|
this.dateRange = dates;
|
|
if (dates) {
|
|
this.dateFilterVisible = false;
|
|
}
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearDateRange(): void {
|
|
this.dateRange = null;
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
clearAllFilters(): void {
|
|
this.searchText = '';
|
|
this.appliedSearchText = '';
|
|
this.channelFilter = [];
|
|
this.senderFilter = [];
|
|
this.priorityFilter = [];
|
|
this.dateRange = null;
|
|
this.currentPage.set(1);
|
|
this.loadMessages();
|
|
}
|
|
|
|
hasActiveFilters(): boolean {
|
|
return !!this.appliedSearchText || this.channelFilter.length > 0 || this.senderFilter.length > 0 || this.priorityFilter.length > 0 || !!this.dateRange;
|
|
}
|
|
|
|
getChannelDisplayName(channelId: string): string {
|
|
const filters = this.channelFilters();
|
|
const channel = filters.find(f => f.value === channelId);
|
|
return channel?.text?.toString() ?? channelId;
|
|
}
|
|
|
|
getDateRangeDisplay(): string {
|
|
if (!this.dateRange) return '';
|
|
const format = (d: Date) => d.toLocaleDateString();
|
|
return `${format(this.dateRange[0])} - ${format(this.dateRange[1])}`;
|
|
}
|
|
|
|
goToPage(page: number): void {
|
|
this.currentPage.set(page);
|
|
this.loadMessages();
|
|
}
|
|
|
|
viewMessage(message: Message): void {
|
|
this.router.navigate(['/messages', message.message_id]);
|
|
}
|
|
|
|
getPriorityLabel(priority: number): string {
|
|
switch (priority) {
|
|
case 0: return 'Low';
|
|
case 1: return 'Normal';
|
|
case 2: return 'High';
|
|
default: return 'Unknown';
|
|
}
|
|
}
|
|
|
|
getPriorityColor(priority: number): string {
|
|
switch (priority) {
|
|
case 0: return 'default';
|
|
case 1: return 'blue';
|
|
case 2: return 'red';
|
|
default: return 'default';
|
|
}
|
|
}
|
|
}
|