207 lines
5.5 KiB
TypeScript
207 lines
5.5 KiB
TypeScript
import { apiRequest, getAccessToken } from "@/lib/meshkee-api";
|
|
|
|
export type CatalogEntityType = "product" | "blog" | "portfolio";
|
|
|
|
export type MeshkeeEntityCategory = {
|
|
id: string;
|
|
name: string;
|
|
nameFa?: string | null;
|
|
parentId: string | null;
|
|
description?: string | null;
|
|
seoMetaTitle?: string | null;
|
|
seoMetaDescription?: string | null;
|
|
sortOrder?: number;
|
|
};
|
|
|
|
export type UpsertCategoryInput = {
|
|
parentId?: string | null;
|
|
name: string;
|
|
nameFa?: string;
|
|
description?: string;
|
|
seoMetaTitle?: string | null;
|
|
seoMetaDescription?: string | null;
|
|
};
|
|
|
|
export type CreateProductInput = {
|
|
title: string;
|
|
nameFa?: string;
|
|
summary?: string;
|
|
descriptionHtml?: string;
|
|
categoryId?: string;
|
|
featuredMediaId?: string;
|
|
galleryMediaIds?: string[];
|
|
tags?: string[];
|
|
seoMetaTitle?: string | null;
|
|
seoMetaDescription?: string | null;
|
|
status?: "draft" | "published" | "archived";
|
|
};
|
|
|
|
export type CreateBlogInput = {
|
|
title: string;
|
|
type: "news" | "article" | "blog";
|
|
abstract?: string;
|
|
mainTextHtml?: string;
|
|
categoryId?: string;
|
|
featuredMediaId?: string;
|
|
tags?: string[];
|
|
seoMetaTitle?: string | null;
|
|
seoMetaDescription?: string | null;
|
|
status?: "draft" | "published" | "archived";
|
|
};
|
|
|
|
export type CreatePortfolioInput = {
|
|
titleFa: string;
|
|
titleEn?: string;
|
|
abstract?: string;
|
|
projectUrl?: string;
|
|
mainTextHtml?: string;
|
|
categoryId?: string;
|
|
featuredMediaId?: string;
|
|
galleryMediaIds?: string[];
|
|
tags?: string[];
|
|
seoMetaTitle?: string | null;
|
|
seoMetaDescription?: string | null;
|
|
status?: "draft" | "published" | "archived";
|
|
};
|
|
|
|
export async function listMeshkeeEntityCategories(
|
|
businessId: string,
|
|
entityType: CatalogEntityType,
|
|
) {
|
|
const params = new URLSearchParams({ entityType });
|
|
const data = await apiRequest<{ items: MeshkeeEntityCategory[] }>(
|
|
`/businesses/${businessId}/categories?${params}`,
|
|
{ auth: true },
|
|
);
|
|
return (data.items ?? []).map((item) => ({
|
|
...item,
|
|
id: String(item.id),
|
|
parentId: item.parentId == null ? null : String(item.parentId),
|
|
description: item.description ?? "",
|
|
seoMetaTitle: item.seoMetaTitle ?? "",
|
|
seoMetaDescription: item.seoMetaDescription ?? "",
|
|
}));
|
|
}
|
|
|
|
export function categoryOptionLabel(category: MeshkeeEntityCategory) {
|
|
if (category.nameFa && category.nameFa !== category.name) {
|
|
return `${category.name} / ${category.nameFa}`;
|
|
}
|
|
return category.name || category.nameFa || "Category";
|
|
}
|
|
|
|
export async function createMeshkeeEntityCategory(
|
|
businessId: string,
|
|
entityType: CatalogEntityType,
|
|
body: UpsertCategoryInput,
|
|
) {
|
|
return apiRequest(`/businesses/${businessId}/categories`, {
|
|
method: "POST",
|
|
auth: true,
|
|
body: {
|
|
entityType,
|
|
parentId: body.parentId || undefined,
|
|
name: body.name.trim(),
|
|
nameFa: body.nameFa?.trim() || undefined,
|
|
description: body.description?.trim() || undefined,
|
|
seoMetaTitle: body.seoMetaTitle?.trim() || null,
|
|
seoMetaDescription: body.seoMetaDescription?.trim() || null,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function updateMeshkeeEntityCategory(
|
|
businessId: string,
|
|
categoryId: string,
|
|
body: UpsertCategoryInput,
|
|
) {
|
|
return apiRequest(`/businesses/${businessId}/categories/${categoryId}`, {
|
|
method: "PATCH",
|
|
auth: true,
|
|
body: {
|
|
parentId: body.parentId === undefined ? undefined : body.parentId || null,
|
|
name: body.name.trim(),
|
|
nameFa: body.nameFa?.trim() || null,
|
|
description: body.description?.trim() || null,
|
|
seoMetaTitle: body.seoMetaTitle?.trim() || null,
|
|
seoMetaDescription: body.seoMetaDescription?.trim() || null,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function deleteMeshkeeEntityCategory(
|
|
businessId: string,
|
|
categoryId: string,
|
|
) {
|
|
return apiRequest<{ deletedIds?: string[] }>(
|
|
`/businesses/${businessId}/categories/${categoryId}`,
|
|
{
|
|
method: "DELETE",
|
|
auth: true,
|
|
},
|
|
);
|
|
}
|
|
|
|
export async function uploadMeshkeeMediaFile(businessId: string, file: File) {
|
|
const token = getAccessToken();
|
|
const form = new FormData();
|
|
form.append("files", file);
|
|
const base =
|
|
process.env.NEXT_PUBLIC_MESHKEE_API_URL?.replace(/\/$/, "") ||
|
|
"http://localhost:3010/api/v1";
|
|
|
|
const response = await fetch(`${base}/businesses/${businessId}/media`, {
|
|
method: "POST",
|
|
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
|
|
body: form,
|
|
});
|
|
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(", ")
|
|
: `Upload failed (${response.status})`;
|
|
throw new Error(message);
|
|
}
|
|
const item = Array.isArray(payload?.items) ? payload.items[0] : payload;
|
|
return {
|
|
id: String(item.id),
|
|
publicUrl: String(item.publicUrl ?? item.url ?? ""),
|
|
};
|
|
}
|
|
|
|
export async function createMeshkeeProduct(
|
|
businessId: string,
|
|
body: CreateProductInput,
|
|
) {
|
|
return apiRequest(`/businesses/${businessId}/products`, {
|
|
method: "POST",
|
|
auth: true,
|
|
body: { status: "published", ...body },
|
|
});
|
|
}
|
|
|
|
export async function createMeshkeeBlog(
|
|
businessId: string,
|
|
body: CreateBlogInput,
|
|
) {
|
|
return apiRequest(`/businesses/${businessId}/blogs`, {
|
|
method: "POST",
|
|
auth: true,
|
|
body: { status: "published", ...body },
|
|
});
|
|
}
|
|
|
|
export async function createMeshkeePortfolio(
|
|
businessId: string,
|
|
body: CreatePortfolioInput,
|
|
) {
|
|
return apiRequest(`/businesses/${businessId}/portfolios`, {
|
|
method: "POST",
|
|
auth: true,
|
|
body: { status: "published", ...body },
|
|
});
|
|
}
|