Ordre des status

Signed-off-by: Gato <cedric@goutailler-olivier.fr>
This commit is contained in:
2026-05-28 20:58:40 +02:00
parent 3450066c6f
commit b9ee016119
15 changed files with 667 additions and 24 deletions
+109
View File
@@ -0,0 +1,109 @@
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' };
}
}