Files
goodgo-platform/apps/web/lib/listings-server.ts
2026-05-07 13:08:20 +07:00

54 lines
1.6 KiB
TypeScript

/**
* Server-side listing data fetching for Next.js Server Components.
*
* This module uses `fetch` directly (no browser-only helpers) so it can run
* inside `generateMetadata`, `generateStaticParams`, `sitemap()`, etc.
*/
import type { ListingDetail, PaginatedResult } from './listings-api';
const API_BASE_URL = process.env['NEXT_PUBLIC_API_URL'] || 'http://localhost:3001/api/v1';
/**
* Fetch a single listing by ID — server-only.
* Returns `null` when the listing is not found (404) so callers can `notFound()`.
*/
export async function fetchListingById(id: string): Promise<ListingDetail | null> {
try {
const res = await fetch(`${API_BASE_URL}/listings/${id}`, {
// Listing detail includes mutable status, price, legal and moderation data.
// Avoid serving stale details after admin/user actions.
cache: 'no-store',
});
if (!res.ok) return null;
return (await res.json()) as ListingDetail;
} catch {
return null;
}
}
/**
* Fetch active listings — server-only, used by the dynamic sitemap.
*/
export async function fetchActiveListings(params: {
page?: number;
limit?: number;
}): Promise<PaginatedResult<ListingDetail>> {
const query = new URLSearchParams({
status: 'ACTIVE',
page: String(params.page ?? 1),
limit: String(params.limit ?? 100),
});
const res = await fetch(`${API_BASE_URL}/listings?${query}`, {
next: { revalidate: 3600 }, // re-validate every hour for sitemap
});
if (!res.ok) {
return { data: [], total: 0, page: 1, limit: 100, totalPages: 0 };
}
return (await res.json()) as PaginatedResult<ListingDetail>;
}