168 lines
4.2 KiB
TypeScript
168 lines
4.2 KiB
TypeScript
import { createSupabaseServiceRoleClient } from "@/lib/supabase/service-role";
|
|
|
|
export type PublicGalleryPhotoRow = {
|
|
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;
|
|
likes: number | null;
|
|
urls: Record<string, unknown>;
|
|
user_info: Record<string, unknown>;
|
|
photo_created_at: string | null;
|
|
picked_at: string | null;
|
|
oss_url: string | null;
|
|
};
|
|
|
|
export const publicGalleryPhotoSelect =
|
|
"id,unsplash_id,slug,description,alt_description,width,height,color,color_family,likes,urls,user_info,photo_created_at,picked_at,oss_url";
|
|
|
|
export function getPublicPhotoUrl(photo: PublicGalleryPhotoRow) {
|
|
const candidates = [
|
|
photo.oss_url,
|
|
photo.urls?.regular,
|
|
photo.urls?.small,
|
|
photo.urls?.raw,
|
|
photo.urls?.thumb,
|
|
];
|
|
|
|
for (const candidate of candidates) {
|
|
if (typeof candidate === "string" && candidate.length > 0) {
|
|
return candidate;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export async function getFavoritePhotoIds({
|
|
photoIds,
|
|
userId,
|
|
}: {
|
|
photoIds: string[];
|
|
userId: string | null;
|
|
}) {
|
|
if (!userId || photoIds.length === 0) {
|
|
return new Set<string>();
|
|
}
|
|
|
|
const supabase = createSupabaseServiceRoleClient();
|
|
const { data, error } = await supabase
|
|
.from("wg_user_favorites")
|
|
.select("photo_id")
|
|
.eq("user_id", userId)
|
|
.in("photo_id", photoIds);
|
|
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
|
|
return new Set((data ?? []).map((favorite) => favorite.photo_id));
|
|
}
|
|
|
|
export function mapPublicGalleryPhoto({
|
|
favoritePhotoIds,
|
|
photo,
|
|
}: {
|
|
favoritePhotoIds?: Set<string>;
|
|
photo: PublicGalleryPhotoRow;
|
|
}) {
|
|
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,
|
|
likes: photo.likes,
|
|
url: getPublicPhotoUrl(photo),
|
|
sourceUrl: getPublicPhotoUrl({ ...photo, oss_url: null }),
|
|
user: photo.user_info,
|
|
photoCreatedAt: photo.photo_created_at,
|
|
pickedAt: photo.picked_at,
|
|
isFavorited: favoritePhotoIds?.has(photo.id) ?? false,
|
|
};
|
|
}
|
|
|
|
export async function listPickedGalleryPhotos({
|
|
colorFamily,
|
|
page,
|
|
pageSize,
|
|
userId,
|
|
}: {
|
|
colorFamily: string | null;
|
|
page: number;
|
|
pageSize: number;
|
|
userId: string | null;
|
|
}) {
|
|
const supabase = createSupabaseServiceRoleClient();
|
|
let query = supabase
|
|
.from("wg_gallery_photos")
|
|
.select(publicGalleryPhotoSelect, { count: "exact" })
|
|
.eq("is_picked", true);
|
|
|
|
if (colorFamily && colorFamily !== "all") {
|
|
query = query.eq("color_family", colorFamily);
|
|
}
|
|
|
|
const { data, error, count } = await query
|
|
.order("picked_at", { ascending: false, nullsFirst: false })
|
|
.order("photo_created_at", { ascending: false })
|
|
.range((page - 1) * pageSize, page * pageSize - 1);
|
|
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
|
|
const photos = (data ?? []) as PublicGalleryPhotoRow[];
|
|
const favoritePhotoIds = await getFavoritePhotoIds({
|
|
userId,
|
|
photoIds: photos.map((photo) => photo.id),
|
|
});
|
|
|
|
return {
|
|
data: photos.map((photo) =>
|
|
mapPublicGalleryPhoto({ photo, favoritePhotoIds }),
|
|
),
|
|
total: count ?? 0,
|
|
};
|
|
}
|
|
|
|
export async function getPickedGalleryPhotoById({
|
|
id,
|
|
userId,
|
|
}: {
|
|
id: string;
|
|
userId: string | null;
|
|
}) {
|
|
const supabase = createSupabaseServiceRoleClient();
|
|
const { data, error } = await supabase
|
|
.from("wg_gallery_photos")
|
|
.select(publicGalleryPhotoSelect)
|
|
.eq("id", id)
|
|
.eq("is_picked", true)
|
|
.maybeSingle<PublicGalleryPhotoRow>();
|
|
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
|
|
if (!data) {
|
|
return null;
|
|
}
|
|
|
|
const favoritePhotoIds = await getFavoritePhotoIds({
|
|
userId,
|
|
photoIds: [data.id],
|
|
});
|
|
|
|
return mapPublicGalleryPhoto({ photo: data, favoritePhotoIds });
|
|
}
|