import { createSupabaseServiceRoleClient } from "@/lib/supabase/service-role"; type FavoriteRow = { photo_id: string; created_at: string; }; type FavoritePhotoRow = { id: string; unsplash_id: string; slug: string | null; description: string | null; alt_description: string | null; width: number | null; height: number | null; color: string | null; color_family: string | null; urls: Record; user_info: Record; picked_at: string | null; oss_url: string | null; }; const favoritePhotoSelect = "id,unsplash_id,slug,description,alt_description,width,height,color,color_family,urls,user_info,picked_at,oss_url"; function getPhotoUrl(photo: FavoritePhotoRow) { const urls = photo.urls as Record | undefined; return ( photo.oss_url ?? urls?.regular ?? urls?.small ?? urls?.raw ?? urls?.thumb ?? null ); } function mapPhoto(photo: FavoritePhotoRow, favoritedAt: string | null) { return { id: photo.id, unsplashId: photo.unsplash_id, slug: photo.slug, description: photo.description, altDescription: photo.alt_description, width: photo.width, height: photo.height, color: photo.color, colorFamily: photo.color_family, url: getPhotoUrl(photo), sourceUrl: getPhotoUrl({ ...photo, oss_url: null }), user: photo.user_info, pickedAt: photo.picked_at, favoritedAt, }; } export async function listUserFavorites({ page, pageSize, userId, }: { page: number; pageSize: number; userId: string; }) { const supabase = createSupabaseServiceRoleClient(); const { data, error, count } = await supabase .from("wg_user_favorites") .select("photo_id,created_at", { count: "exact" }) .eq("user_id", userId) .order("created_at", { ascending: false }) .range((page - 1) * pageSize, page * pageSize - 1); if (error) { throw error; } const favorites = (data ?? []) as FavoriteRow[]; const photoIds = favorites.map((favorite) => favorite.photo_id); if (photoIds.length === 0) { return { data: [], total: count ?? 0, }; } const { data: photos, error: photosError } = await supabase .from("wg_gallery_photos") .select(favoritePhotoSelect) .eq("is_picked", true) .in("id", photoIds); if (photosError) { throw photosError; } const favoritedAtByPhotoId = new Map( favorites.map((favorite) => [favorite.photo_id, favorite.created_at]), ); const photoById = new Map( ((photos ?? []) as FavoritePhotoRow[]).map((photo) => [ photo.id, photo, ]), ); return { data: photoIds .map((photoId) => photoById.get(photoId)) .filter((photo): photo is FavoritePhotoRow => Boolean(photo)) .map((photo) => mapPhoto(photo, favoritedAtByPhotoId.get(photo.id) ?? null), ), total: count ?? 0, }; } export async function addUserFavorite({ photoId, userId, }: { photoId: string; userId: string; }) { const supabase = createSupabaseServiceRoleClient(); const { data: photo, error: photoError } = await supabase .from("wg_gallery_photos") .select(favoritePhotoSelect) .eq("id", photoId) .eq("is_picked", true) .maybeSingle(); if (photoError) { throw photoError; } if (!photo) { throw new Error("Picked photo was not found."); } const { data, error } = await supabase .from("wg_user_favorites") .upsert( { user_id: userId, photo_id: photoId, }, { onConflict: "user_id,photo_id" }, ) .select("created_at") .single<{ created_at: string }>(); if (error) { throw error; } return mapPhoto(photo, data.created_at); } export async function removeUserFavorite({ photoId, userId, }: { photoId: string; userId: string; }) { const supabase = createSupabaseServiceRoleClient(); const { error } = await supabase .from("wg_user_favorites") .delete() .eq("user_id", userId) .eq("photo_id", photoId); if (error) { throw error; } }