Initial commit: NovinTrades website monorepo.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-07-24 17:16:53 +03:30
co-authored by Cursor
commit 722a520e68
147 changed files with 15748 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
import { api, ApiError } from "./api";
import { assertClientImageSize } from "./image";
import type {
AuthUser,
Blog,
Brand,
BrandContact,
Category,
Reportage,
VerificationStatus,
} from "./types";
export function login(email: string, password: string) {
return api<{ user: AuthUser }>("/api/auth/login", {
method: "POST",
body: JSON.stringify({ email, password }),
});
}
export function listCategories() {
return api<Category[]>("/api/categories");
}
export function listBlogs() {
return api<Blog[]>("/api/blogs");
}
export function getBlog(id: string) {
return api<Blog>(`/api/blogs/${id}`);
}
export function createBlog(input: {
title: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
tags?: string[];
categoryIds?: string[];
authorId: string;
verificationStatus?: VerificationStatus;
}) {
return api<Blog>("/api/blogs", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateBlog(
id: string,
input: {
title?: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
tags?: string[];
categoryIds?: string[];
verificationStatus?: VerificationStatus;
publishedAt?: string | null;
},
) {
return api<Blog>(`/api/blogs/${id}`, {
method: "PATCH",
body: JSON.stringify(input),
});
}
export function listReportages() {
return api<Reportage[]>("/api/reportages");
}
export function getReportage(id: string) {
return api<Reportage>(`/api/reportages/${id}`);
}
export function createReportage(input: {
title: string;
businessOwner: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
tags?: string[];
categoryIds?: string[];
authorId: string;
verificationStatus?: VerificationStatus;
}) {
return api<Reportage>("/api/reportages", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateReportage(
id: string,
input: {
title?: string;
businessOwner?: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
tags?: string[];
categoryIds?: string[];
verificationStatus?: VerificationStatus;
publishedAt?: string | null;
},
) {
return api<Reportage>(`/api/reportages/${id}`, {
method: "PATCH",
body: JSON.stringify(input),
});
}
export function listBrands() {
return api<Brand[]>("/api/brands");
}
export function getBrand(id: string) {
return api<Brand>(`/api/brands/${id}`);
}
export function createBrand(input: {
title: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
galleryUrls?: string[];
tags?: string[];
country: string;
city?: string;
address?: string;
contacts?: BrandContact[];
categoryIds?: string[];
authorId: string;
verificationStatus?: VerificationStatus;
}) {
return api<Brand>("/api/brands", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateBrand(
id: string,
input: {
title?: string;
abstract?: string;
content?: string;
imageUrl?: string | null;
galleryUrls?: string[];
tags?: string[];
country?: string;
city?: string;
address?: string;
contacts?: BrandContact[];
categoryIds?: string[];
verificationStatus?: VerificationStatus;
publishedAt?: string | null;
},
) {
return api<Brand>(`/api/brands/${id}`, {
method: "PATCH",
body: JSON.stringify(input),
});
}
export async function uploadImage(
file: Blob,
folder: string,
): Promise<{ url: string; key: string; size: number }> {
assertClientImageSize(file.size);
const form = new FormData();
const filename =
file instanceof File && file.name
? file.name
: `image.${file.type.includes("png") ? "png" : "jpg"}`;
form.append("file", file, filename);
const response = await fetch(
`/api/uploads?folder=${encodeURIComponent(folder)}`,
{
method: "POST",
body: form,
},
);
if (!response.ok) {
let message = "Upload failed";
try {
const data = (await response.json()) as { error?: string };
if (data.error) message = data.error;
} catch {
// ignore
}
throw new ApiError(response.status, message);
}
return (await response.json()) as {
url: string;
key: string;
size: number;
};
}