Files
root-org/src/lib/api/department-dashboard.ts
2026-02-07 21:47:47 +02:00

355 lines
9.3 KiB
TypeScript

import type { SupabaseClient } from '@supabase/supabase-js';
import type { Database, DepartmentDashboard, DashboardPanel, DepartmentChecklist, DepartmentChecklistItem, DepartmentNote, ModuleType, LayoutPreset } from '$lib/supabase/types';
import { createLogger } from '$lib/utils/logger';
const log = createLogger('api.department-dashboard');
// ============================================================
// Dashboard
// ============================================================
export interface DashboardWithPanels extends DepartmentDashboard {
panels: DashboardPanel[];
}
export async function fetchDashboard(
supabase: SupabaseClient<Database>,
departmentId: string
): Promise<DashboardWithPanels | null> {
const { data, error } = await supabase
.from('department_dashboards')
.select('*, panels:dashboard_panels(*)')
.eq('department_id', departmentId)
.single();
if (error) {
if (error.code === 'PGRST116') return null;
log.error('fetchDashboard failed', { error, data: { departmentId } });
throw error;
}
const dashboard = data as any;
return {
...dashboard,
panels: (dashboard.panels ?? []).sort((a: DashboardPanel, b: DashboardPanel) => a.position - b.position),
};
}
export async function updateDashboardLayout(
supabase: SupabaseClient<Database>,
dashboardId: string,
layout: LayoutPreset
): Promise<DepartmentDashboard> {
const { data, error } = await supabase
.from('department_dashboards')
.update({ layout, updated_at: new Date().toISOString() })
.eq('id', dashboardId)
.select()
.single();
if (error) {
log.error('updateDashboardLayout failed', { error, data: { dashboardId, layout } });
throw error;
}
return data as unknown as DepartmentDashboard;
}
// ============================================================
// Panels
// ============================================================
export async function addPanel(
supabase: SupabaseClient<Database>,
dashboardId: string,
module: ModuleType,
position: number,
width: string = 'half'
): Promise<DashboardPanel> {
const { data, error } = await supabase
.from('dashboard_panels')
.insert({ dashboard_id: dashboardId, module, position, width })
.select()
.single();
if (error) {
log.error('addPanel failed', { error, data: { dashboardId, module } });
throw error;
}
return data as unknown as DashboardPanel;
}
export async function updatePanel(
supabase: SupabaseClient<Database>,
panelId: string,
params: Partial<Pick<DashboardPanel, 'position' | 'width' | 'config'>>
): Promise<DashboardPanel> {
const { data, error } = await supabase
.from('dashboard_panels')
.update(params)
.eq('id', panelId)
.select()
.single();
if (error) {
log.error('updatePanel failed', { error, data: { panelId } });
throw error;
}
return data as unknown as DashboardPanel;
}
export async function removePanel(
supabase: SupabaseClient<Database>,
panelId: string
): Promise<void> {
const { error } = await supabase
.from('dashboard_panels')
.delete()
.eq('id', panelId);
if (error) {
log.error('removePanel failed', { error, data: { panelId } });
throw error;
}
}
// ============================================================
// Checklists
// ============================================================
export interface ChecklistWithItems extends DepartmentChecklist {
items: DepartmentChecklistItem[];
}
export async function fetchChecklists(
supabase: SupabaseClient<Database>,
departmentId: string
): Promise<ChecklistWithItems[]> {
const { data: checklists, error } = await supabase
.from('department_checklists')
.select('*')
.eq('department_id', departmentId)
.order('sort_order');
if (error) {
log.error('fetchChecklists failed', { error, data: { departmentId } });
throw error;
}
if (!checklists || checklists.length === 0) return [];
const checklistIds = checklists.map(c => c.id);
const { data: items, error: itemsError } = await supabase
.from('department_checklist_items')
.select('*')
.in('checklist_id', checklistIds)
.order('sort_order');
if (itemsError) {
log.error('fetchChecklistItems failed', { error: itemsError });
throw itemsError;
}
const itemsByChecklist: Record<string, DepartmentChecklistItem[]> = {};
for (const item of (items ?? [])) {
if (!itemsByChecklist[item.checklist_id]) itemsByChecklist[item.checklist_id] = [];
itemsByChecklist[item.checklist_id].push(item as unknown as DepartmentChecklistItem);
}
return checklists.map(c => ({
...(c as unknown as DepartmentChecklist),
items: itemsByChecklist[c.id] ?? [],
}));
}
export async function createChecklist(
supabase: SupabaseClient<Database>,
departmentId: string,
title: string,
userId?: string
): Promise<DepartmentChecklist> {
const { data, error } = await supabase
.from('department_checklists')
.insert({ department_id: departmentId, title, created_by: userId ?? null })
.select()
.single();
if (error) {
log.error('createChecklist failed', { error, data: { departmentId, title } });
throw error;
}
return data as unknown as DepartmentChecklist;
}
export async function deleteChecklist(
supabase: SupabaseClient<Database>,
checklistId: string
): Promise<void> {
const { error } = await supabase
.from('department_checklists')
.delete()
.eq('id', checklistId);
if (error) {
log.error('deleteChecklist failed', { error, data: { checklistId } });
throw error;
}
}
export async function renameChecklist(
supabase: SupabaseClient<Database>,
checklistId: string,
title: string
): Promise<DepartmentChecklist> {
const { data, error } = await supabase
.from('department_checklists')
.update({ title })
.eq('id', checklistId)
.select()
.single();
if (error) {
log.error('renameChecklist failed', { error, data: { checklistId, title } });
throw error;
}
return data as unknown as DepartmentChecklist;
}
// ============================================================
// Checklist Items
// ============================================================
export async function addChecklistItem(
supabase: SupabaseClient<Database>,
checklistId: string,
content: string,
sortOrder: number = 0
): Promise<DepartmentChecklistItem> {
const { data, error } = await supabase
.from('department_checklist_items')
.insert({ checklist_id: checklistId, content, sort_order: sortOrder })
.select()
.single();
if (error) {
log.error('addChecklistItem failed', { error, data: { checklistId, content } });
throw error;
}
return data as unknown as DepartmentChecklistItem;
}
export async function updateChecklistItem(
supabase: SupabaseClient<Database>,
itemId: string,
params: Partial<Pick<DepartmentChecklistItem, 'content' | 'is_completed' | 'assigned_to' | 'due_date' | 'sort_order'>>
): Promise<DepartmentChecklistItem> {
const { data, error } = await supabase
.from('department_checklist_items')
.update({ ...params, updated_at: new Date().toISOString() })
.eq('id', itemId)
.select()
.single();
if (error) {
log.error('updateChecklistItem failed', { error, data: { itemId } });
throw error;
}
return data as unknown as DepartmentChecklistItem;
}
export async function deleteChecklistItem(
supabase: SupabaseClient<Database>,
itemId: string
): Promise<void> {
const { error } = await supabase
.from('department_checklist_items')
.delete()
.eq('id', itemId);
if (error) {
log.error('deleteChecklistItem failed', { error, data: { itemId } });
throw error;
}
}
export async function toggleChecklistItem(
supabase: SupabaseClient<Database>,
itemId: string,
isCompleted: boolean
): Promise<DepartmentChecklistItem> {
return updateChecklistItem(supabase, itemId, { is_completed: isCompleted });
}
// ============================================================
// Notes
// ============================================================
export async function fetchNotes(
supabase: SupabaseClient<Database>,
departmentId: string
): Promise<DepartmentNote[]> {
const { data, error } = await supabase
.from('department_notes')
.select('*')
.eq('department_id', departmentId)
.order('sort_order');
if (error) {
log.error('fetchNotes failed', { error, data: { departmentId } });
throw error;
}
return (data ?? []) as unknown as DepartmentNote[];
}
export async function createNote(
supabase: SupabaseClient<Database>,
departmentId: string,
title: string,
userId?: string
): Promise<DepartmentNote> {
const { data, error } = await supabase
.from('department_notes')
.insert({ department_id: departmentId, title, created_by: userId ?? null })
.select()
.single();
if (error) {
log.error('createNote failed', { error, data: { departmentId, title } });
throw error;
}
return data as unknown as DepartmentNote;
}
export async function updateNote(
supabase: SupabaseClient<Database>,
noteId: string,
params: Partial<Pick<DepartmentNote, 'title' | 'content' | 'sort_order'>>
): Promise<DepartmentNote> {
const { data, error } = await supabase
.from('department_notes')
.update({ ...params, updated_at: new Date().toISOString() })
.eq('id', noteId)
.select()
.single();
if (error) {
log.error('updateNote failed', { error, data: { noteId } });
throw error;
}
return data as unknown as DepartmentNote;
}
export async function deleteNote(
supabase: SupabaseClient<Database>,
noteId: string
): Promise<void> {
const { error } = await supabase
.from('department_notes')
.delete()
.eq('id', noteId);
if (error) {
log.error('deleteNote failed', { error, data: { noteId } });
throw error;
}
}