import { error } from '@sveltejs/kit'; import type { LayoutServerLoad } from './$types'; export const load: LayoutServerLoad = async ({ params, locals }) => { const { session, user } = await locals.safeGetSession(); if (!session || !user) { error(401, 'Unauthorized'); } // Fetch org first (need org.id for subsequent queries) const { data: org, error: orgError } = await locals.supabase .from('organizations') .select('*') .eq('slug', params.orgSlug) .single(); if (orgError || !org) { error(404, 'Organization not found'); } // Now fetch membership, members, activity, and user profile in parallel (all depend on org.id) const [membershipResult, membersResult, activityResult, profileResult, docCountResult, folderCountResult, kanbanCountResult, eventCountResult] = await Promise.all([ locals.supabase .from('org_members') .select('role, role_id') .eq('org_id', org.id) .eq('user_id', user.id) .single(), locals.supabase .from('org_members') .select('id, user_id, role') .eq('org_id', org.id) .limit(10), locals.supabase .from('activity_log') .select(` id, action, entity_type, entity_id, entity_name, created_at, profiles:user_id ( full_name, email ) `) .eq('org_id', org.id) .order('created_at', { ascending: false }) .limit(10), locals.supabase .from('profiles') .select('id, email, full_name, avatar_url') .eq('id', user.id) .single(), locals.supabase .from('documents') .select('id', { count: 'exact', head: true }) .eq('org_id', org.id) .eq('type', 'document'), locals.supabase .from('documents') .select('id', { count: 'exact', head: true }) .eq('org_id', org.id) .eq('type', 'folder'), locals.supabase .from('documents') .select('id', { count: 'exact', head: true }) .eq('org_id', org.id) .eq('type', 'kanban'), locals.supabase .from('events') .select('id', { count: 'exact', head: true }) .eq('org_id', org.id) ]); const { data: membership } = membershipResult; const { data: rawMembers } = membersResult; const { data: recentActivity } = activityResult; const { data: profile } = profileResult; const stats = { memberCount: (rawMembers ?? []).length, documentCount: docCountResult.count ?? 0, folderCount: folderCountResult.count ?? 0, kanbanCount: kanbanCountResult.count ?? 0, eventCount: eventCountResult.count ?? 0, }; if (!membership) { error(403, 'You are not a member of this organization'); } // Resolve user's permissions from their custom org_role (if assigned) let userPermissions: string[] | null = null; if (membership.role_id) { const { data: roleData } = await locals.supabase .from('org_roles') .select('permissions') .eq('id', membership.role_id) .single(); if (roleData?.permissions && Array.isArray(roleData.permissions)) { userPermissions = roleData.permissions as string[]; } } // Fetch profiles separately since org_members.user_id FK points to auth.users, not profiles const memberUserIds = (rawMembers ?? []).map(m => m.user_id).filter((id): id is string => id !== null); let memberProfilesMap: Record = {}; if (memberUserIds.length > 0) { const { data: memberProfiles } = await locals.supabase .from('profiles') .select('id, email, full_name, avatar_url') .in('id', memberUserIds); if (memberProfiles) { memberProfilesMap = Object.fromEntries(memberProfiles.map(p => [p.id, p])); } } const members = (rawMembers ?? []).map(m => ({ ...m, profiles: (m.user_id ? memberProfilesMap[m.user_id] : null) ?? null })); // Fetch upcoming events for the overview const { data: upcomingEvents } = await locals.supabase .from('events') .select('id, name, slug, status, start_date, end_date, color, venue_name') .eq('org_id', org.id) .in('status', ['planning', 'active']) .order('start_date', { ascending: true, nullsFirst: false }) .limit(5); return { org, userRole: membership.role, userPermissions, members, recentActivity: recentActivity ?? [], stats, upcomingEvents: upcomingEvents ?? [], user, profile: profile ?? { id: user.id, email: user.email ?? '', full_name: null, avatar_url: null } }; };