125 lines
4.3 KiB
TypeScript
125 lines
4.3 KiB
TypeScript
import type { Article, Category, Order, Page, Product } from '@homaroma/types'
|
|
import { API_BASE } from './api'
|
|
|
|
const isDev = process.env.NODE_ENV === 'development'
|
|
const defaultRevalidate = 0
|
|
|
|
type ProductListResponse = {
|
|
data?: Product[]
|
|
}
|
|
|
|
export type Coupon = {
|
|
id: number
|
|
code: string
|
|
type: 'PERCENTAGE' | 'FIXED_AMOUNT' | 'FREE_SHIPPING' | string
|
|
value: number
|
|
minPurchase: number
|
|
usageLimit: number | null
|
|
usedCount: number
|
|
expiresAt?: string | null
|
|
}
|
|
|
|
export type ApiResult<T> =
|
|
| { ok: true; data: T }
|
|
| { ok: false; error: string; status?: number }
|
|
|
|
export async function fetchJson<T>(path: string, init?: RequestInit & { next?: { revalidate?: number } }): Promise<T | null> {
|
|
try {
|
|
const res = await fetch(`${API_BASE}${path}`, {
|
|
...init,
|
|
next: init?.next ?? { revalidate: defaultRevalidate },
|
|
})
|
|
|
|
if (!res.ok) {
|
|
console.error(`[website-api] ${path} returned ${res.status}`)
|
|
return null
|
|
}
|
|
|
|
return await res.json() as T
|
|
} catch (error) {
|
|
console.error(`[website-api] Failed to fetch ${path}`, error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function fetchJsonResult<T>(path: string, init?: RequestInit & { next?: { revalidate?: number } }): Promise<ApiResult<T>> {
|
|
try {
|
|
const res = await fetch(`${API_BASE}${path}`, {
|
|
...init,
|
|
next: init?.next ?? { revalidate: defaultRevalidate },
|
|
})
|
|
|
|
if (!res.ok) {
|
|
return { ok: false, error: `${path} returned ${res.status}`, status: res.status }
|
|
}
|
|
|
|
return { ok: true, data: await res.json() as T }
|
|
} catch (error) {
|
|
return {
|
|
ok: false,
|
|
error: error instanceof Error ? error.message : `Failed to fetch ${path}`,
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function getCategories(lang = 'all'): Promise<Category[]> {
|
|
return await fetchJson<Category[]>(`/categories?lang=${lang}`, { next: { revalidate: 0 } }) ?? []
|
|
}
|
|
|
|
export async function getCategoriesResult(lang = 'all'): Promise<ApiResult<Category[]>> {
|
|
return await fetchJsonResult<Category[]>(`/categories?lang=${lang}`, { next: { revalidate: 0 } })
|
|
}
|
|
|
|
export async function getCmsPage(slug: string, lang = 'all'): Promise<Page | null> {
|
|
return await fetchJson<Page>(`/pages/${slug}?lang=${lang}`, { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getCmsPageResult(slug: string, lang = 'all'): Promise<ApiResult<Page>> {
|
|
return await fetchJsonResult<Page>(`/pages/${slug}?lang=${lang}`, { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getArticlesResult(): Promise<ApiResult<Article[]>> {
|
|
return await fetchJsonResult<Article[]>('/articles?publishedOnly=true', { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getActiveCouponsResult(): Promise<ApiResult<Coupon[]>> {
|
|
const response = await fetchJsonResult<Coupon[]>('/coupons/active', { next: { revalidate: defaultRevalidate } })
|
|
if (!response.ok) return response
|
|
|
|
return {
|
|
ok: true,
|
|
data: response.data.filter((coupon) => coupon.usageLimit === null || coupon.usedCount < coupon.usageLimit),
|
|
}
|
|
}
|
|
|
|
export async function getOrderResult(id: string | number): Promise<ApiResult<Order>> {
|
|
return await fetchJsonResult<Order>(`/orders/${id}`, { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getProduct(id: string | number, lang = 'all'): Promise<Product | null> {
|
|
return await fetchJson<Product>(`/products/${id}?lang=${lang}`, { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getProductResult(id: string | number, lang = 'all'): Promise<ApiResult<Product>> {
|
|
return await fetchJsonResult<Product>(`/products/${id}?lang=${lang}`, { next: { revalidate: defaultRevalidate } })
|
|
}
|
|
|
|
export async function getProducts(query = '', lang = 'all'): Promise<Product[]> {
|
|
const separator = query ? '&' : ''
|
|
const response = await fetchJson<ProductListResponse>(`/products?${query}${separator}lang=${lang}`, {
|
|
next: { revalidate: defaultRevalidate },
|
|
})
|
|
|
|
return response?.data ?? []
|
|
}
|
|
|
|
export async function getProductsResult(query = '', lang = 'all'): Promise<ApiResult<Product[]>> {
|
|
const separator = query ? '&' : ''
|
|
const response = await fetchJsonResult<ProductListResponse>(`/products?${query}${separator}lang=${lang}`, {
|
|
next: { revalidate: defaultRevalidate },
|
|
})
|
|
|
|
if (!response.ok) return response
|
|
return { ok: true, data: response.data.data ?? [] }
|
|
}
|