Files
gameovergne-app/client/src/app/components/ps-generic-crud/ps-admin-crud.component.ts

165 lines
5.2 KiB
TypeScript

import {CommonModule} from '@angular/common';
import {AfterViewInit, Component, inject, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {FormBuilder, ReactiveFormsModule, Validators} from '@angular/forms';
import {
MatCell,
MatCellDef,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef,
MatHeaderRow, MatHeaderRowDef, MatNoDataRow, MatRow, MatRowDef,
MatTable, MatTableDataSource
} from '@angular/material/table';
import {MatSort, MatSortModule} from '@angular/material/sort';
import {MatPaginator, MatPaginatorModule} from '@angular/material/paginator';
import {MatFormField, MatLabel} from '@angular/material/form-field';
import {MatInput} from '@angular/material/input';
import {MatButton, MatIconButton} from '@angular/material/button';
import {MatIcon} from '@angular/material/icon';
import {PrestashopService} from '../../services/prestashop.serivce';
import {debounceTime, Observable, Subject, takeUntil} from 'rxjs';
import {PsItem} from '../../interfaces/ps-item';
import {PsItemDialogComponent} from '../ps-item-dialog/ps-item-dialog.component';
import {MatDialog} from '@angular/material/dialog';
type Resource = 'categories' | 'manufacturers' | 'suppliers';
@Component({
selector: 'app-ps-admin-crud',
standalone: true,
templateUrl: './ps-admin-crud.component.html',
styleUrls: ['./ps-admin-crud.component.css'],
imports: [
CommonModule,
ReactiveFormsModule,
MatTable, MatColumnDef, MatHeaderCell, MatHeaderCellDef, MatCell, MatCellDef,
MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
MatSortModule, MatPaginatorModule,
MatFormField, MatLabel, MatInput,
MatButton, MatIconButton, MatIcon, MatNoDataRow
]
})
export class PsAdminCrudComponent implements OnInit, AfterViewInit, OnDestroy {
@Input({required: true}) resource!: Resource;
@Input({required: true}) label!: string;
private readonly fb = inject(FormBuilder);
private readonly ps = inject(PrestashopService);
private readonly dialog = inject(MatDialog);
private readonly destroy$ = new Subject<void>();
dataSource = new MatTableDataSource<PsItem>([]);
displayedColumns: string[] = ['id', 'name', 'actions'];
form = this.fb.group({name: ['', Validators.required]});
editId: number | null = null;
@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;
@ViewChild(MatTable) table!: MatTable<PsItem>;
private readonly filter$: Subject<string> = new Subject<string>();
ngOnInit(): void {
this.dataSource.filterPredicate = (row, filter) => {
const f = filter.trim().toLowerCase();
return (
String(row.id).toLowerCase().includes(f) ||
String(row.name ?? '').toLowerCase().includes(f)
);
};
this.filter$.pipe(debounceTime(150), takeUntil(this.destroy$))
.subscribe(v => {
this.dataSource.filter = (v ?? '').trim().toLowerCase();
if (this.paginator) this.paginator.firstPage();
});
this.reload();
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
reload(): void {
this.ps.list(this.resource).subscribe({
next: items => {
this.dataSource.data = items;
// rafraîchir le rendu si nécessaire
this.table?.renderRows?.();
},
error: e => alert('Erreur de chargement: ' + (e?.message || e))
});
}
createNew() {
const ref = this.dialog.open(PsItemDialogComponent, {
width: '400px',
data: {label: this.label, title: `Créer ${this.label}`}
});
ref.afterClosed().subscribe((name: string | null) => {
if (!name) return;
this.ps.create(this.resource, name).subscribe({
next: () => this.reload(),
error: e => alert('Erreur: ' + (e?.message || e))
});
});
}
startEdit(row: PsItem) {
const ref = this.dialog.open(PsItemDialogComponent, {
width: '400px',
data: {label: this.label, name: row.name, title: `Modifier ${this.label} #${row.id}`}
});
ref.afterClosed().subscribe((name: string | null) => {
if (!name) return;
this.ps.update(this.resource, row.id, name).subscribe({
next: () => this.reload(),
error: e => alert('Erreur: ' + (e?.message || e))
});
});
}
cancelEdit() {
this.editId = null;
this.form.reset({name: ''});
}
onSubmit() {
const name = (this.form.value.name ?? '').trim();
if (!name) return;
const req$: Observable<unknown> = this.editId
? this.ps.update(this.resource, this.editId, name) as Observable<unknown>
: this.ps.create(this.resource, name) as Observable<unknown>;
req$.subscribe({
next: () => {
this.cancelEdit();
this.reload();
},
error: (e: unknown) => alert('Erreur: ' + (e instanceof Error ? e.message : String(e)))
});
}
remove(row: PsItem) {
if (!confirm(`Supprimer ${this.label.toLowerCase()} "#${row.id} ${row.name} ?`)) return;
this.ps.delete(this.resource, row.id).subscribe({
next: () => this.reload(),
error: e => alert('Erreur: ' + (e?.message || e))
});
}
applyFilter(value: string) {
this.filter$.next(value);
}
}