feat: implement home page, business directory, and administrative management features with updated schema and API routes
Some checks failed
Build and Push App / build (push) Failing after 51s

This commit is contained in:
2026-04-23 14:40:50 +02:00
parent 88e4c13b9f
commit e6310f30de
23 changed files with 1124 additions and 222 deletions

View File

@@ -18,10 +18,10 @@ model User {
updatedAt DateTime @updatedAt
bio String?
location String?
countryId String?
phone String?
isSuspended Boolean @default(false)
suspensionReason String?
countryId String?
businesses Business?
comments Comment[]
conversations ConversationParticipant[]
@@ -35,7 +35,10 @@ model Business {
id String @id @default(uuid())
name String
category String
suggestedCategory String?
location String
countryId String?
city String?
description String
logoUrl String
coverUrl String?
@@ -66,26 +69,37 @@ model Business {
isSuspended Boolean @default(false)
suspensionReason String?
plan Plan @default(STARTER)
city String?
countryId String?
country Country? @relation(fields: [countryId], references: [id])
owner User @relation(fields: [ownerId], references: [id])
comments Comment[]
conversations Conversation[]
offers Offer[]
ratings Rating[]
country Country? @relation(fields: [countryId], references: [id])
categoryRef BusinessCategory? @relation(fields: [categoryId], references: [id])
categoryId String?
}
model BusinessCategory {
id String @id @default(uuid())
name String @unique
slug String @unique
icon String? // Lucide icon name
isActive Boolean @default(true)
businesses Business[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Country {
id String @id @default(uuid())
name String @unique
code String @unique
flag String?
code String @unique // ISO alpha-2
flag String? // Emoji or URL
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
businesses Business[]
users User[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model PricingPlan {
@@ -93,7 +107,9 @@ model PricingPlan {
tier Plan @unique
name String
priceXOF String
yearlyPriceXOF String?
priceEUR String
yearlyPriceEUR String?
description String
features String[]
offerLimit Int @default(1)
@@ -172,34 +188,40 @@ model AnalyticsEvent {
label String?
value Float?
metadata Json?
createdAt DateTime @default(now())
browser String?
city String?
country String?
device String?
ip String?
country String?
city String?
browser String?
os String?
device String?
referrer String?
userId String?
createdAt DateTime @default(now())
}
model Rating {
id String @id @default(uuid())
id String @id @default(uuid())
value Int
userId String
businessId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
comment String?
reply String?
replyAt DateTime?
status RatingStatus @default(PENDING)
business Business @relation(fields: [businessId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
businessId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
business Business @relation(fields: [businessId], references: [id], onDelete: Cascade)
@@unique([userId, businessId])
}
enum RatingStatus {
PENDING
APPROVED
REJECTED
}
model Conversation {
id String @id @default(uuid())
businessId String
@@ -244,6 +266,34 @@ model MessageReport {
reporter User @relation(fields: [reporterId], references: [id], onDelete: Cascade)
}
enum ReportStatus {
PENDING
RESOLVED
DISMISSED
}
enum UserRole {
VISITOR
ENTREPRENEUR
ADMIN
}
enum Plan {
STARTER
BOOSTER
EMPIRE
}
enum OfferType {
PRODUCT
SERVICE
}
enum InterviewType {
VIDEO
ARTICLE
}
model SiteSetting {
id String @id @default("singleton")
siteName String @default("Afrohub")
@@ -267,39 +317,6 @@ model SiteSetting {
updatedAt DateTime @updatedAt
}
enum Plan {
STARTER
BOOSTER
EMPIRE
}
enum RatingStatus {
PENDING
APPROVED
REJECTED
}
enum ReportStatus {
PENDING
RESOLVED
DISMISSED
}
enum UserRole {
VISITOR
ENTREPRENEUR
ADMIN
}
enum OfferType {
PRODUCT
SERVICE
}
enum InterviewType {
VIDEO
ARTICLE
}
model LegalDocument {
id String @id @default(uuid())
type String @unique // 'CGU' or 'CGV'

52
prisma/seed-categories.ts Normal file
View File

@@ -0,0 +1,52 @@
import { PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import pg from 'pg';
import { config } from 'dotenv';
config();
config({ path: '.env.local', override: true });
const connectionString = process.env.DATABASE_URL!;
const pool = new pg.Pool({ connectionString });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
const CATEGORIES = [
{ name: "Technologie & IT", slug: "technologie-it" },
{ name: "Agriculture & Agrobusiness", slug: "agriculture-agrobusiness" },
{ name: "Mode & Textile", slug: "mode-textile" },
{ name: "Cosmétique & Beauté", slug: "cosmetique-beaute" },
{ name: "Services aux entreprises", slug: "services-entreprises" },
{ name: "Restauration & Alimentation", slug: "restauration-alimentation" },
{ name: "Construction & BTP", slug: "construction-btp" },
{ name: "Éducation & Formation", slug: "education-formation" },
{ name: "Santé & Bien-être", slug: "sante-bien-etre" },
{ name: "Artisanat & Déco", slug: "artisanat-deco" },
{ name: "Tourisme & Loisirs", slug: "tourisme-loisirs" },
{ name: "Finance & Assurance", slug: "finance-assurance" }
];
async function main() {
console.log('Seeding categories...');
for (const cat of CATEGORIES) {
await prisma.businessCategory.upsert({
where: { name: cat.name },
update: {},
create: {
name: cat.name,
slug: cat.slug,
isActive: true
},
});
}
console.log('Categories seeded!');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});

126
prisma/seed-events.ts Normal file
View File

@@ -0,0 +1,126 @@
import { PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import pg from 'pg';
import { config } from 'dotenv';
config();
config({ path: '.env.local', override: true });
const connectionString = process.env.DATABASE_URL!;
const pool = new pg.Pool({ connectionString });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
const EVENTS = [
{
title: "Forum de l'Entrepreneuriat Africain 2026",
slug: "forum-entrepreneuriat-africain-2026",
description: "Le plus grand rassemblement d'entrepreneurs africains pour discuter des opportunités de croissance et de financement.",
date: new Date("2026-02-15T09:00:00Z"),
location: "Abidjan, Côte d'Ivoire",
thumbnailUrl: "https://images.unsplash.com/photo-1540575861501-7ad05823c28b?auto=format&fit=crop&q=80&w=1200",
tags: ["Entrepreneuriat", "Networking", "Abidjan"],
},
{
title: "Tech Summit Dakar 2026",
slug: "tech-summit-dakar-2026",
description: "Découvrez les dernières innovations technologiques et rencontrez les startups les plus prometteuses du Sénégal.",
date: new Date("2026-03-10T10:00:00Z"),
location: "Dakar, Sénégal",
thumbnailUrl: "https://images.unsplash.com/photo-1505373877841-8d25f7d46678?auto=format&fit=crop&q=80&w=1200",
tags: ["Tech", "Innovation", "Dakar"],
},
{
title: "Salon de l'Agrobusiness Africain",
slug: "salon-agrobusiness-africain-2026",
description: "Exploration des nouvelles techniques agricoles et des opportunités de transformation locale.",
date: new Date("2026-05-20T08:30:00Z"),
location: "Nairobi, Kenya",
thumbnailUrl: "https://images.unsplash.com/photo-1523348837708-15d4a09cfac2?auto=format&fit=crop&q=80&w=1200",
tags: ["Agriculture", "Agrobusiness", "Nairobi"],
},
{
title: "Conférence sur l'Économie Numérique",
slug: "conference-economie-numerique-2026",
description: "Vers une accélération de la digitalisation des services en Afrique centrale.",
date: new Date("2026-06-15T09:00:00Z"),
location: "Douala, Cameroun",
thumbnailUrl: "https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&q=80&w=1200",
tags: ["Digital", "Économie", "Douala"],
},
{
title: "Afro-Invest 2026",
slug: "afro-invest-2026",
description: "Rencontre entre investisseurs internationaux et porteurs de projets africains.",
date: new Date("2026-08-05T14:00:00Z"),
location: "Lagos, Nigeria",
thumbnailUrl: "https://images.unsplash.com/photo-1559136555-9303baea8ebd?auto=format&fit=crop&q=80&w=1200",
tags: ["Investissement", "Finance", "Lagos"],
},
{
title: "Sommet du Tourisme Durable",
slug: "sommet-tourisme-durable-2026",
description: "Promotion des destinations africaines à travers un tourisme respectueux de l'environnement.",
date: new Date("2026-09-22T09:00:00Z"),
location: "Cape Town, Afrique du Sud",
thumbnailUrl: "https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&q=80&w=1200",
tags: ["Tourisme", "Durable", "Cape Town"],
},
{
title: "Salon de la Mode et du Design Africain",
slug: "salon-mode-design-africain-2026",
description: "Célébration des créateurs locaux et de l'artisanat de luxe.",
date: new Date("2026-10-12T11:00:00Z"),
location: "Accra, Ghana",
thumbnailUrl: "https://images.unsplash.com/photo-1445205170230-053b83016050?auto=format&fit=crop&q=80&w=1200",
tags: ["Mode", "Design", "Accra"],
},
{
title: "Forum de l'Énergie Renouvelable",
slug: "forum-energie-renouvelable-2026",
description: "Solutions énergétiques pour l'Afrique de demain.",
date: new Date("2026-11-08T09:30:00Z"),
location: "Casablanca, Maroc",
thumbnailUrl: "https://images.unsplash.com/photo-1473341304170-971dccb5ac1e?auto=format&fit=crop&q=80&w=1200",
tags: ["Énergie", "Solaire", "Casablanca"],
},
{
title: "Afro-Education Summit",
slug: "afro-education-summit-2026",
description: "L'avenir de l'éducation et de la formation professionnelle en Afrique.",
date: new Date("2026-12-05T09:00:00Z"),
location: "Kigali, Rwanda",
thumbnailUrl: "https://images.unsplash.com/photo-1524178232363-1fb2b075b655?auto=format&fit=crop&q=80&w=1200",
tags: ["Éducation", "Kigali"],
},
{
title: "Gala de fin d'année des Entrepreneurs",
slug: "gala-entrepreneurs-2026",
description: "Soirée de prestige pour célébrer les réussites entrepreneuriales de l'année.",
date: new Date("2026-12-20T20:00:00Z"),
location: "Abidjan, Côte d'Ivoire",
thumbnailUrl: "https://images.unsplash.com/photo-1519671482749-fd09be7ccebf?auto=format&fit=crop&q=80&w=1200",
tags: ["Gala", "Célébration", "Abidjan"],
},
];
async function main() {
console.log('Seeding events...');
for (const event of EVENTS) {
await prisma.event.upsert({
where: { slug: event.slug },
update: event,
create: event,
});
}
console.log('Events seeded!');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});