import type { MessageData } from '$lib/types/message'; import type { Calendar, CalendarConnection } from './types'; interface RawEvent { id: string; calendar_id: string; title: string; description: string | null; starts_at: string; ends_at: string | null; all_day: boolean; color: string | null; linked_node: string | null; created_by: string | null; created_at: string; } interface RawCalendar { id: string; name: string; color: string | null; events: RawEvent[]; } function eventToMessageData(event: RawEvent): MessageData { return { id: event.id, channel_id: null, reply_to: null, author_id: event.created_by, author_name: null, message_type: 'calendar', title: event.title, body: event.description ?? '', pinned: false, visibility: 'workspace', created_at: event.created_at, updated_at: event.created_at, kanban_view: null, calendar_view: { starts_at: event.starts_at, ends_at: event.ends_at, all_day: event.all_day, color: event.color } }; } export function createPgCalendar(calendarId: string): CalendarConnection { let _calendar = $state(null); let _events = $state([]); let _error = $state(''); let _loading = $state(true); let _viewDate = $state(new Date()); let _interval: ReturnType | null = null; function getMonthRange(date: Date): { from: string; to: string } { const year = date.getFullYear(); const month = date.getMonth(); const from = new Date(year, month, -6); const to = new Date(year, month + 1, 7); return { from: from.toISOString(), to: to.toISOString() }; } async function fetchEvents() { try { const { from, to } = getMonthRange(_viewDate); const res = await fetch( `/api/calendar/${calendarId}?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}` ); if (!res.ok) { _error = `Feil: ${res.status}`; return; } const data: RawCalendar = await res.json(); const mapped = data.events.map(eventToMessageData); _calendar = { id: data.id, name: data.name, color: data.color, events: mapped }; _events = mapped; _error = ''; } catch (e) { _error = e instanceof Error ? e.message : 'Ukjent feil'; } finally { _loading = false; } } fetchEvents(); _interval = setInterval(fetchEvents, 5000); return { get calendar() { return _calendar; }, get events() { return _events; }, get error() { return _error; }, get loading() { return _loading; }, get viewDate() { return _viewDate; }, setViewDate(date: Date) { _viewDate = date; _loading = true; fetchEvents(); }, async addEvent(event) { const res = await fetch(`/api/calendar/${calendarId}/events`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event) }); if (!res.ok) { _error = `Feil: ${res.status}`; return; } await fetchEvents(); }, async updateEvent(eventId, updates) { const res = await fetch(`/api/calendar/${calendarId}/events/${eventId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates) }); if (!res.ok) { _error = `Feil: ${res.status}`; return; } await fetchEvents(); }, async deleteEvent(eventId) { const res = await fetch(`/api/calendar/${calendarId}/events/${eventId}`, { method: 'DELETE' }); if (!res.ok) { _error = `Feil: ${res.status}`; return; } await fetchEvents(); }, destroy() { if (_interval) clearInterval(_interval); } }; }