164 lines
6.4 KiB
TypeScript
164 lines
6.4 KiB
TypeScript
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 l’enregistrement' }, { status: 500 })
|
||
}
|
||
}
|