Skip to content

Commit 8b5a107

Browse files
Add categories
1 parent 55f4495 commit 8b5a107

File tree

24 files changed

+1136
-121
lines changed

24 files changed

+1136
-121
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ It simulates a real-world development workflow with collaborative feature develo
1313
S25-Full-Stack-Circle/
1414
├── frontend/ # React + Vite + CSS Modules
1515
├── backend/ # Express + Prisma + PostgreSQL
16+
├── scripts/ # Utility scripts for setup and maintenance
1617
└── README.md
1718

1819
````
@@ -89,6 +90,24 @@ npm run seed
8990

9091
---
9192

93+
### 🏷️ Category System
94+
95+
The app uses a category-based organization system for pins:
96+
97+
- Each pin can belong to one category
98+
- Categories are displayed on the Explore page
99+
100+
#### Seeding Categories
101+
102+
To populate the database with initial categories:
103+
104+
```bash
105+
cd backend
106+
node scripts/seed-categories.js
107+
```
108+
109+
---
110+
92111
## ⚙ Tech Stack
93112

94113
* **Frontend**: React + Vite + CSS Modules

backend/prisma/schema.prisma

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ model User {
3131
savedPins SavedPin[]
3232
}
3333

34+
model Category {
35+
id Int @id @default(autoincrement())
36+
title String @unique
37+
imageUrl String?
38+
description String?
39+
createdAt DateTime @default(now())
40+
41+
pins Pin[]
42+
}
43+
3444
model Pin {
3545
id Int @id @default(autoincrement())
3646
title String
@@ -43,6 +53,8 @@ model Pin {
4353
isAllowedtoComment Boolean @default(true)
4454
link String?
4555
showSimilarProduct Boolean @default(false)
56+
categoryId Int?
57+
category Category? @relation(fields: [categoryId], references: [id])
4658
comments Comment[]
4759
author User @relation("CreatedPins", fields: [authorId], references: [id])
4860
// board Board? @relation(fields: [boardId], references: [id])
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { PrismaClient } from "@prisma/client";
2+
// script used to cleanup categories in the database
3+
const prisma = new PrismaClient();
4+
5+
async function main() {
6+
console.log("Cleaning up categories...");
7+
8+
// First, remove category references from pins
9+
await prisma.pin.updateMany({
10+
data: {
11+
categoryId: null
12+
}
13+
});
14+
15+
// Then delete all categories
16+
await prisma.category.deleteMany({});
17+
18+
console.log("Categories cleaned up successfully!");
19+
}
20+
21+
main()
22+
.catch(e => {
23+
console.error("Error cleaning up categories:", e);
24+
process.exit(1);
25+
})
26+
.finally(async () => {
27+
await prisma.$disconnect();
28+
process.exit(0);
29+
});

backend/scripts/seed-categories.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Script to seed initial categories into the database
2+
import { PrismaClient } from "@prisma/client";
3+
4+
const prisma = new PrismaClient();
5+
6+
const categories = [
7+
{
8+
title: "Art",
9+
description:
10+
"Paintings, drawings, sculptures and other beautiful creations",
11+
imageUrl: "https://picsum.photos/300/150?random=2"
12+
},
13+
{
14+
title: "Beauty",
15+
description: "Makeup, skincare, hair and other beauty topics",
16+
imageUrl: "https://picsum.photos/300/150?random=3"
17+
},
18+
{
19+
title: "Design",
20+
description: "Graphic design, interior design and other creative designs",
21+
imageUrl: "https://picsum.photos/300/150?random=4"
22+
},
23+
{
24+
title: "DIY and Crafts",
25+
description: "Do it yourself projects and crafting ideas",
26+
imageUrl: "https://picsum.photos/300/150?random=5"
27+
},
28+
{
29+
title: "Food and Drink",
30+
description: "Recipes, cooking tips, and food inspiration",
31+
imageUrl: "https://picsum.photos/300/150?random=6"
32+
},
33+
{
34+
title: "Home Decor",
35+
description: "Ideas to decorate and style your home",
36+
imageUrl: "https://picsum.photos/300/150?random=7"
37+
},
38+
{
39+
title: "Men's Fashion",
40+
description: "Clothing, accessories and style for men",
41+
imageUrl: "https://picsum.photos/300/150?random=8"
42+
},
43+
{
44+
title: "Women's Fashion",
45+
description: "Clothing, accessories and style for women",
46+
imageUrl: "https://picsum.photos/300/150?random=9"
47+
},
48+
{
49+
title: "Travel",
50+
description: "Destinations, travel tips and vacation inspiration",
51+
imageUrl: "https://picsum.photos/300/150?random=10"
52+
},
53+
{
54+
title: "Technology",
55+
description: "Gadgets, software, and tech innovations",
56+
imageUrl: "https://picsum.photos/300/150?random=11"
57+
},
58+
{
59+
title: "Nature",
60+
description: "Beautiful landscapes, plants, and animals",
61+
imageUrl: "https://picsum.photos/300/150?random=12"
62+
},
63+
{
64+
title: "Photography",
65+
description: "Photography inspiration, tips and techniques",
66+
imageUrl: "https://picsum.photos/300/150?random=13"
67+
}
68+
];
69+
70+
async function main() {
71+
console.log("Starting to seed categories...");
72+
73+
for (const category of categories) {
74+
// Check if category already exists to avoid duplicates
75+
const existing = await prisma.category.findFirst({
76+
where: {
77+
title: {
78+
equals: category.title,
79+
mode: "insensitive"
80+
}
81+
}
82+
});
83+
84+
if (!existing) {
85+
const created = await prisma.category.create({
86+
data: category
87+
});
88+
console.log(`Created category: ${created.title}`);
89+
} else {
90+
console.log(`Category "${category.title}" already exists, skipping`);
91+
}
92+
}
93+
94+
console.log("Category seeding completed!");
95+
}
96+
97+
main()
98+
.catch(e => {
99+
console.error("Error seeding categories:", e);
100+
process.exit(1);
101+
})
102+
.finally(async () => {
103+
await prisma.$disconnect();
104+
process.exit(0);
105+
});

0 commit comments

Comments
 (0)