'use server'; import { createServerClient } from '@/utils/supabase'; import type { Profile, Result } from '@/utils/supabase'; import { getUser, getProfileWithAvatar, getSignedUrl } from '@/lib/actions'; export type UserWithStatus = { id?: string; user: Profile; status: string; created_at: string; updated_by?: Profile; }; type PaginatedHistory = { statuses: UserWithStatus[]; meta: { current_page: number; per_page: number; total_pages: number; total_count: number; }; }; export const getRecentUsersWithStatuses = async (): Promise< Result > => { const getAvatarUrl = async (url: string | null | undefined) => { if (!url) return null; const avatarUrl = await getSignedUrl({ bucket: 'avatars', url, transform: { width: 128, height: 128 }, }); if (avatarUrl.success) return avatarUrl.data; else return null; }; try { const supabase = await createServerClient(); const oneDayAgo = new Date(Date.now() - 1000 * 60 * 60 * 24); const { data, error } = (await supabase .from('statuses') .select( ` user:profiles!user_id(*), status, created_at, updated_by:profiles!updated_by_id(*) `, ) .gte('created_at', oneDayAgo.toISOString()) .order('created_at', { ascending: false })) as { data: UserWithStatus[]; error: unknown; }; if (error) throw error as Error; if (!data?.length) return { success: true, data: [] }; // 3️⃣ client-side dedupe: keep the first status you see per user const seen = new Set(); const filtered = data.filter((row) => { if (seen.has(row.user.id)) return false; seen.add(row.user.id); return true; }); const filteredWithAvatars = new Array(); for (const userWithStatus of filtered) { if (userWithStatus.user.avatar_url) userWithStatus.user.avatar_url = await getAvatarUrl( userWithStatus.user.avatar_url, ); if (userWithStatus.updated_by?.avatar_url) userWithStatus.updated_by.avatar_url = await getAvatarUrl( userWithStatus.updated_by?.avatar_url, ); filteredWithAvatars.push(userWithStatus); } return { success: true, data: filteredWithAvatars }; } catch (error) { return { success: false, error: `Error: ${error as Error}` }; } }; export const broadcastStatusUpdates = async ( userStatuses: UserWithStatus[], ): Promise> => { try { const supabase = await createServerClient(); for (const userStatus of userStatuses) { const broadcast = await supabase.channel('status_updates').send({ type: 'broadcast', event: 'status_updated', payload: { user_status: userStatus, timestamp: new Date().toISOString(), }, }); if (broadcast === 'error' || broadcast === 'timed out') throw new Error( 'Failed to broadcast status update. Timed out or errored.', ); } return { success: true, data: undefined }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } }; export const updateStatuses = async ( usersWithStatuses: UserWithStatus[], status: string, ): Promise> => { try { const supabase = await createServerClient(); const profileResponse = await getProfileWithAvatar(); if (!profileResponse.success) throw new Error('Not authenticated!'); const user = profileResponse.data; const { data: insertedStatuses, error: insertedStatusesError } = await supabase .from('statuses') .insert( usersWithStatuses.map((userWithStatus) => ({ user_id: userWithStatus.user.id, status, updated_by_id: user.id, })), ) .select(); if (insertedStatusesError) throw new Error("Couldn't insert statuses!"); else if (insertedStatuses) { const createdAtFallback = new Date(Date.now()).toISOString(); await broadcastStatusUpdates( usersWithStatuses.map((s, i) => { return { user: s.user, status: status, created_at: insertedStatuses[i]?.created_at ?? createdAtFallback, updated_by: user, }; }), ); } return { success: true, data: undefined }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } }; export const updateUserStatus = async ( status: string, ): Promise> => { try { const supabase = await createServerClient(); const profileResponse = await getProfileWithAvatar(); if (!profileResponse.success) throw new Error(`Not authenticated! ${profileResponse.error}`); const userProfile = profileResponse.data; const { data: insertedStatus, error: insertedStatusError } = await supabase .from('statuses') .insert({ user_id: userProfile.id, status, updated_by_id: userProfile.id, }) .select() .single(); if (insertedStatusError) throw insertedStatusError as Error; await broadcastStatusUpdates([ { user: userProfile, status: insertedStatus.status, created_at: insertedStatus.created_at, updated_by: userProfile, }, ]); return { success: true, data: undefined }; } catch (error) { return { success: false, error: `Error updating user's status: ${error as Error}`, }; } }; export const getUserHistory = async ( userId: string, page = 1, perPage = 50, ): Promise> => { try { const supabase = await createServerClient(); const userResponse = await getUser(); if (!userResponse.success) throw new Error(`Not authenticated! ${userResponse.error}`); const offset = (page - 1) * perPage; const { count } = await supabase .from('statuses') .select('*', { count: 'exact', head: true }) .eq('user_id', userId); const { data: statuses, error: statusesError } = (await supabase .from('statuses') .select( ` id, user:profiles!user_id(*), status, created_at, updated_by:profiles!updated_by_id(*) `, ) .eq('user_id', userId) .order('created_at', { ascending: false }) .range(offset, offset + perPage - 1)) as { data: UserWithStatus[]; error: unknown; }; if (statusesError) throw statusesError as Error; const totalCount = count ?? 0; const totalPages = Math.ceil(totalCount / perPage); return { success: true, data: { statuses, meta: { current_page: page, per_page: perPage, total_pages: totalPages, total_count: totalCount, }, }, }; } catch (error) { return { success: false, error: `Error getting user's history: ${error as Error}`, }; } }; export const getAllHistory = async ( page = 1, perPage = 50, ): Promise> => { try { const supabase = await createServerClient(); const userResponse = await getUser(); if (!userResponse.success) throw new Error(`Not authenticated! ${userResponse.error}`); const offset = (page - 1) * perPage; const { count } = await supabase .from('statuses') .select('*', { count: 'exact', head: true }); const { data: statuses, error: statusesError } = (await supabase .from('statuses') .select( ` id, user:profiles!user_id(*), status, created_at, updated_by:profiles!updated_by_id(*) `, ) .order('created_at', { ascending: false }) .range(offset, offset + perPage - 1)) as { data: UserWithStatus[]; error: unknown; }; if (statusesError) throw statusesError as Error; const totalCount = count ?? 0; const totalPages = Math.ceil(totalCount / perPage); return { success: true, data: { statuses, meta: { current_page: page, per_page: perPage, total_pages: totalPages, total_count: totalCount, }, }, }; } catch (error) { return { success: false, error: `Error getting all history: ${error as Error}`, }; } };