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
+84
View File
@@ -0,0 +1,84 @@
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
import {
brandCategoryTree,
type CategoryNode,
} from "./data/brand-categories.js";
const prisma = new PrismaClient();
function slugify(value: string): string {
return value
.trim()
.toLowerCase()
.replace(/['"]/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 120);
}
async function uniqueSlug(base: string): Promise<string> {
let slug = slugify(base) || "category";
let candidate = slug;
let i = 2;
while (await prisma.category.findUnique({ where: { slug: candidate } })) {
candidate = `${slug}-${i}`;
i += 1;
}
return candidate;
}
async function insertTree(
nodes: CategoryNode[],
parentId: string | null = null,
): Promise<number> {
let count = 0;
for (const node of nodes) {
const slug = await uniqueSlug(node.name);
const created = await prisma.category.create({
data: {
name: node.name,
slug,
parentId,
},
});
count += 1;
if (node.children?.length) {
count += await insertTree(node.children, created.id);
}
}
return count;
}
async function main() {
const passwordHash = await bcrypt.hash("admin123", 10);
const admin = await prisma.user.upsert({
where: { email: "admin@novintrades.com" },
update: {},
create: {
email: "admin@novintrades.com",
name: "Admin",
passwordHash,
},
});
await prisma.blogCategory.deleteMany();
await prisma.reportageCategory.deleteMany();
await prisma.brandCategory.deleteMany();
await prisma.category.deleteMany();
const treeCount = await insertTree(brandCategoryTree);
console.log(`Seeded admin: ${admin.email}`);
console.log(`Seeded ${treeCount} categories from Categories.docx hierarchy`);
}
main()
.catch((error) => {
console.error(error);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});