Files
afrov2/app/api/businesses/route.ts
2026-04-23 14:40:50 +02:00

164 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextRequest, NextResponse } from 'next/server'
import prisma from '@/lib/prisma'
// GET /api/businesses — List all businesses (Mock + DB)
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const category = searchParams.get('category')
const q = searchParams.get('q')?.toLowerCase()
const featured = searchParams.get('featured')
const countryId = searchParams.get('countryId')
// 1. Fetch from Database
const where: any = {
isActive: true,
isSuspended: false,
owner: {
isSuspended: false
}
}
if (category && category !== 'All') {
// Robust check: IDs are usually alphanumeric and long, without spaces or special chars
// Names like "Agriculture & Agrobusiness" have spaces or special chars.
const isId = /^[a-z0-9-]+$/.test(category) && category.length > 20;
if (isId) {
where.categoryId = category
} else {
where.category = category
}
}
if (featured === 'true') where.isFeatured = true
if (countryId) where.countryId = countryId
if (q) {
where.OR = [
{ name: { contains: q, mode: 'insensitive' } },
{ description: { contains: q, mode: 'insensitive' } },
// Simplified tags check
{ tags: { has: q } }
]
}
const dbBusinesses = await prisma.business.findMany({
where,
include: { owner: true, offers: true },
orderBy: { createdAt: 'desc' },
})
// 2. Return DB results
return NextResponse.json(dbBusinesses)
} catch (error) {
console.error('GET /api/businesses error:', error)
return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 })
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const headerUserId = request.headers.get('x-user-id')
const { ownerId: bodyOwnerId, ...data } = body
const ownerId = bodyOwnerId || headerUserId
if (!ownerId) {
return NextResponse.json({ error: 'ownerId est requis (via body ou x-user-id header)' }, { status: 400 })
}
// 1. Sanitize & Validate data
const cleanData: any = {
name: data.name || "",
slug: data.slug || null,
category: data.category || "Autre",
categoryId: (data.categoryId && data.categoryId !== 'Autre') ? data.categoryId : null,
suggestedCategory: data.suggestedCategory || null,
location: data.location || "",
countryId: data.countryId || null,
city: data.city || "",
description: data.description || "",
logoUrl: data.logoUrl || "https://picsum.photos/200/200?random=default",
coverUrl: data.coverUrl || null,
coverPosition: data.coverPosition || "50% 50%",
coverZoom: data.coverZoom ? parseFloat(data.coverZoom) : 1.0,
videoUrl: data.videoUrl || null,
contactEmail: data.contactEmail || "",
contactPhone: data.contactPhone || null,
websiteUrl: data.websiteUrl || null,
socialLinks: data.socialLinks || {},
showEmail: data.showEmail ?? true,
showPhone: data.showPhone ?? true,
showSocials: data.showSocials ?? true,
verified: data.verified ?? false,
viewCount: data.viewCount ?? 0,
rating: data.rating ?? 0,
tags: Array.isArray(data.tags) ? data.tags : [],
isFeatured: data.isFeatured ?? false,
founderName: data.founderName || null,
founderImageUrl: data.founderImageUrl || null,
keyMetric: data.keyMetric || null,
}
// 1b. Calculate isActive based on mandatory fields
const isNameOk = cleanData.name && cleanData.name !== "Nouvelle Entreprise";
const isDescOk = cleanData.description && cleanData.description.length >= 20;
const isLocOk = (cleanData.countryId && cleanData.city) || (cleanData.location && cleanData.location !== "Ma Ville");
const isEmailOk = !!cleanData.contactEmail;
const isPhoneOk = !!cleanData.contactPhone;
cleanData.isActive = !!(isNameOk && isDescOk && isLocOk && isEmailOk && isPhoneOk);
// 2. Slug Uniqueness Check
if (cleanData.slug) {
const slugConflict = await prisma.business.findFirst({
where: {
slug: cleanData.slug,
NOT: { ownerId: ownerId } // Important: allow the owner to keep their own slug
}
});
if (slugConflict) {
return NextResponse.json({
error: `Le lien personnalisé "${cleanData.slug}" est déjà utilisé par une autre entreprise. Veuillez en choisir un autre.`
}, { status: 400 });
}
}
let business;
const existing = await prisma.business.findFirst({
where: { ownerId: ownerId }
});
console.log('Upserting business for ownerId:', ownerId, 'Existing:', !!existing);
if (existing) {
// When updating, we use the sanitized cleanData and the existing record's id
business = await prisma.business.update({
where: { id: existing.id },
data: cleanData,
include: { owner: true }
});
} else {
// When creating, we add the ownerId to the sanitized cleanData
business = await prisma.business.create({
data: {
...cleanData,
ownerId: ownerId
},
include: { owner: true }
});
// Automatic role upgrade
await prisma.user.update({
where: { id: ownerId },
data: { role: 'ENTREPRENEUR' }
});
}
console.log('Business saved successfully:', business.id);
return NextResponse.json(business, { status: 200 })
} catch (error) {
console.error('POST /api/businesses error:', error)
return NextResponse.json({ error: 'Erreur lors de lenregistrement' }, { status: 500 })
}
}