101 lines
4.0 KiB
TypeScript
101 lines
4.0 KiB
TypeScript
|
|
import type {
|
||
|
|
ApiResponse,
|
||
|
|
CafeDiscoverDto,
|
||
|
|
CafePublicDto,
|
||
|
|
PublicMenuDto,
|
||
|
|
CafeReviewDto,
|
||
|
|
NlpHints,
|
||
|
|
DiscoverFilters,
|
||
|
|
} from "@/lib/types";
|
||
|
|
|
||
|
|
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "https://api.meezi.ir";
|
||
|
|
|
||
|
|
async function get<T>(path: string, opts?: RequestInit): Promise<T | null> {
|
||
|
|
try {
|
||
|
|
const res = await fetch(`${API_URL}${path}`, {
|
||
|
|
next: { revalidate: 60 },
|
||
|
|
...opts,
|
||
|
|
});
|
||
|
|
if (!res.ok) return null;
|
||
|
|
const json = (await res.json()) as ApiResponse<T>;
|
||
|
|
return json.success ? json.data : null;
|
||
|
|
} catch {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Discover / search ─────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export async function discoverCafes(
|
||
|
|
filters: DiscoverFilters
|
||
|
|
): Promise<CafeDiscoverDto[]> {
|
||
|
|
const params = new URLSearchParams();
|
||
|
|
if (filters.city) params.set("city", filters.city);
|
||
|
|
if (filters.q) params.set("q", filters.q);
|
||
|
|
if (filters.minRating) params.set("minRating", String(filters.minRating));
|
||
|
|
if (filters.sort) params.set("sort", filters.sort);
|
||
|
|
if (filters.themes?.length) params.set("themes", filters.themes.join(","));
|
||
|
|
if (filters.vibes?.length) params.set("vibes", filters.vibes.join(","));
|
||
|
|
if (filters.occasions?.length) params.set("occasions", filters.occasions.join(","));
|
||
|
|
if (filters.spaceFeatures?.length) params.set("spaceFeatures", filters.spaceFeatures.join(","));
|
||
|
|
if (filters.noise) params.set("noise", filters.noise);
|
||
|
|
if (filters.priceTier) params.set("priceTier", filters.priceTier);
|
||
|
|
if (filters.size) params.set("size", filters.size);
|
||
|
|
if (filters.openNow) params.set("openNow", "true");
|
||
|
|
|
||
|
|
const qs = params.toString();
|
||
|
|
const result = await get<CafeDiscoverDto[]>(
|
||
|
|
`/api/public/discover${qs ? `?${qs}` : ""}`,
|
||
|
|
{ next: { revalidate: 30 } }
|
||
|
|
);
|
||
|
|
return result ?? [];
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Individual cafe ───────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export async function getCafe(slug: string): Promise<CafePublicDto | null> {
|
||
|
|
return get<CafePublicDto>(`/api/public/cafes/${slug}`, {
|
||
|
|
next: { revalidate: 300 },
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Menu ──────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export async function getCafeMenu(slug: string): Promise<PublicMenuDto | null> {
|
||
|
|
return get<PublicMenuDto>(`/api/public/cafes/${slug}/menu`, {
|
||
|
|
next: { revalidate: 300 },
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Reviews ───────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export async function getCafeReviews(
|
||
|
|
slug: string,
|
||
|
|
page = 1
|
||
|
|
): Promise<CafeReviewDto[]> {
|
||
|
|
const result = await get<CafeReviewDto[]>(
|
||
|
|
`/api/public/cafes/${slug}/reviews?page=${page}&pageSize=10`,
|
||
|
|
{ next: { revalidate: 120 } }
|
||
|
|
);
|
||
|
|
return result ?? [];
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── NLP parse (server-side only; for ISR hint pre-population) ─────────────────
|
||
|
|
|
||
|
|
export async function nlpParse(q: string): Promise<NlpHints | null> {
|
||
|
|
return get<NlpHints>(
|
||
|
|
`/api/public/discover/nlp-parse?q=${encodeURIComponent(q)}`,
|
||
|
|
{ cache: "no-store" }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Slugs for static generation ───────────────────────────────────────────────
|
||
|
|
|
||
|
|
export async function getAllCafeSlugs(): Promise<string[]> {
|
||
|
|
// Fetch all cafes without filters to get slugs for static generation
|
||
|
|
const cafes = await get<CafeDiscoverDto[]>("/api/public/discover?requireProfile=false", {
|
||
|
|
next: { revalidate: 3600 },
|
||
|
|
});
|
||
|
|
return cafes?.map((c) => c.slug) ?? [];
|
||
|
|
}
|