First commit

This commit is contained in:
AlacrisDevs
2026-02-04 23:01:44 +02:00
commit cfec43f7ef
78 changed files with 9509 additions and 0 deletions

215
src/lib/api/kanban.ts Normal file
View File

@@ -0,0 +1,215 @@
import type { SupabaseClient } from '@supabase/supabase-js';
import type { Database, KanbanBoard, KanbanColumn, KanbanCard } from '$lib/supabase/types';
export interface ColumnWithCards extends KanbanColumn {
cards: KanbanCard[];
}
export interface BoardWithColumns extends KanbanBoard {
columns: ColumnWithCards[];
}
export async function fetchBoards(
supabase: SupabaseClient<Database>,
orgId: string
): Promise<KanbanBoard[]> {
const { data, error } = await supabase
.from('kanban_boards')
.select('*')
.eq('org_id', orgId)
.order('created_at');
if (error) throw error;
return data ?? [];
}
export async function fetchBoardWithColumns(
supabase: SupabaseClient<Database>,
boardId: string
): Promise<BoardWithColumns | null> {
const { data: board, error: boardError } = await supabase
.from('kanban_boards')
.select('*')
.eq('id', boardId)
.single();
if (boardError) throw boardError;
if (!board) return null;
const { data: columns, error: colError } = await supabase
.from('kanban_columns')
.select('*')
.eq('board_id', boardId)
.order('position');
if (colError) throw colError;
const { data: cards, error: cardError } = await supabase
.from('kanban_cards')
.select('*')
.in('column_id', (columns ?? []).map((c) => c.id))
.order('position');
if (cardError) throw cardError;
const cardsByColumn = new Map<string, KanbanCard[]>();
(cards ?? []).forEach((card) => {
if (!cardsByColumn.has(card.column_id)) {
cardsByColumn.set(card.column_id, []);
}
cardsByColumn.get(card.column_id)!.push(card);
});
return {
...board,
columns: (columns ?? []).map((col) => ({
...col,
cards: cardsByColumn.get(col.id) ?? []
}))
};
}
export async function createBoard(
supabase: SupabaseClient<Database>,
orgId: string,
name: string
): Promise<KanbanBoard> {
const { data, error } = await supabase
.from('kanban_boards')
.insert({ org_id: orgId, name })
.select()
.single();
if (error) throw error;
// Create default columns
const defaultColumns = ['To Do', 'In Progress', 'Done'];
await supabase.from('kanban_columns').insert(
defaultColumns.map((name, index) => ({
board_id: data.id,
name,
position: index
}))
);
return data;
}
export async function updateBoard(
supabase: SupabaseClient<Database>,
id: string,
name: string
): Promise<void> {
const { error } = await supabase.from('kanban_boards').update({ name }).eq('id', id);
if (error) throw error;
}
export async function deleteBoard(
supabase: SupabaseClient<Database>,
id: string
): Promise<void> {
const { error } = await supabase.from('kanban_boards').delete().eq('id', id);
if (error) throw error;
}
export async function createColumn(
supabase: SupabaseClient<Database>,
boardId: string,
name: string,
position: number
): Promise<KanbanColumn> {
const { data, error } = await supabase
.from('kanban_columns')
.insert({ board_id: boardId, name, position })
.select()
.single();
if (error) throw error;
return data;
}
export async function updateColumn(
supabase: SupabaseClient<Database>,
id: string,
updates: Partial<Pick<KanbanColumn, 'name' | 'position' | 'color'>>
): Promise<void> {
const { error } = await supabase.from('kanban_columns').update(updates).eq('id', id);
if (error) throw error;
}
export async function deleteColumn(
supabase: SupabaseClient<Database>,
id: string
): Promise<void> {
const { error } = await supabase.from('kanban_columns').delete().eq('id', id);
if (error) throw error;
}
export async function createCard(
supabase: SupabaseClient<Database>,
columnId: string,
title: string,
position: number,
userId: string
): Promise<KanbanCard> {
const { data, error } = await supabase
.from('kanban_cards')
.insert({
column_id: columnId,
title,
position,
created_by: userId
})
.select()
.single();
if (error) throw error;
return data;
}
export async function updateCard(
supabase: SupabaseClient<Database>,
id: string,
updates: Partial<Pick<KanbanCard, 'title' | 'description' | 'column_id' | 'position' | 'due_date' | 'color'>>
): Promise<void> {
const { error } = await supabase.from('kanban_cards').update(updates).eq('id', id);
if (error) throw error;
}
export async function deleteCard(
supabase: SupabaseClient<Database>,
id: string
): Promise<void> {
const { error } = await supabase.from('kanban_cards').delete().eq('id', id);
if (error) throw error;
}
export async function moveCard(
supabase: SupabaseClient<Database>,
cardId: string,
newColumnId: string,
newPosition: number
): Promise<void> {
const { error } = await supabase
.from('kanban_cards')
.update({ column_id: newColumnId, position: newPosition })
.eq('id', cardId);
if (error) throw error;
}
export function subscribeToBoard(
supabase: SupabaseClient<Database>,
boardId: string,
onColumnChange: () => void,
onCardChange: () => void
) {
const channel = supabase.channel(`kanban:${boardId}`);
channel
.on('postgres_changes', { event: '*', schema: 'public', table: 'kanban_columns', filter: `board_id=eq.${boardId}` }, onColumnChange)
.on('postgres_changes', { event: '*', schema: 'public', table: 'kanban_cards' }, onCardChange)
.subscribe();
return channel;
}