First commit
This commit is contained in:
215
src/lib/api/kanban.ts
Normal file
215
src/lib/api/kanban.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user