Update carousels, card hover, and IranBay branding.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { getAccessToken } from "@/lib/meshkee-api";
|
||||
|
||||
const API_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_MARKETPLACE_API_URL?.replace(/\/$/, "") ||
|
||||
"http://localhost:3001/api/v1";
|
||||
|
||||
const WEBSITE_ORIGIN =
|
||||
process.env.NEXT_PUBLIC_WEBSITE_URL?.replace(/\/$/, "") ||
|
||||
"http://localhost:3000";
|
||||
|
||||
export type WebsiteMediaItem = {
|
||||
id: string;
|
||||
imageUrl: string;
|
||||
linkUrl: string;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
cta?: string;
|
||||
};
|
||||
|
||||
export type WebsiteHomeMedia = {
|
||||
slider: WebsiteMediaItem[];
|
||||
standingBanners: WebsiteMediaItem[];
|
||||
categories: WebsiteMediaItem[];
|
||||
menuImages: WebsiteMediaItem[];
|
||||
aboutUs: WebsiteMediaItem;
|
||||
banners: WebsiteMediaItem[];
|
||||
};
|
||||
|
||||
function resolveMediaUrl(url: string) {
|
||||
if (!url) return url;
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) return url;
|
||||
// Uploaded files live on the IranBay marketplace API.
|
||||
if (url.startsWith("/api/v1/")) {
|
||||
const origin = API_BASE_URL.replace(/\/api\/v1$/, "");
|
||||
return `${origin}${url}`;
|
||||
}
|
||||
// Bundled homepage assets live on the public website.
|
||||
if (url.startsWith("/")) {
|
||||
return `${WEBSITE_ORIGIN}${url}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
async function parseResponse<T>(response: Response): Promise<T> {
|
||||
const payload = await response.json().catch(() => null);
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
typeof payload?.message === "string"
|
||||
? payload.message
|
||||
: Array.isArray(payload?.message)
|
||||
? payload.message.join(", ")
|
||||
: `Request failed (${response.status})`;
|
||||
throw new Error(message);
|
||||
}
|
||||
return payload as T;
|
||||
}
|
||||
|
||||
export async function getWebsiteHomeMedia(): Promise<WebsiteHomeMedia> {
|
||||
const response = await fetch(`${API_BASE_URL}/website/home-media`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
const data = await parseResponse<WebsiteHomeMedia>(response);
|
||||
return {
|
||||
...data,
|
||||
slider: data.slider.map((item) => ({
|
||||
...item,
|
||||
imageUrl: resolveMediaUrl(item.imageUrl),
|
||||
})),
|
||||
standingBanners: data.standingBanners.map((item) => ({
|
||||
...item,
|
||||
imageUrl: resolveMediaUrl(item.imageUrl),
|
||||
})),
|
||||
categories: data.categories.map((item) => ({
|
||||
...item,
|
||||
imageUrl: resolveMediaUrl(item.imageUrl),
|
||||
})),
|
||||
menuImages: (data.menuImages ?? []).map((item) => ({
|
||||
...item,
|
||||
imageUrl: resolveMediaUrl(item.imageUrl),
|
||||
})),
|
||||
aboutUs: {
|
||||
...data.aboutUs,
|
||||
imageUrl: resolveMediaUrl(data.aboutUs.imageUrl),
|
||||
},
|
||||
banners: data.banners.map((item) => ({
|
||||
...item,
|
||||
imageUrl: resolveMediaUrl(item.imageUrl),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function saveWebsiteHomeMedia(
|
||||
body: WebsiteHomeMedia,
|
||||
): Promise<WebsiteHomeMedia> {
|
||||
const response = await fetch(`${API_BASE_URL}/website/home-media`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(getAccessToken()
|
||||
? { Authorization: `Bearer ${getAccessToken()}` }
|
||||
: {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
return parseResponse<WebsiteHomeMedia>(response);
|
||||
}
|
||||
|
||||
export async function uploadWebsiteMedia(file: File): Promise<string> {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
const headers: HeadersInit = {};
|
||||
const token = getAccessToken();
|
||||
if (token) headers.Authorization = `Bearer ${token}`;
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/website/upload`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: form,
|
||||
});
|
||||
const data = await parseResponse<{ url: string }>(response);
|
||||
return resolveMediaUrl(data.url);
|
||||
}
|
||||
|
||||
export function newMediaItem(
|
||||
partial?: Partial<WebsiteMediaItem>,
|
||||
): WebsiteMediaItem {
|
||||
return {
|
||||
id: `item-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
imageUrl: "",
|
||||
linkUrl: "/",
|
||||
...partial,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user