ObsiViewer/src/app/blocks/kanban/services/kanban-board.service.ts
Bruno Charest 5e8cddf92e ```
docs: remove outdated implementation documentation files

- Deleted AI_TOOLS_IMPLEMENTATION.md (296 lines) - outdated AI tools integration guide
- Deleted ALIGN_INDENT_COLUMNS_FIX.md (557 lines) - obsolete column alignment fix documentation
- Deleted BLOCK_COMMENTS_IMPLEMENTATION.md (400 lines) - superseded block comments implementation notes
- Deleted DRAG_DROP_COLUMNS_IMPLEMENTATION.md (500 lines) - outdated drag-and-drop columns guide
- Deleted INLINE_TOOLBAR_IMPLEMENTATION.md (350 lines) - obsol
2025-11-17 10:09:25 -05:00

210 lines
5.1 KiB
TypeScript

import { Injectable, signal, computed } from '@angular/core';
import { KanbanBoard, KanbanColumn, KanbanTask } from '../models/kanban.types';
/**
* KanbanBoardService - Main state management for Kanban boards
* Angular 20 + Signals
*/
@Injectable()
export class KanbanBoardService {
// Board state
private readonly _board = signal<KanbanBoard | null>(null);
readonly board = this._board.asReadonly();
// Computed signals
readonly columns = computed(() => this._board()?.columns ?? []);
readonly tasks = computed(() => {
const cols = this.columns();
return cols.flatMap(col => col.tasks);
});
/**
* Initialize a new board with default columns
*/
initializeBoard(blockId: string): void {
const now = new Date();
const board: KanbanBoard = {
id: blockId,
title: 'Board',
columns: [
{
id: this.generateId(),
title: 'Column 1',
tasks: [],
order: 0,
boardId: blockId
},
{
id: this.generateId(),
title: 'Column 2',
tasks: [],
order: 1,
boardId: blockId
}
],
createdAt: now,
updatedAt: now
};
this._board.set(board);
}
/**
* Load board from serialized data
*/
loadBoard(data: KanbanBoard): void {
this._board.set(data);
}
/**
* Get current board state for serialization
*/
serializeBoard(): KanbanBoard | null {
return this._board();
}
/**
* Add a new column
*/
addColumn(position: 'left' | 'right', targetColumnId?: string): void {
const board = this._board();
if (!board) return;
const columns = [...board.columns];
let order = columns.length;
if (targetColumnId) {
const targetIndex = columns.findIndex(c => c.id === targetColumnId);
if (targetIndex !== -1) {
order = position === 'left' ? targetIndex : targetIndex + 1;
// Shift subsequent columns
columns.forEach(col => {
if (col.order >= order) {
col.order++;
}
});
}
}
const newColumn: KanbanColumn = {
id: this.generateId(),
title: `Column ${columns.length + 1}`,
tasks: [],
order,
boardId: board.id
};
columns.splice(order, 0, newColumn);
this._board.update(b => b ? { ...b, columns, updatedAt: new Date() } : null);
}
/**
* Rename a column
*/
renameColumn(columnId: string, newTitle: string): void {
this._board.update(board => {
if (!board) return null;
const columns = board.columns.map(col =>
col.id === columnId ? { ...col, title: newTitle } : col
);
return { ...board, columns, updatedAt: new Date() };
});
}
/**
* Delete a column
*/
deleteColumn(columnId: string): void {
this._board.update(board => {
if (!board) return null;
const columns = board.columns
.filter(col => col.id !== columnId)
.map((col, index) => ({ ...col, order: index }));
return { ...board, columns, updatedAt: new Date() };
});
}
/**
* Duplicate a column
*/
duplicateColumn(columnId: string): void {
const board = this._board();
if (!board) return;
const sourceColumn = board.columns.find(c => c.id === columnId);
if (!sourceColumn) return;
const newColumn: KanbanColumn = {
...sourceColumn,
id: this.generateId(),
title: `${sourceColumn.title} (copy)`,
order: sourceColumn.order + 1,
tasks: sourceColumn.tasks.map(task => ({
...task,
id: this.generateId(),
createdAt: new Date()
}))
};
const columns = [...board.columns];
columns.splice(newColumn.order, 0, newColumn);
// Reorder subsequent columns
columns.forEach((col, index) => {
col.order = index;
});
this._board.update(b => b ? { ...b, columns, updatedAt: new Date() } : null);
}
/**
* Complete all tasks in a column
*/
completeAllTasks(columnId: string): void {
this._board.update(board => {
if (!board) return null;
const columns = board.columns.map(col => {
if (col.id !== columnId) return col;
const tasks = col.tasks.map(task => ({ ...task, completed: true }));
return { ...col, tasks };
});
return { ...board, columns, updatedAt: new Date() };
});
}
/**
* Reorder columns (after drag & drop)
*/
reorderColumns(sourceIndex: number, targetIndex: number): void {
this._board.update(board => {
if (!board) return null;
const columns = [...board.columns];
const [movedColumn] = columns.splice(sourceIndex, 1);
columns.splice(targetIndex, 0, movedColumn);
// Update orders
columns.forEach((col, index) => {
col.order = index;
});
return { ...board, columns, updatedAt: new Date() };
});
}
/**
* Generate unique ID
*/
private generateId(): string {
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
}