b9ee016119
Signed-off-by: Gato <cedric@goutailler-olivier.fr>
110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import { Component, inject, signal } from '@angular/core';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { StatusEntity, StatusesStore } from './statuses.store';
|
|
|
|
type FormMode = 'create' | 'edit';
|
|
type StatusForm = { id: string; label: string; bg: string; color: string };
|
|
|
|
@Component({
|
|
selector: 'app-statuses',
|
|
imports: [FormsModule],
|
|
templateUrl: './statuses.html',
|
|
styleUrl: './statuses.css',
|
|
})
|
|
export class Statuses {
|
|
protected readonly statusesStore = inject(StatusesStore);
|
|
protected readonly statuses = this.statusesStore.statuses;
|
|
|
|
protected dragIndex: number | null = null;
|
|
protected dragOverIndex: number | null = null;
|
|
|
|
protected formMode = signal<FormMode | null>(null);
|
|
protected editingId = signal<string | null>(null);
|
|
protected form: StatusForm = this.emptyForm();
|
|
protected idError = signal<string | null>(null);
|
|
|
|
protected openCreate(): void {
|
|
this.form = this.emptyForm();
|
|
this.idError.set(null);
|
|
this.editingId.set(null);
|
|
this.formMode.set('create');
|
|
}
|
|
|
|
protected openEdit(status: StatusEntity): void {
|
|
this.form = { id: status.id, label: status.label, bg: status.bg, color: status.color };
|
|
this.idError.set(null);
|
|
this.editingId.set(status.id);
|
|
this.formMode.set('edit');
|
|
}
|
|
|
|
protected cancel(): void {
|
|
this.formMode.set(null);
|
|
this.editingId.set(null);
|
|
}
|
|
|
|
protected save(): void {
|
|
if (this.formMode() === 'create') {
|
|
const id = this.slugify(this.form.id || this.form.label);
|
|
if (!id) return;
|
|
if (this.statusesStore.getById(id)) {
|
|
this.idError.set('Un statut avec cet identifiant existe déjà.');
|
|
return;
|
|
}
|
|
this.statusesStore.create({ id, label: this.form.label.trim(), bg: this.form.bg, color: this.form.color });
|
|
} else {
|
|
const id = this.editingId();
|
|
if (!id) return;
|
|
this.statusesStore.update(id, { label: this.form.label.trim(), bg: this.form.bg, color: this.form.color });
|
|
}
|
|
this.formMode.set(null);
|
|
this.editingId.set(null);
|
|
}
|
|
|
|
protected isFormValid(): boolean {
|
|
return this.form.label.trim().length > 0;
|
|
}
|
|
|
|
protected onDragStart(index: number): void {
|
|
this.dragIndex = index;
|
|
}
|
|
|
|
protected onDragOver(event: DragEvent, index: number): void {
|
|
event.preventDefault();
|
|
this.dragOverIndex = index;
|
|
}
|
|
|
|
protected onDrop(event: DragEvent, dropIndex: number): void {
|
|
event.preventDefault();
|
|
if (this.dragIndex === null || this.dragIndex === dropIndex) {
|
|
this.dragIndex = null;
|
|
this.dragOverIndex = null;
|
|
return;
|
|
}
|
|
const newOrder = [...this.statuses()];
|
|
const [dragged] = newOrder.splice(this.dragIndex, 1);
|
|
newOrder.splice(dropIndex, 0, dragged);
|
|
this.statusesStore.setOrder(newOrder);
|
|
this.dragIndex = null;
|
|
this.dragOverIndex = null;
|
|
}
|
|
|
|
protected onDragEnd(): void {
|
|
this.dragIndex = null;
|
|
this.dragOverIndex = null;
|
|
}
|
|
|
|
private slugify(value: string): string {
|
|
return value
|
|
.trim()
|
|
.toLowerCase()
|
|
.normalize('NFD')
|
|
.replace(/[̀-ͯ]/g, '')
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '');
|
|
}
|
|
|
|
private emptyForm(): StatusForm {
|
|
return { id: '', label: '', bg: '#e2e8f0', color: '#475569' };
|
|
}
|
|
}
|