lomavuokraus/lib/listings.ts
2025-11-26 14:27:55 +02:00

84 lines
2.4 KiB
TypeScript

import { Prisma, ListingStatus } from '@prisma/client';
import { prisma } from './prisma';
import { DEFAULT_LOCALE, SAMPLE_LISTING_SLUG } from './sampleListing';
export type ListingWithTranslations = Prisma.ListingTranslationGetPayload<{
include: {
listing: {
include: {
images: { select: { id: true; url: true; altText: true; order: true; isCover: true; size: true; mimeType: true } };
owner: true;
};
};
};
}>;
type FetchOptions = {
slug: string;
locale?: string;
};
function resolveImageUrl(img: { id: string; url: string | null; size: number | null }) {
if (img.size && img.size > 0) {
return `/api/images/${img.id}`;
}
return img.url;
}
/**
* Fetch a listing translation by slug and locale.
* Falls back to any locale if the requested locale is missing.
*/
export async function getListingBySlug({ slug, locale }: FetchOptions): Promise<ListingWithTranslations | null> {
const targetLocale = locale ?? DEFAULT_LOCALE;
const translation = await prisma.listingTranslation.findFirst({
where: { slug, locale: targetLocale, listing: { status: ListingStatus.PUBLISHED, removedAt: null } },
include: {
listing: {
include: {
images: { orderBy: { order: 'asc' }, select: { id: true, url: true, altText: true, order: true, isCover: true, size: true, mimeType: true } },
owner: true,
},
},
},
});
if (translation) {
return translation;
}
// Fallback: first translation for this slug
return prisma.listingTranslation.findFirst({
where: { slug, listing: { status: ListingStatus.PUBLISHED, removedAt: null } },
include: {
listing: {
include: {
images: { orderBy: { order: 'asc' }, select: { id: true, url: true, altText: true, order: true, isCover: true, size: true, mimeType: true } },
owner: true,
},
},
},
orderBy: { createdAt: 'asc' },
});
}
export function withResolvedListingImages(translation: ListingWithTranslations): ListingWithTranslations {
const images = translation.listing.images
.map((img) => {
const url = resolveImageUrl(img);
if (!url) return null;
return { ...img, url };
})
.filter(Boolean) as ListingWithTranslations['listing']['images'];
return {
...translation,
listing: {
...translation.listing,
images,
},
};
}
export { SAMPLE_LISTING_SLUG, DEFAULT_LOCALE };