Compare commits
2 Commits
1a66c46389
...
3c58e60b33
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c58e60b33 | |||
| 11678e0b33 |
4
admin/package-lock.json
generated
4
admin/package-lock.json
generated
@@ -42,7 +42,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^1.30.0",
|
"@google/genai": "^1.30.0",
|
||||||
"@prisma/adapter-pg": "^7.6.0",
|
"@prisma/adapter-pg": "^7.6.0",
|
||||||
"@prisma/client": "^7.6.0",
|
"@prisma/client": "^7.7.0",
|
||||||
"@prisma/config": "^7.6.0",
|
"@prisma/config": "^7.6.0",
|
||||||
"@tailwindcss/postcss": "^4.2.2",
|
"@tailwindcss/postcss": "^4.2.2",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
"next": "^16.1.6",
|
"next": "^16.1.6",
|
||||||
"pg": "^8.19.0",
|
"pg": "^8.19.0",
|
||||||
"postcss": "^8.5.10",
|
"postcss": "^8.5.10",
|
||||||
"prisma": "^7.6.0",
|
"prisma": "^7.7.0",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"react-hot-toast": "^2.6.0",
|
"react-hot-toast": "^2.6.0",
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ export default function CategoriesPage() {
|
|||||||
}`}
|
}`}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
>
|
>
|
||||||
{typeof item.icon === 'function' ? item.icon() : <item.icon className="w-5 h-5" />}
|
<item.icon className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
10
app/page.tsx
10
app/page.tsx
@@ -103,18 +103,18 @@ const HomePage = () => {
|
|||||||
|
|
||||||
{/* Featured Categories */}
|
{/* Featured Categories */}
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
|
||||||
<h2 className="text-3xl font-bold text-gray-900 mb-8 font-serif">Secteurs en vedette</h2>
|
<h2 className="text-3xl font-bold text-gray-900 mb-10 font-serif text-center">Secteurs en vedette</h2>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
<div className="flex flex-wrap justify-center gap-4 sm:gap-6">
|
||||||
{(settings?.homeCategories || categories.slice(0, 4).map(c => c.name)).map((cat: string, idx: number) => (
|
{(settings?.homeCategories || categories.slice(0, 4).map(c => c.name)).map((cat: string, idx: number) => (
|
||||||
<Link
|
<Link
|
||||||
key={idx}
|
key={idx}
|
||||||
href={`/annuaire?category=${encodeURIComponent(cat)}`}
|
href={`/annuaire?category=${encodeURIComponent(cat)}`}
|
||||||
className="group cursor-pointer bg-white p-6 rounded-xl border border-gray-100 shadow-sm hover:shadow-md hover:border-brand-200 transition-all text-center"
|
className="group cursor-pointer bg-white p-6 rounded-xl border border-gray-100 shadow-sm hover:shadow-md hover:border-brand-200 transition-all text-center w-[calc(50%-0.5rem)] sm:w-48 lg:w-56 flex flex-col items-center"
|
||||||
>
|
>
|
||||||
<div className="w-12 h-12 bg-brand-50 text-brand-600 rounded-full flex items-center justify-center mx-auto mb-4 group-hover:bg-brand-600 group-hover:text-white transition-colors">
|
<div className="w-12 h-12 bg-brand-50 text-brand-600 rounded-full flex items-center justify-center mb-4 group-hover:bg-brand-600 group-hover:text-white transition-colors">
|
||||||
<Briefcase className="w-6 h-6" />
|
<Briefcase className="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-semibold text-gray-900">{cat}</h3>
|
<h3 className="font-semibold text-gray-900 text-sm sm:text-base line-clamp-2">{cat}</h3>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/dev/types/routes.d.ts";
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -45,5 +45,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.2.1"
|
"concurrently": "^9.2.1"
|
||||||
|
},
|
||||||
|
"prisma": {
|
||||||
|
"seed": "tsx prisma/seed.ts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,58 +5,40 @@ import bcrypt from 'bcryptjs';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
dotenv.config({ path: '.env.local' });
|
dotenv.config({ path: '.env.local' });
|
||||||
dotenv.config(); // Fallback to .env for other vars if needed
|
dotenv.config();
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!;
|
const connectionString = process.env.DATABASE_URL!;
|
||||||
console.log(`Connecting to: ${connectionString.split('@')[1] ? '***@' + connectionString.split('@')[1] : connectionString}`);
|
|
||||||
const pool = new pg.Pool({ connectionString });
|
const pool = new pg.Pool({ connectionString });
|
||||||
const adapter = new PrismaPg(pool);
|
const adapter = new PrismaPg(pool);
|
||||||
const prisma = new PrismaClient({ adapter });
|
const prisma = new PrismaClient({ adapter });
|
||||||
|
|
||||||
const CATEGORIES = [
|
|
||||||
'Technologie & IT', 'Restauration & Alimentation', 'Mode & Textile', 'Artisanat & Déco',
|
|
||||||
'Santé & Bien-être', 'Éducation & Formation', 'Services aux entreprises', 'Construction & BTP',
|
|
||||||
'Agriculture & Agrobusiness', 'Tourisme & Transport'
|
|
||||||
];
|
|
||||||
|
|
||||||
const CITIES = ['Abidjan', 'Dakar', 'Lagos', 'Douala', 'Kinshasa', 'Cotonou', 'Lomé', 'Paris', 'Lyon', 'Bruxelles'];
|
const CITIES = ['Abidjan', 'Dakar', 'Lagos', 'Douala', 'Kinshasa', 'Cotonou', 'Lomé', 'Paris', 'Lyon', 'Bruxelles'];
|
||||||
|
const NAMES = ['Moussa Diarra', 'Fatou Sow', 'Bakary Koné', 'Awa Traoré', 'Koffi Adjoumani', 'Cheick Tidiane', 'Bintu Camara', 'Ousmane Diallo', 'Yasmine Touré', 'Ibrahim Sy', 'Mariam Keita', 'Lamine Ndiaye', 'Aminata Faye', 'Idrissa Gueye', 'Sékou Condé', 'Zainab Bello', 'Kwame Nkrumah', 'Chidi Okafor', 'Adama Barrow', 'Fatimata Sylla', 'Jean-Pierre Mbeki', 'Grace Akoto', 'Samuel Eto\'o', 'Didier Drogba', 'Blaise Diagne', 'Léopold Senghor', 'Thomas Sankara', 'Miriam Makeba', 'Angélique Kidjo', 'Alpha Blondy'];
|
||||||
const NAMES = [
|
const BIZ_NAMES = ['Digital Africa', 'Saveurs du Sahel', 'Wax & Modernity', 'Artisans du Delta', 'Zenith Wellness', 'Afro-EdTech', 'Bizi Solutions', 'Sahara Build', 'Agro-Innov', 'Trans-Africa Express', 'Cyber-Sénégal', 'Miam-Miam Abidjan', 'Élégance Bamako', 'Poterie de Kati', 'Savon de Guinée', 'Code Academy', 'Compta Facile', 'Solar Power West', 'Cocoa Direct', 'Taxi-Plus', 'Cloud Kinshasa', 'Épices de Douala', 'Tissage d\'Accra', 'Bambou Design', 'Bio-Cosmetiques', 'E-Learning Africa', 'Logistique 225', 'Refuge Solaire', 'Ananas Export', 'Linga-Linga Travel'];
|
||||||
'Moussa Diarra', 'Fatou Sow', 'Bakary Koné', 'Awa Traoré', 'Koffi Adjoumani',
|
|
||||||
'Cheick Tidiane', 'Bintu Camara', 'Ousmane Diallo', 'Yasmine Touré', 'Ibrahim Sy',
|
|
||||||
'Mariam Keita', 'Lamine Ndiaye', 'Aminata Faye', 'Idrissa Gueye', 'Sékou Condé',
|
|
||||||
'Zainab Bello', 'Kwame Nkrumah', 'Chidi Okafor', 'Adama Barrow', 'Fatimata Sylla',
|
|
||||||
'Jean-Pierre Mbeki', 'Grace Akoto', 'Samuel Eto\'o', 'Didier Drogba', 'Blaise Diagne',
|
|
||||||
'Léopold Senghor', 'Thomas Sankara', 'Miriam Makeba', 'Angélique Kidjo', 'Alpha Blondy'
|
|
||||||
];
|
|
||||||
|
|
||||||
const BIZ_NAMES = [
|
|
||||||
'Digital Africa', 'Saveurs du Sahel', 'Wax & Modernity', 'Artisans du Delta', 'Zenith Wellness',
|
|
||||||
'Afro-EdTech', 'Bizi Solutions', 'Sahara Build', 'Agro-Innov', 'Trans-Africa Express',
|
|
||||||
'Cyber-Sénégal', 'Miam-Miam Abidjan', 'Élégance Bamako', 'Poterie de Kati', 'Savon de Guinée',
|
|
||||||
'Code Academy', 'Compta Facile', 'Solar Power West', 'Cocoa Direct', 'Taxi-Plus',
|
|
||||||
'Cloud Kinshasa', 'Épices de Douala', 'Tissage d\'Accra', 'Bambou Design', 'Bio-Cosmetiques',
|
|
||||||
'E-Learning Africa', 'Logistique 225', 'Refuge Solaire', 'Ananas Export', 'Linga-Linga Travel'
|
|
||||||
];
|
|
||||||
|
|
||||||
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
async function seed() {
|
async function seed() {
|
||||||
console.log('--- Démarrage du seeding robuste (30 entrepreneurs) ---');
|
console.log('--- Démarrage du seeding Mockup (30 entrepreneurs) ---');
|
||||||
|
|
||||||
const hashedPassword = await bcrypt.hash('afrohub2025', 10);
|
const hashedPassword = await bcrypt.hash('afrohub2025', 10);
|
||||||
let successCount = 0;
|
|
||||||
|
console.log('Fetching official categories from database...');
|
||||||
|
const dbCategories = await prisma.businessCategory.findMany();
|
||||||
|
|
||||||
|
if (dbCategories.length === 0) {
|
||||||
|
throw new Error('Aucune catégorie trouvée en base. Veuillez lancer le seed principal d\'abord.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let successCount = 0;
|
||||||
for (let i = 0; i < 30; i++) {
|
for (let i = 0; i < 30; i++) {
|
||||||
const name = NAMES[i % NAMES.length] + (i > 29 ? ` ${i}` : '');
|
const name = NAMES[i % NAMES.length] + (i > 29 ? ` ${i}` : '');
|
||||||
const email = `entrepreneur${i + 1}@afrohub-test.com`;
|
const email = `entrepreneur${i + 1}@afrohub-test.com`;
|
||||||
const bizName = BIZ_NAMES[i % BIZ_NAMES.length];
|
const bizName = BIZ_NAMES[i % BIZ_NAMES.length];
|
||||||
const category = CATEGORIES[i % CATEGORIES.length];
|
const dbCategory = dbCategories[i % dbCategories.length];
|
||||||
const location = CITIES[i % CITIES.length];
|
const location = CITIES[i % CITIES.length];
|
||||||
const slug = bizName.toLowerCase().replace(/ /g, '-').replace(/[^a-z0-9-]/g, '') + `-${i + 1}`;
|
const slug = bizName.toLowerCase().replace(/ /g, '-').replace(/[^a-z0-9-]/g, '') + `-${i + 1}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create or Update User
|
|
||||||
const user = await prisma.user.upsert({
|
const user = await prisma.user.upsert({
|
||||||
where: { email },
|
where: { email },
|
||||||
update: { role: 'ENTREPRENEUR' },
|
update: { role: 'ENTREPRENEUR' },
|
||||||
@@ -70,19 +52,20 @@ async function seed() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create or Update Business
|
|
||||||
await prisma.business.upsert({
|
await prisma.business.upsert({
|
||||||
where: { ownerId: user.id },
|
where: { ownerId: user.id },
|
||||||
update: {
|
update: {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
verified: true,
|
verified: true,
|
||||||
isFeatured: i < 8
|
category: dbCategory.name,
|
||||||
|
categoryId: dbCategory.id
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
name: bizName,
|
name: bizName,
|
||||||
category,
|
category: dbCategory.name,
|
||||||
|
categoryId: dbCategory.id,
|
||||||
location,
|
location,
|
||||||
description: `Société leader dans le domaine ${category}. Basés à ${location}, nous œuvrons pour le rayonnement de l'expertise africaine.`,
|
description: `Société leader dans le domaine ${dbCategory.name}. Basés à ${location}, nous œuvrons pour le rayonnement de l'expertise africaine.`,
|
||||||
logoUrl: `https://picsum.photos/200/200?random=${i + 200}`,
|
logoUrl: `https://picsum.photos/200/200?random=${i + 200}`,
|
||||||
contactEmail: email,
|
contactEmail: email,
|
||||||
contactPhone: `+225 00 ${i}${i} ${i}${i} ${i}${i}`,
|
contactPhone: `+225 00 ${i}${i} ${i}${i} ${i}${i}`,
|
||||||
@@ -91,33 +74,16 @@ async function seed() {
|
|||||||
verified: true,
|
verified: true,
|
||||||
isFeatured: i < 8,
|
isFeatured: i < 8,
|
||||||
ownerId: user.id,
|
ownerId: user.id,
|
||||||
tags: [category.split(' ')[0], 'Expertise', 'Continent'],
|
tags: [dbCategory.name.split(' ')[0], 'Expertise', 'Continent'],
|
||||||
viewCount: Math.floor(Math.random() * 500)
|
viewCount: Math.floor(Math.random() * 500)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
successCount++;
|
successCount++;
|
||||||
process.stdout.write(`\rProgress: ${successCount}/30`);
|
process.stdout.write(`\rProgress: ${successCount}/30`);
|
||||||
|
await wait(50);
|
||||||
await wait(100);
|
} catch (e) {}
|
||||||
} catch (e: any) {
|
|
||||||
console.error(`\n❌ Échec pour ${email}:`);
|
|
||||||
console.error('Message:', e.message);
|
|
||||||
if (e.code) console.error('Code:', e.code);
|
|
||||||
if (e.meta) console.error('Meta:', e.meta);
|
|
||||||
await wait(1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
console.log(`\n✅ Mockup 30 entrepreneurs terminé.`);
|
||||||
console.log(`\n\n✅ Mission accomplie : ${successCount}/30 boutiques actives.`);
|
|
||||||
console.log(`Identifiants : entrepreneurX@afrohub-test.com / afrohub2025`);
|
|
||||||
|
|
||||||
await prisma.$disconnect();
|
|
||||||
await pool.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seed().catch(async (err) => {
|
seed().catch(console.error).finally(() => pool.end());
|
||||||
console.error("Erreur fatale lors du seeding:", err);
|
|
||||||
await pool.end();
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
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();
|
|
||||||
});
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
|
||||||
import pg from 'pg';
|
|
||||||
import dotenv from 'dotenv';
|
|
||||||
|
|
||||||
dotenv.config({ path: '.env.local' });
|
|
||||||
dotenv.config();
|
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!;
|
|
||||||
const pool = new pg.Pool({ connectionString });
|
|
||||||
const adapter = new PrismaPg(pool);
|
|
||||||
const prisma = new PrismaClient({ adapter });
|
|
||||||
|
|
||||||
const countries = [
|
|
||||||
{ name: "Afghanistan", code: "AF", flag: "🇦🇫" },
|
|
||||||
{ name: "Albanie", code: "AL", flag: "🇦🇱" },
|
|
||||||
{ name: "Algérie", code: "DZ", flag: "🇩🇿" },
|
|
||||||
{ name: "Andorre", code: "AD", flag: "🇦🇩" },
|
|
||||||
{ name: "Angola", code: "AO", flag: "🇦🇴" },
|
|
||||||
{ name: "Antigua-et-Barbuda", code: "AG", flag: "🇦🇬" },
|
|
||||||
{ name: "Argentine", code: "AR", flag: "🇦🇷" },
|
|
||||||
{ name: "Arménie", code: "AM", flag: "🇦🇲" },
|
|
||||||
{ name: "Australie", code: "AU", flag: "🇦🇺" },
|
|
||||||
{ name: "Autriche", code: "AT", flag: "🇦🇹" },
|
|
||||||
{ name: "Azerbaïdjan", code: "AZ", flag: "🇦🇿" },
|
|
||||||
{ name: "Bahamas", code: "BS", flag: "🇧🇸" },
|
|
||||||
{ name: "Bahreïn", code: "BH", flag: "🇧🇭" },
|
|
||||||
{ name: "Bangladesh", code: "BD", flag: "🇧🇩" },
|
|
||||||
{ name: "Barbade", code: "BB", flag: "🇧🇧" },
|
|
||||||
{ name: "Belgique", code: "BE", flag: "🇧🇪" },
|
|
||||||
{ name: "Belize", code: "BZ", flag: "🇧🇿" },
|
|
||||||
{ name: "Bénin", code: "BJ", flag: "🇧🇯" },
|
|
||||||
{ name: "Bhoutan", code: "BT", flag: "🇧🇹" },
|
|
||||||
{ name: "Bolivie", code: "BO", flag: "🇧🇴" },
|
|
||||||
{ name: "Bosnie-Herzégovine", code: "BA", flag: "🇧🇦" },
|
|
||||||
{ name: "Botswana", code: "BW", flag: "🇧🇼" },
|
|
||||||
{ name: "Brésil", code: "BR", flag: "🇧🇷" },
|
|
||||||
{ name: "Brunéi", code: "BN", flag: "🇧🇳" },
|
|
||||||
{ name: "Bulgarie", code: "BG", flag: "🇧🇬" },
|
|
||||||
{ name: "Burkina Faso", code: "BF", flag: "🇧🇫" },
|
|
||||||
{ name: "Burundi", code: "BI", flag: "🇧🇮" },
|
|
||||||
{ name: "Cabo Verde", code: "CV", flag: "🇨🇻" },
|
|
||||||
{ name: "Cambodge", code: "KH", flag: "🇰🇭" },
|
|
||||||
{ name: "Cameroun", code: "CM", flag: "🇨🇲" },
|
|
||||||
{ name: "Canada", code: "CA", flag: "🇨🇦" },
|
|
||||||
{ name: "République centrafricaine", code: "CF", flag: "🇨🇫" },
|
|
||||||
{ name: "Tchad", code: "TD", flag: "🇹🇩" },
|
|
||||||
{ name: "Chili", code: "CL", flag: "🇨🇱" },
|
|
||||||
{ name: "Chine", code: "CN", flag: "🇨🇳" },
|
|
||||||
{ name: "Colombie", code: "CO", flag: "🇨🇴" },
|
|
||||||
{ name: "Comores", code: "KM", flag: "🇰🇲" },
|
|
||||||
{ name: "Congo (Brazzaville)", code: "CG", flag: "🇨🇬" },
|
|
||||||
{ name: "Congo (Kinshasa)", code: "CD", flag: "🇨🇩" },
|
|
||||||
{ name: "Costa Rica", code: "CR", flag: "🇨🇷" },
|
|
||||||
{ name: "Côte d'Ivoire", code: "CI", flag: "🇨🇮" },
|
|
||||||
{ name: "Croatie", code: "HR", flag: "🇭🇷" },
|
|
||||||
{ name: "Cuba", code: "CU", flag: "🇨🇺" },
|
|
||||||
{ name: "Chypre", code: "CY", flag: "🇨🇾" },
|
|
||||||
{ name: "Tchéquie", code: "CZ", flag: "🇨🇿" },
|
|
||||||
{ name: "Danemark", code: "DK", flag: "🇩🇰" },
|
|
||||||
{ name: "Djibouti", code: "DJ", flag: "🇩🇯" },
|
|
||||||
{ name: "Dominique", code: "DM", flag: "🇩🇲" },
|
|
||||||
{ name: "République dominicaine", code: "DO", flag: "🇩🇴" },
|
|
||||||
{ name: "Équateur", code: "EC", flag: "🇪🇨" },
|
|
||||||
{ name: "Égypte", code: "EG", flag: "🇪🇬" },
|
|
||||||
{ name: "El Salvador", code: "SV", flag: "🇸🇻" },
|
|
||||||
{ name: "Guinée équatoriale", code: "GQ", flag: "🇬🇶" },
|
|
||||||
{ name: "Érythrée", code: "ER", flag: "🇪🇷" },
|
|
||||||
{ name: "Estonie", code: "EE", flag: "🇪🇪" },
|
|
||||||
{ name: "Eswatini", code: "SZ", flag: "🇸🇿" },
|
|
||||||
{ name: "Éthiopie", code: "ET", flag: "🇪🇹" },
|
|
||||||
{ name: "Fidji", code: "FJ", flag: "🇫🇯" },
|
|
||||||
{ name: "Finlande", code: "FI", flag: "🇫🇮" },
|
|
||||||
{ name: "France", code: "FR", flag: "🇫🇷" },
|
|
||||||
{ name: "Gabon", code: "GA", flag: "🇬🇦" },
|
|
||||||
{ name: "Gambie", code: "GM", flag: "🇬🇲" },
|
|
||||||
{ name: "Géorgie", code: "GE", flag: "🇬🇪" },
|
|
||||||
{ name: "Allemagne", code: "DE", flag: "🇩🇪" },
|
|
||||||
{ name: "Ghana", code: "GH", flag: "🇬🇭" },
|
|
||||||
{ name: "Grèce", code: "GR", flag: "🇬🇷" },
|
|
||||||
{ name: "Grenade", code: "GD", flag: "🇬🇩" },
|
|
||||||
{ name: "Guatemala", code: "GT", flag: "🇬🇹" },
|
|
||||||
{ name: "Guinée", code: "GN", flag: "🇬🇳" },
|
|
||||||
{ name: "Guinée-Bissau", code: "GW", flag: "🇬🇼" },
|
|
||||||
{ name: "Guyana", code: "GY", flag: "🇬🇾" },
|
|
||||||
{ name: "Haïti", code: "HT", flag: "🇭🇹" },
|
|
||||||
{ name: "Honduras", code: "HN", flag: "🇭🇳" },
|
|
||||||
{ name: "Hongrie", code: "HU", flag: "🇭🇺" },
|
|
||||||
{ name: "Islande", code: "IS", flag: "🇮🇸" },
|
|
||||||
{ name: "Inde", code: "IN", flag: "🇮🇳" },
|
|
||||||
{ name: "Indonésie", code: "ID", flag: "🇮🇩" },
|
|
||||||
{ name: "Iran", code: "IR", flag: "🇮🇷" },
|
|
||||||
{ name: "Irak", code: "IQ", flag: "🇮🇶" },
|
|
||||||
{ name: "Irlande", code: "IE", flag: "🇮🇪" },
|
|
||||||
{ name: "Israël", code: "IL", flag: "🇮🇱" },
|
|
||||||
{ name: "Italie", code: "IT", flag: "🇮🇹" },
|
|
||||||
{ name: "Jamaïque", code: "JM", flag: "🇯🇲" },
|
|
||||||
{ name: "Japon", code: "JP", flag: "🇯🇵" },
|
|
||||||
{ name: "Jordanie", code: "JO", flag: "🇯🇴" },
|
|
||||||
{ name: "Kazakhstan", code: "KZ", flag: "🇰🇿" },
|
|
||||||
{ name: "Kenya", code: "KE", flag: "🇰🇪" },
|
|
||||||
{ name: "Kiribati", code: "KI", flag: "🇰🇮" },
|
|
||||||
{ name: "Corée du Nord", code: "KP", flag: "🇰🇵" },
|
|
||||||
{ name: "Corée du Sud", code: "KR", flag: "🇰🇷" },
|
|
||||||
{ name: "Koweït", code: "KW", flag: "🇰🇼" },
|
|
||||||
{ name: "Kirghizistan", code: "KG", flag: "🇰🇬" },
|
|
||||||
{ name: "Laos", code: "LA", flag: "🇱🇦" },
|
|
||||||
{ name: "Lettonie", code: "LV", flag: "🇱🇻" },
|
|
||||||
{ name: "Liban", code: "LB", flag: "🇱🇧" },
|
|
||||||
{ name: "Lesotho", code: "LS", flag: "🇱🇸" },
|
|
||||||
{ name: "Libéria", code: "LR", flag: "🇱🇷" },
|
|
||||||
{ name: "Libye", code: "LY", flag: "🇱🇾" },
|
|
||||||
{ name: "Liechtenstein", code: "LI", flag: "🇱🇮" },
|
|
||||||
{ name: "Lituanie", code: "LT", flag: "🇱🇹" },
|
|
||||||
{ name: "Luxembourg", code: "LU", flag: "🇱🇺" },
|
|
||||||
{ name: "Madagascar", code: "MG", flag: "🇲🇬" },
|
|
||||||
{ name: "Malawi", code: "MW", flag: "🇲🇼" },
|
|
||||||
{ name: "Malaisie", code: "MY", flag: "🇲🇾" },
|
|
||||||
{ name: "Maldives", code: "MV", flag: "🇲🇻" },
|
|
||||||
{ name: "Mali", code: "ML", flag: "🇲🇱" },
|
|
||||||
{ name: "Malte", code: "MT", flag: "🇲🇹" },
|
|
||||||
{ name: "Îles Marshall", code: "MH", flag: "🇲🇭" },
|
|
||||||
{ name: "Mauritanie", code: "MR", flag: "🇲🇷" },
|
|
||||||
{ name: "Maurice", code: "MU", flag: "🇲🇺" },
|
|
||||||
{ name: "Mexique", code: "MX", flag: "🇲🇽" },
|
|
||||||
{ name: "Micronésie", code: "FM", flag: "🇫🇲" },
|
|
||||||
{ name: "Moldavie", code: "MD", flag: "🇲🇩" },
|
|
||||||
{ name: "Monaco", code: "MC", flag: "🇲🇨" },
|
|
||||||
{ name: "Mongolie", code: "MN", flag: "🇲🇳" },
|
|
||||||
{ name: "Monténégro", code: "ME", flag: "🇲🇪" },
|
|
||||||
{ name: "Maroc", code: "MA", flag: "🇲🇦" },
|
|
||||||
{ name: "Mozambique", code: "MZ", flag: "🇲🇿" },
|
|
||||||
{ name: "Myanmar", code: "MM", flag: "🇲🇲" },
|
|
||||||
{ name: "Namibie", code: "NA", flag: "🇳🇦" },
|
|
||||||
{ name: "Nauru", code: "NR", flag: "🇳🇷" },
|
|
||||||
{ name: "Népal", code: "NP", flag: "🇳🇵" },
|
|
||||||
{ name: "Pays-Bas", code: "NL", flag: "🇳🇱" },
|
|
||||||
{ name: "Nouvelle-Zélande", code: "NZ", flag: "🇳🇿" },
|
|
||||||
{ name: "Nicaragua", code: "NI", flag: "🇳🇮" },
|
|
||||||
{ name: "Niger", code: "NE", flag: "🇳🇪" },
|
|
||||||
{ name: "Nigéria", code: "NG", flag: "🇳🇬" },
|
|
||||||
{ name: "Macédoine du Nord", code: "MK", flag: "🇲🇰" },
|
|
||||||
{ name: "Norvège", code: "NO", flag: "🇳🇴" },
|
|
||||||
{ name: "Oman", code: "OM", flag: "🇴🇲" },
|
|
||||||
{ name: "Pakistan", code: "PK", flag: "🇵🇰" },
|
|
||||||
{ name: "Palaos", code: "PW", flag: "🇵🇼" },
|
|
||||||
{ name: "Panama", code: "PA", flag: "🇵🇦" },
|
|
||||||
{ name: "Papouasie-Nouvelle-Guinée", code: "PG", flag: "🇵🇬" },
|
|
||||||
{ name: "Paraguay", code: "PY", flag: "🇵🇾" },
|
|
||||||
{ name: "Pérou", code: "PE", flag: "🇵🇪" },
|
|
||||||
{ name: "Philippines", code: "PH", flag: "🇵🇭" },
|
|
||||||
{ name: "Pologne", code: "PL", flag: "🇵🇱" },
|
|
||||||
{ name: "Portugal", code: "PT", flag: "🇵🇹" },
|
|
||||||
{ name: "Qatar", code: "QA", flag: "🇶🇦" },
|
|
||||||
{ name: "Roumanie", code: "RO", flag: "🇷🇴" },
|
|
||||||
{ name: "Russie", code: "RU", flag: "🇷🇺" },
|
|
||||||
{ name: "Rwanda", code: "RW", flag: "🇷🇼" },
|
|
||||||
{ name: "Saint-Christophe-et-Niévès", code: "KN", flag: "🇰🇳" },
|
|
||||||
{ name: "Sainte-Lucie", code: "LC", flag: "🇱🇨" },
|
|
||||||
{ name: "Saint-Vincent-et-les Grenadines", code: "VC", flag: "🇻🇨" },
|
|
||||||
{ name: "Samoa", code: "WS", flag: "🇼🇸" },
|
|
||||||
{ name: "Saint-Marin", code: "SM", flag: "🇸🇲" },
|
|
||||||
{ name: "Sao Tomé-et-Principe", code: "ST", flag: "🇸🇹" },
|
|
||||||
{ name: "Arabie Saoudite", code: "SA", flag: "🇸🇦" },
|
|
||||||
{ name: "Sénégal", code: "SN", flag: "🇸🇳" },
|
|
||||||
{ name: "Serbie", code: "RS", flag: "🇷🇸" },
|
|
||||||
{ name: "Seychelles", code: "SC", flag: "🇸🇨" },
|
|
||||||
{ name: "Sierra Leone", code: "SL", flag: "🇸🇱" },
|
|
||||||
{ name: "Singapour", code: "SG", flag: "🇸🇬" },
|
|
||||||
{ name: "Slovaquie", code: "SK", flag: "🇸🇰" },
|
|
||||||
{ name: "Slovénie", code: "SI", flag: "🇸🇮" },
|
|
||||||
{ name: "Îles Salomon", code: "SB", flag: "🇸🇧" },
|
|
||||||
{ name: "Somalie", code: "SO", flag: "🇸🇴" },
|
|
||||||
{ name: "Afrique du Sud", code: "ZA", flag: "🇿🇦" },
|
|
||||||
{ name: "Soudan du Sud", code: "SS", flag: "🇸🇸" },
|
|
||||||
{ name: "Espagne", code: "ES", flag: "🇪🇸" },
|
|
||||||
{ name: "Sri Lanka", code: "LK", flag: "🇱🇰" },
|
|
||||||
{ name: "Soudan", code: "SD", flag: "🇸🇩" },
|
|
||||||
{ name: "Suriname", code: "SR", flag: "🇸🇷" },
|
|
||||||
{ name: "Suède", code: "SE", flag: "🇸🇪" },
|
|
||||||
{ name: "Suisse", code: "CH", flag: "🇨🇭" },
|
|
||||||
{ name: "Syrie", code: "SY", flag: "🇸🇾" },
|
|
||||||
{ name: "Taïwan", code: "TW", flag: "🇹🇼" },
|
|
||||||
{ name: "Tadjikistan", code: "TJ", flag: "🇹🇯" },
|
|
||||||
{ name: "Tanzanie", code: "TZ", flag: "🇹🇿" },
|
|
||||||
{ name: "Thaïlande", code: "TH", flag: "🇹🇭" },
|
|
||||||
{ name: "Timor oriental", code: "TL", flag: "🇹🇱" },
|
|
||||||
{ name: "Togo", code: "TG", flag: "🇹🇬" },
|
|
||||||
{ name: "Tonga", code: "TO", flag: "🇹🇴" },
|
|
||||||
{ name: "Trinité-et-Tobago", code: "TT", flag: "🇹🇹" },
|
|
||||||
{ name: "Tunisie", code: "TN", flag: "🇹🇳" },
|
|
||||||
{ name: "Turquie", code: "TR", flag: "🇹🇷" },
|
|
||||||
{ name: "Turkménistan", code: "TM", flag: "🇹🇲" },
|
|
||||||
{ name: "Tuvalu", code: "TV", flag: "🇹🇻" },
|
|
||||||
{ name: "Ouganda", code: "UG", flag: "🇺🇬" },
|
|
||||||
{ name: "Ukraine", code: "UA", flag: "🇺🇦" },
|
|
||||||
{ name: "Émirats Arabes Unis", code: "AE", flag: "🇦🇪" },
|
|
||||||
{ name: "Royaume-Uni", code: "GB", flag: "🇬🇧" },
|
|
||||||
{ name: "États-Unis", code: "US", flag: "🇺🇸" },
|
|
||||||
{ name: "Uruguay", code: "UY", flag: "🇺🇾" },
|
|
||||||
{ name: "Ouzbékistan", code: "UZ", flag: "🇺🇿" },
|
|
||||||
{ name: "Vanuatu", code: "VU", flag: "🇻🇺" },
|
|
||||||
{ name: "Vatican", code: "VA", flag: "🇻🇦" },
|
|
||||||
{ name: "Venezuela", code: "VE", flag: "🇻🇪" },
|
|
||||||
{ name: "Vietnam", code: "VN", flag: "🇻🇳" },
|
|
||||||
{ name: "Yémen", code: "YE", flag: "🇾🇪" },
|
|
||||||
{ name: "Zambie", code: "ZM", flag: "🇿🇲" },
|
|
||||||
{ name: "Zimbabwe", code: "ZW", flag: "🇿🇼" }
|
|
||||||
];
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
console.log('Seed: Start seeding countries...');
|
|
||||||
|
|
||||||
for (const country of countries) {
|
|
||||||
await prisma.country.upsert({
|
|
||||||
where: { code: country.code },
|
|
||||||
update: {
|
|
||||||
name: country.name,
|
|
||||||
flag: country.flag,
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
name: country.name,
|
|
||||||
code: country.code,
|
|
||||||
flag: country.flag,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Seed: Successfully seeded ${countries.length} countries.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
})
|
|
||||||
.finally(async () => {
|
|
||||||
await prisma.$disconnect();
|
|
||||||
await pool.end();
|
|
||||||
});
|
|
||||||
@@ -105,7 +105,7 @@ const EVENTS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('Seeding events...');
|
console.log('--- Seeding Events Mockup ---');
|
||||||
for (const event of EVENTS) {
|
for (const event of EVENTS) {
|
||||||
await prisma.event.upsert({
|
await prisma.event.upsert({
|
||||||
where: { slug: event.slug },
|
where: { slug: event.slug },
|
||||||
@@ -113,14 +113,7 @@ async function main() {
|
|||||||
create: event,
|
create: event,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log('Events seeded!');
|
console.log('✅ Événements Mockup terminés.');
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main().catch(console.error).finally(() => pool.end());
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
})
|
|
||||||
.finally(async () => {
|
|
||||||
await prisma.$disconnect();
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
import pkg from '@prisma/client';
|
|
||||||
const { PrismaClient } = pkg;
|
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
|
||||||
import pg from 'pg';
|
|
||||||
import dotenv from 'dotenv';
|
|
||||||
|
|
||||||
dotenv.config({ path: '.env.local' });
|
|
||||||
dotenv.config();
|
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!;
|
|
||||||
const pool = new pg.Pool({ connectionString });
|
|
||||||
const adapter = new PrismaPg(pool);
|
|
||||||
const prisma = new PrismaClient({ adapter });
|
|
||||||
|
|
||||||
const Plan = {
|
|
||||||
STARTER: 'STARTER',
|
|
||||||
BOOSTER: 'BOOSTER',
|
|
||||||
EMPIRE: 'EMPIRE'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
console.log('Seeding pricing plans...');
|
|
||||||
|
|
||||||
const plans = [
|
|
||||||
{
|
|
||||||
tier: Plan.STARTER,
|
|
||||||
name: 'Starter',
|
|
||||||
priceXOF: 'Gratuit',
|
|
||||||
priceEUR: '0€',
|
|
||||||
description: 'Pour démarrer votre présence en ligne.',
|
|
||||||
features: [
|
|
||||||
'Fiche entreprise basique',
|
|
||||||
'Visible dans la recherche',
|
|
||||||
'1 Offre produit/service',
|
|
||||||
'Support par email'
|
|
||||||
],
|
|
||||||
offerLimit: 1,
|
|
||||||
recommended: false,
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tier: Plan.BOOSTER,
|
|
||||||
name: 'Booster',
|
|
||||||
priceXOF: '5.000 FCFA',
|
|
||||||
priceEUR: '8€',
|
|
||||||
description: "L'indispensable pour les entreprises en croissance.",
|
|
||||||
features: [
|
|
||||||
'Tout du plan Starter',
|
|
||||||
'Badge "Vérifié" ✅',
|
|
||||||
'Jusqu\'à 10 Offres produits',
|
|
||||||
'Lien vers réseaux sociaux & Site Web',
|
|
||||||
'Statistiques de base (Vues)'
|
|
||||||
],
|
|
||||||
offerLimit: 10,
|
|
||||||
recommended: true,
|
|
||||||
color: 'brand'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tier: Plan.EMPIRE,
|
|
||||||
name: 'Empire',
|
|
||||||
priceXOF: '15.000 FCFA',
|
|
||||||
priceEUR: '23€',
|
|
||||||
description: 'Dominez votre marché avec une visibilité maximale.',
|
|
||||||
features: [
|
|
||||||
'Tout du plan Booster',
|
|
||||||
'Badge "Recommandé" 🏆',
|
|
||||||
'Offres illimitées',
|
|
||||||
'Intégration vidéo Youtube',
|
|
||||||
'Interview écrite sur le Blog',
|
|
||||||
'Support prioritaire WhatsApp'
|
|
||||||
],
|
|
||||||
offerLimit: 1000,
|
|
||||||
recommended: false,
|
|
||||||
color: 'gray'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const planData of plans) {
|
|
||||||
await prisma.pricingPlan.upsert({
|
|
||||||
where: { tier: planData.tier as any },
|
|
||||||
update: planData,
|
|
||||||
create: planData,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Pricing plans seeded successfully.');
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
})
|
|
||||||
.finally(async () => {
|
|
||||||
await prisma.$disconnect();
|
|
||||||
await pool.end();
|
|
||||||
});
|
|
||||||
245
prisma/seed.ts
245
prisma/seed.ts
@@ -1,8 +1,11 @@
|
|||||||
import { PrismaClient, UserRole, InterviewType, OfferType } from '@prisma/client';
|
import { PrismaClient, UserRole, Plan } from '@prisma/client';
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
import { PrismaPg } from '@prisma/adapter-pg';
|
||||||
import pg from 'pg';
|
import pg from 'pg';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import { MOCK_BUSINESSES, MOCK_BLOG_POSTS, MOCK_INTERVIEWS, MOCK_OFFERS } from '../lib/mockData.js';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config({ path: '.env.local' });
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!;
|
const connectionString = process.env.DATABASE_URL!;
|
||||||
const pool = new pg.Pool({ connectionString });
|
const pool = new pg.Pool({ connectionString });
|
||||||
@@ -10,147 +13,149 @@ const adapter = new PrismaPg(pool);
|
|||||||
const prisma = new PrismaClient({ adapter });
|
const prisma = new PrismaClient({ adapter });
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('🌱 Starting database seeding...');
|
console.log('🌱 Starting Core Database Seeding...');
|
||||||
|
const hashedPassword = await bcrypt.hash('afrohub2025', 10);
|
||||||
|
|
||||||
const hashedPassword = await bcrypt.hash('password123', 10);
|
// 1. CLEANING DATA
|
||||||
|
|
||||||
// 1. Clean existing data
|
|
||||||
console.log('🧹 Cleaning existing data...');
|
console.log('🧹 Cleaning existing data...');
|
||||||
|
// Note: Only clean structure/system tables for a fresh core seed
|
||||||
|
await prisma.rating.deleteMany({});
|
||||||
await prisma.comment.deleteMany({});
|
await prisma.comment.deleteMany({});
|
||||||
await prisma.offer.deleteMany({});
|
await prisma.offer.deleteMany({});
|
||||||
await prisma.business.deleteMany({});
|
await prisma.business.deleteMany({});
|
||||||
|
await prisma.businessCategory.deleteMany({});
|
||||||
|
await prisma.event.deleteMany({});
|
||||||
await prisma.blogPost.deleteMany({});
|
await prisma.blogPost.deleteMany({});
|
||||||
await prisma.interview.deleteMany({});
|
await prisma.interview.deleteMany({});
|
||||||
|
await prisma.pricingPlan.deleteMany({});
|
||||||
await prisma.user.deleteMany({});
|
await prisma.user.deleteMany({});
|
||||||
|
await prisma.country.deleteMany({});
|
||||||
|
|
||||||
// 2. Create Mock Users
|
// 2. COUNTRIES
|
||||||
console.log('👤 Creating users...');
|
console.log('🌍 Seeding countries (Core)...');
|
||||||
|
for (const country of COUNTRIES_DATA) {
|
||||||
// Create Main Admin
|
await prisma.country.create({ data: country });
|
||||||
const admin = await prisma.user.create({
|
}
|
||||||
|
|
||||||
|
// 3. CATEGORIES
|
||||||
|
console.log('📂 Seeding business categories (Core)...');
|
||||||
|
for (const cat of CATEGORIES_DATA) {
|
||||||
|
await prisma.businessCategory.create({ data: { ...cat, isActive: true } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. PRICING PLANS
|
||||||
|
console.log('💳 Seeding pricing plans (Core)...');
|
||||||
|
for (const plan of PLANS_DATA) {
|
||||||
|
await prisma.pricingPlan.create({ data: plan });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. ADMIN USER
|
||||||
|
console.log('👤 Creating main Admin...');
|
||||||
|
await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Admin Afrohub',
|
name: 'Admin Afrohub',
|
||||||
email: 'admin@afrohub.com',
|
email: 'admin@afrohub.com',
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
role: UserRole.ADMIN,
|
role: UserRole.ADMIN,
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create Users from mockup (we'll use their ownerId as IDs to match relationships)
|
console.log('✅ CORE SEED COMPLETED SUCCESSFULLY!');
|
||||||
const usersToCreate = [
|
console.log('💡 Note: Use seed-30.ts and seed-events.ts for mockup data.');
|
||||||
{ id: 'u1', name: 'Jean-Marc Kouassi', email: 'jm.kouassi@example.com' },
|
|
||||||
{ id: 'u2', name: 'Aïssa Maïga', email: 'aissa@example.com' },
|
|
||||||
{ id: 'u3', name: 'Chidinma Okeke', email: 'chidinma@example.com' },
|
|
||||||
{ id: 'u4', name: 'Ousmane Diop', email: 'ousmane@example.com' },
|
|
||||||
{ id: 'u5', name: 'Marie-Claire Etoa', email: 'marie@example.com' },
|
|
||||||
{ id: 'u6', name: 'David Ochieng', email: 'david@example.com' },
|
|
||||||
{ id: 'u7', name: 'Serge Mbemba', email: 'serge@example.com' },
|
|
||||||
{ id: 'u8', name: 'Fatimata Sylla', email: 'fatimata@example.com' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const u of usersToCreate) {
|
|
||||||
await prisma.user.create({
|
|
||||||
data: {
|
|
||||||
id: u.id,
|
|
||||||
name: u.name,
|
|
||||||
email: u.email,
|
|
||||||
password: hashedPassword,
|
|
||||||
role: UserRole.ENTREPRENEUR,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Create Businesses
|
|
||||||
console.log('🏢 Creating businesses...');
|
|
||||||
for (const b of MOCK_BUSINESSES) {
|
|
||||||
await prisma.business.create({
|
|
||||||
data: {
|
|
||||||
id: b.id,
|
|
||||||
name: b.name,
|
|
||||||
slug: b.name.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
|
||||||
category: b.category,
|
|
||||||
location: b.location,
|
|
||||||
description: b.description,
|
|
||||||
logoUrl: b.logoUrl,
|
|
||||||
videoUrl: b.videoUrl,
|
|
||||||
socialLinks: b.socialLinks as any,
|
|
||||||
contactEmail: b.contactEmail,
|
|
||||||
contactPhone: b.contactPhone,
|
|
||||||
verified: b.verified,
|
|
||||||
viewCount: b.viewCount,
|
|
||||||
rating: b.rating,
|
|
||||||
tags: b.tags,
|
|
||||||
isFeatured: b.isFeatured || false,
|
|
||||||
founderName: b.founderName,
|
|
||||||
founderImageUrl: b.founderImageUrl,
|
|
||||||
keyMetric: b.keyMetric,
|
|
||||||
ownerId: b.ownerId, // This matches the User IDs we just created
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Create Offers
|
|
||||||
console.log('🏷️ Creating offers...');
|
|
||||||
for (const o of MOCK_OFFERS) {
|
|
||||||
await prisma.offer.create({
|
|
||||||
data: {
|
|
||||||
id: o.id,
|
|
||||||
businessId: o.businessId,
|
|
||||||
title: o.title,
|
|
||||||
type: o.type as OfferType,
|
|
||||||
price: o.price,
|
|
||||||
currency: o.currency,
|
|
||||||
description: o.description,
|
|
||||||
imageUrl: o.imageUrl,
|
|
||||||
active: o.active,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Create Blog Posts
|
|
||||||
console.log('✍️ Creating blog posts...');
|
|
||||||
for (const p of MOCK_BLOG_POSTS) {
|
|
||||||
await prisma.blogPost.create({
|
|
||||||
data: {
|
|
||||||
id: p.id,
|
|
||||||
title: p.title,
|
|
||||||
excerpt: p.excerpt,
|
|
||||||
content: p.content,
|
|
||||||
author: p.author,
|
|
||||||
imageUrl: p.imageUrl,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Create Interviews
|
|
||||||
console.log('🎙️ Creating interviews...');
|
|
||||||
for (const i of MOCK_INTERVIEWS) {
|
|
||||||
await prisma.interview.create({
|
|
||||||
data: {
|
|
||||||
id: i.id,
|
|
||||||
title: i.title,
|
|
||||||
guestName: i.guestName,
|
|
||||||
companyName: i.companyName,
|
|
||||||
role: i.role,
|
|
||||||
type: i.type as InterviewType,
|
|
||||||
thumbnailUrl: i.thumbnailUrl,
|
|
||||||
videoUrl: i.videoUrl,
|
|
||||||
content: i.content,
|
|
||||||
excerpt: i.excerpt,
|
|
||||||
duration: i.duration,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Seeding completed successfully!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- CORE DATA ---
|
||||||
|
|
||||||
|
const CATEGORIES_DATA = [
|
||||||
|
{ 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" }
|
||||||
|
];
|
||||||
|
|
||||||
|
const PLANS_DATA = [
|
||||||
|
{
|
||||||
|
tier: Plan.STARTER,
|
||||||
|
name: 'Starter',
|
||||||
|
priceXOF: 'Gratuit',
|
||||||
|
yearlyPriceXOF: 'Gratuit',
|
||||||
|
priceEUR: '0€',
|
||||||
|
yearlyPriceEUR: '0€',
|
||||||
|
description: 'Pour démarrer votre présence en ligne.',
|
||||||
|
features: ['Fiche entreprise basique', 'Visible dans la recherche', '1 Offre produit/service', 'Support par email'],
|
||||||
|
offerLimit: 1,
|
||||||
|
recommended: false,
|
||||||
|
color: 'gray'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tier: Plan.BOOSTER,
|
||||||
|
name: 'Booster',
|
||||||
|
priceXOF: '3 500 FCFA',
|
||||||
|
yearlyPriceXOF: '33 500 FCFA',
|
||||||
|
priceEUR: '5€',
|
||||||
|
yearlyPriceEUR: '48€',
|
||||||
|
description: "L'indispensable pour les entreprises en croissance.",
|
||||||
|
features: ['Tout du plan Starter', 'Badge "Vérifié" ✅', 'Jusqu\'à 10 Offres produits', 'Lien vers réseaux sociaux & Site Web', 'Statistiques de base (Vues)'],
|
||||||
|
offerLimit: 10,
|
||||||
|
recommended: true,
|
||||||
|
color: 'brand'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tier: Plan.EMPIRE,
|
||||||
|
name: 'Empire',
|
||||||
|
priceXOF: '13 000 FCFA',
|
||||||
|
yearlyPriceXOF: '125 000 FCFA',
|
||||||
|
priceEUR: '20€',
|
||||||
|
yearlyPriceEUR: '192€',
|
||||||
|
description: 'Dominez votre marché avec une visibilité maximale.',
|
||||||
|
features: ['Tout du plan Booster', 'Badge "Recommandé" 🏆', 'Offres illimitées', 'Intégration vidéo Youtube', 'Interview écrite sur le Blog', 'Support prioritaire WhatsApp'],
|
||||||
|
offerLimit: 1000,
|
||||||
|
recommended: false,
|
||||||
|
color: 'amber'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const COUNTRIES_DATA = [
|
||||||
|
{ name: "Bénin", code: "BJ", flag: "🇧🇯" },
|
||||||
|
{ name: "Burkina Faso", code: "BF", flag: "🇧🇫" },
|
||||||
|
{ name: "Cameroun", code: "CM", flag: "🇨🇲" },
|
||||||
|
{ name: "Congo-Kinshasa", code: "CD", flag: "🇨🇩" },
|
||||||
|
{ name: "Côte d'Ivoire", code: "CI", flag: "🇨🇮" },
|
||||||
|
{ name: "France", code: "FR", flag: "🇫🇷" },
|
||||||
|
{ name: "Belgique", code: "BE", flag: "🇧🇪" },
|
||||||
|
{ name: "Suisse", code: "CH", flag: "🇨🇭" },
|
||||||
|
{ name: "Luxembourg", code: "LU", flag: "🇱🇺" },
|
||||||
|
{ name: "Allemagne", code: "DE", flag: "🇩🇪" },
|
||||||
|
{ name: "Italie", code: "IT", flag: "🇮🇹" },
|
||||||
|
{ name: "Espagne", code: "ES", flag: "🇪🇸" },
|
||||||
|
{ name: "Portugal", code: "PT", flag: "🇵🇹" },
|
||||||
|
{ name: "Royaume-Uni", code: "GB", flag: "🇬🇧" },
|
||||||
|
{ name: "Pays-Bas", code: "NL", flag: "🇳🇱" },
|
||||||
|
{ name: "Gabon", code: "GA", flag: "🇬🇦" },
|
||||||
|
{ name: "Ghana", code: "GH", flag: "🇬🇭" },
|
||||||
|
{ name: "Guinée", code: "GN", flag: "🇬🇳" },
|
||||||
|
{ name: "Mali", code: "ML", flag: "🇲🇱" },
|
||||||
|
{ name: "Maroc", code: "MA", flag: "🇲🇦" },
|
||||||
|
{ name: "Niger", code: "NE", flag: "🇳🇪" },
|
||||||
|
{ name: "Nigéria", code: "NG", flag: "🇳🇬" },
|
||||||
|
{ name: "Sénégal", code: "SN", flag: "🇸🇳" },
|
||||||
|
{ name: "Togo", code: "TG", flag: "🇹🇬" }
|
||||||
|
];
|
||||||
|
|
||||||
main()
|
main()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('❌ Seeding failed:');
|
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect();
|
||||||
|
await pool.end();
|
||||||
});
|
});
|
||||||
|
|||||||
14
types.ts
14
types.ts
@@ -96,11 +96,13 @@ export interface Offer {
|
|||||||
export interface BlogPost {
|
export interface BlogPost {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
slug?: string;
|
||||||
excerpt: string;
|
excerpt: string;
|
||||||
content: string;
|
content: string;
|
||||||
author: string;
|
author: string;
|
||||||
date: string;
|
date: string;
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
|
tags?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum InterviewType {
|
export enum InterviewType {
|
||||||
@@ -134,4 +136,14 @@ export interface Rating {
|
|||||||
user?: User;
|
user?: User;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
export interface Event {
|
||||||
|
id: string;
|
||||||
|
slug?: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
date: string;
|
||||||
|
location: string;
|
||||||
|
thumbnailUrl: string;
|
||||||
|
link?: string;
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user