import { DecimalPipe } from '@angular/common';
import { CommonModule, DecimalPipe } from '@angular/common';
import { Component, inject, viewChildren } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { supportTicket } from '../../../../shared/data/data/support-ticket';
import {
SortEvent,
SupportTicketDirective,
} from '../../../../shared/directive/support-ticket.directive';
import { SupportTicketService } from '../../../../shared/services/support-ticket.service';
@Component({
selector: 'app-data-table',
imports: [CommonModule, NgbModule, FormsModule, SupportTicketDirective],
templateUrl: './data-table.html',
styleUrl: './data-table.scss',
providers: [SupportTicketService, DecimalPipe],
})
export class DataTable {
service = inject(SupportTicketService);
supportTicket$: Observable;
total$: Observable;
readonly headers = viewChildren(SupportTicketDirective);
constructor() {
const service = this.service;
this.supportTicket$ = service.supportTicket$;
this.total$ = service.total$;
}
onSort({ column, direction }: SortEvent) {
// resetting other headers
this.headers().forEach(header => {
if (header.appSupportTicket() !== column) {
header.currentDirection.set('');
}
});
this.service.sortColumn = column;
this.service.sortDirection = direction;
}
}
import { Injectable, PipeTransform } from '@angular/core';
import { DecimalPipe } from '@angular/common';
import { Injectable, PipeTransform, inject } from '@angular/core';
import {
BehaviorSubject,
Observable,
Subject,
debounceTime,
delay,
of,
switchMap,
tap,
} from 'rxjs';
import { supportTicket, supportTicketTable } from '../data/data/support-ticket';
import { SortColumn, SortDirection } from '../directive/support-ticket.directive';
interface SearchResult {
supportTicket: supportTicket[];
total: number;
}
interface State {
page: number;
pageSize: number;
searchTerm: string;
sortColumn: SortColumn;
sortDirection: SortDirection;
}
const compare = (v1: string | number, v2: string | number) => (v1 < v2 ? -1 : v1 > v2 ? 1 : 0);
function sort(
supportTicket: supportTicket[],
column: SortColumn,
direction: string,
): supportTicket[] {
if (direction === '' || column === '') {
return supportTicket;
} else {
return [...supportTicket].sort((a, b) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
function matches(ticket: supportTicket, term: string, pipe: PipeTransform) {
return (
ticket.name.toLowerCase().includes(term.toLowerCase()) ||
ticket.position.toLowerCase().includes(term.toLowerCase()) ||
ticket.office.toLowerCase().includes(term.toLowerCase()) ||
pipe.transform(ticket.salary).includes(term) ||
pipe.transform(ticket.progress).includes(term) ||
pipe.transform(ticket.extn).includes(term) ||
ticket.email.toLowerCase().includes(term.toLowerCase())
);
}
@Injectable({
providedIn: 'root',
})
export class SupportTicketService {
private pipe = inject(DecimalPipe);
private _loading$ = new BehaviorSubject(true);
private _search$ = new Subject();
private _supportTicket$ = new BehaviorSubject([]);
private _total$ = new BehaviorSubject(0);
private _state: State = {
page: 1,
pageSize: 10,
searchTerm: '',
sortColumn: '',
sortDirection: 'asc',
};
constructor() {
this._search$
.pipe(
tap(() => this._loading$.next(true)),
debounceTime(200),
switchMap(() => this._search()),
delay(200),
tap(() => this._loading$.next(false)),
)
.subscribe(result => {
this._supportTicket$.next(result.supportTicket);
this._total$.next(result.total);
});
this._search$.next();
}
get supportTicket$() {
return this._supportTicket$.asObservable();
}
get total$() {
return this._total$.asObservable();
}
get loading$() {
return this._loading$.asObservable();
}
get page() {
return this._state.page;
}
get pageSize() {
return this._state.pageSize;
}
get searchTerm() {
return this._state.searchTerm;
}
get sortColumn() {
return this._state.sortColumn;
}
get sortDirection() {
return this._state.sortDirection;
}
set page(page: number) {
this._set({ page });
}
set pageSize(pageSize: number) {
this._set({ pageSize });
}
set searchTerm(searchTerm: string) {
this._set({ searchTerm });
}
set sortColumn(sortColumn: SortColumn) {
this._set({ sortColumn });
}
set sortDirection(sortDirection: SortDirection) {
this._set({ sortDirection });
}
private _set(patch: Partial) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable {
const { sortColumn, sortDirection, pageSize, page, searchTerm } = this._state;
// 1. sort
let supportTicket = sort(supportTicketTable, sortColumn, sortDirection);
// 2. filter
supportTicket = supportTicket.filter(order => matches(order, searchTerm, this.pipe));
const total = supportTicket.length;
// 3. paginate
supportTicket = supportTicket.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ supportTicket, total });
}
}
import { Directive, HostBinding, HostListener, input, output, signal } from '@angular/core';
import { supportTicket } from '../data/data/support-ticket';
export type SortColumn = keyof supportTicket | '';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = { asc: 'desc', desc: '', '': 'asc' };
export interface SortEvent {
column: SortColumn;
direction: SortDirection;
}
@Directive({
selector: '[appSupportTicket]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()',
},
})
export class SupportTicketDirective {
readonly appSupportTicket = input('');
readonly direction = input(''); // Initial direction
// Local writable signal
public currentDirection = signal(this.direction());
// Output event
readonly sort = output();
// HostBinding for CSS classes
@HostBinding('class.asc')
get isAsc() {
return this.currentDirection() === 'asc';
}
@HostBinding('class.desc')
get isDesc() {
return this.currentDirection() === 'desc';
}
// Handle click
@HostListener('click')
rotate() {
this.currentDirection.set(rotate[this.currentDirection()]);
this.sort.emit({ column: this.appSupportTicket(), direction: this.currentDirection() });
}
}