maj url photo + page 404 + gestion programmation d'article
This commit is contained in:
@@ -14,16 +14,21 @@ interface Props {
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
const now = new Date();
|
||||
|
||||
const interview = await prisma.interview.findFirst({
|
||||
where: {
|
||||
OR: [{ id }, { slug: id }]
|
||||
OR: [{ id }, { slug: id }],
|
||||
publishedAt: { lte: now },
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
});
|
||||
|
||||
const event = !interview ? await prisma.event.findFirst({
|
||||
where: {
|
||||
OR: [{ id }, { slug: id }]
|
||||
OR: [{ id }, { slug: id }],
|
||||
publishedAt: { lte: now },
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
}) : null;
|
||||
|
||||
@@ -47,18 +52,23 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
|
||||
export default async function AfroLifeDetailPage({ params }: Props) {
|
||||
const { id } = await params;
|
||||
const now = new Date();
|
||||
|
||||
// 1. Try to find an interview
|
||||
const interview = await prisma.interview.findFirst({
|
||||
where: {
|
||||
OR: [{ id }, { slug: id }]
|
||||
OR: [{ id }, { slug: id }],
|
||||
publishedAt: { lte: now },
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
});
|
||||
|
||||
// 2. If not found, try to find an event
|
||||
const event = !interview ? await prisma.event.findFirst({
|
||||
where: {
|
||||
OR: [{ id }, { slug: id }]
|
||||
OR: [{ id }, { slug: id }],
|
||||
publishedAt: { lte: now },
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
}) : null;
|
||||
|
||||
@@ -157,7 +167,7 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
||||
)}
|
||||
|
||||
{/* Description / Article Content / Event Content */}
|
||||
<div className="prose prose-lg prose-orange max-w-none mx-auto text-gray-600 break-words overflow-hidden">
|
||||
<div className="prose prose-lg prose-orange max-w-none mx-auto text-gray-600">
|
||||
{isEvent ? (
|
||||
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML((event as any).description) }} />
|
||||
) : (
|
||||
@@ -195,4 +205,3 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,17 @@ export default async function AfroLifePage({ searchParams }: Props) {
|
||||
const filter = allowedFilters.includes(rawFilter) ? rawFilter : 'ALL';
|
||||
|
||||
let items: any[] = [];
|
||||
const now = new Date();
|
||||
|
||||
try {
|
||||
if (filter === 'EVENT') {
|
||||
const events = await prisma.event.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: now
|
||||
}
|
||||
},
|
||||
orderBy: { date: 'desc' }
|
||||
});
|
||||
items = events.map(e => ({
|
||||
@@ -34,7 +41,12 @@ export default async function AfroLifePage({ searchParams }: Props) {
|
||||
duration: new Date(e.date).toLocaleDateString('fr-FR')
|
||||
}));
|
||||
} else {
|
||||
const where: any = {};
|
||||
const where: any = {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: now
|
||||
}
|
||||
};
|
||||
if (filter !== 'ALL') {
|
||||
where.type = filter as InterviewType;
|
||||
}
|
||||
@@ -47,6 +59,12 @@ export default async function AfroLifePage({ searchParams }: Props) {
|
||||
// If 'ALL', we might want to also fetch events and mix them
|
||||
if (filter === 'ALL') {
|
||||
const events = await prisma.event.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: now
|
||||
}
|
||||
},
|
||||
orderBy: { date: 'desc' },
|
||||
take: 10
|
||||
});
|
||||
|
||||
@@ -6,6 +6,12 @@ import { generateSlug } from '@/lib/utils'
|
||||
export async function GET() {
|
||||
try {
|
||||
const posts = await prisma.blogPost.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: new Date()
|
||||
}
|
||||
},
|
||||
orderBy: { date: 'desc' },
|
||||
})
|
||||
return NextResponse.json(posts)
|
||||
|
||||
@@ -5,11 +5,6 @@ import { USER_SAFE_SELECT, getAuthUser } from '@/lib/auth-utils'
|
||||
// GET /api/businesses — List all businesses (Mock + DB)
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const user = await getAuthUser(request)
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Authentification requise' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const category = searchParams.get('category')
|
||||
const q = searchParams.get('q')?.toLowerCase()
|
||||
|
||||
@@ -5,6 +5,12 @@ import prisma from '@/lib/prisma'
|
||||
export async function GET() {
|
||||
try {
|
||||
const interviews = await prisma.interview.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: new Date()
|
||||
}
|
||||
},
|
||||
orderBy: { date: 'desc' },
|
||||
})
|
||||
return NextResponse.json(interviews)
|
||||
|
||||
20
app/api/tags/route.ts
Normal file
20
app/api/tags/route.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const blogPosts = await prisma.blogPost.findMany({ select: { tags: true } });
|
||||
const interviews = await prisma.interview.findMany({ select: { tags: true } });
|
||||
const events = await prisma.event.findMany({ select: { tags: true } });
|
||||
const businesses = await prisma.business.findMany({ select: { tags: true } });
|
||||
|
||||
const allTags = new Set<string>();
|
||||
[...blogPosts, ...interviews, ...events, ...businesses].forEach(item => {
|
||||
item.tags.forEach(tag => allTags.add(tag.toLowerCase()));
|
||||
});
|
||||
|
||||
return NextResponse.json(Array.from(allTags).sort());
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Failed to fetch tags' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,11 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
OR: [
|
||||
{ id: id },
|
||||
{ slug: id }
|
||||
]
|
||||
],
|
||||
publishedAt: {
|
||||
lte: new Date()
|
||||
},
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -46,7 +50,11 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
OR: [
|
||||
{ id: id },
|
||||
{ slug: id }
|
||||
]
|
||||
],
|
||||
publishedAt: {
|
||||
lte: new Date()
|
||||
},
|
||||
status: 'PUBLISHED'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -102,7 +110,7 @@ export default async function BlogPostPage({ params }: Props) {
|
||||
</header>
|
||||
|
||||
{/* Content */}
|
||||
<div className="prose prose-lg prose-orange max-w-none text-gray-600 break-words overflow-hidden">
|
||||
<div className="prose prose-lg prose-orange max-w-none text-gray-600">
|
||||
<p className="lead text-xl text-gray-500 font-serif italic mb-6 border-b border-gray-100 pb-6">
|
||||
{post.excerpt}
|
||||
</p>
|
||||
|
||||
@@ -10,6 +10,12 @@ export default async function BlogPage() {
|
||||
|
||||
try {
|
||||
posts = await prisma.blogPost.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: {
|
||||
lte: new Date()
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'desc' }
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -23,4 +23,15 @@ body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
|
||||
.prose {
|
||||
text-align: justify;
|
||||
hyphens: auto;
|
||||
word-break: normal;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
50
app/not-found.tsx
Normal file
50
app/not-found.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Home, ArrowLeft, Search } from 'lucide-react';
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="min-h-screen bg-white flex items-center justify-center px-4 sm:px-6 lg:px-8 py-24">
|
||||
<div className="max-w-md w-full text-center">
|
||||
{/* Animated 404 number */}
|
||||
<div className="relative mb-8">
|
||||
<h1 className="text-9xl font-serif font-black text-gray-100 select-none">404</h1>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<span className="text-4xl md:text-5xl font-serif font-bold text-brand-600">Oups !</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-gray-900 mb-4 font-serif">
|
||||
Page introuvable
|
||||
</h2>
|
||||
|
||||
<p className="text-gray-500 mb-10 text-lg">
|
||||
Il semblerait que le chemin que vous avez emprunté n'existe pas ou a été déplacé.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-full text-white bg-brand-600 hover:bg-brand-700 shadow-lg hover:shadow-xl transition-all"
|
||||
>
|
||||
<Home className="w-5 h-5 mr-2" />
|
||||
Retour à l'accueil
|
||||
</Link>
|
||||
<Link
|
||||
href="/annuaire"
|
||||
className="inline-flex items-center justify-center px-6 py-3 border border-gray-200 text-base font-medium rounded-full text-gray-700 bg-white hover:bg-gray-50 shadow-sm transition-all"
|
||||
>
|
||||
<Search className="w-5 h-5 mr-2" />
|
||||
Explorer l'annuaire
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 pt-12 border-t border-gray-100">
|
||||
<p className="text-sm text-gray-400 italic">
|
||||
"L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -62,6 +62,10 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
|
||||
// 3. Fetch all blog posts
|
||||
const blogPosts = await prisma.blogPost.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: { lte: new Date() }
|
||||
},
|
||||
select: { id: true, slug: true, updatedAt: true },
|
||||
});
|
||||
|
||||
@@ -74,6 +78,10 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
|
||||
// 4. Fetch all Afro Life (Interviews)
|
||||
const interviews = await prisma.interview.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: { lte: new Date() }
|
||||
},
|
||||
select: { id: true, slug: true, updatedAt: true },
|
||||
});
|
||||
|
||||
@@ -84,7 +92,23 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
priority: 0.7,
|
||||
}));
|
||||
|
||||
return [...staticRoutes, ...businessRoutes, ...blogRoutes, ...afroLifeRoutes];
|
||||
// 5. Fetch all Events
|
||||
const events = await prisma.event.findMany({
|
||||
where: {
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: { lte: new Date() }
|
||||
},
|
||||
select: { id: true, slug: true, updatedAt: true },
|
||||
});
|
||||
|
||||
const eventRoutes = events.map((event) => ({
|
||||
url: `${baseUrl}/afrolife/${event.slug || event.id}`,
|
||||
lastModified: event.updatedAt,
|
||||
changeFrequency: 'monthly' as const,
|
||||
priority: 0.7,
|
||||
}));
|
||||
|
||||
return [...staticRoutes, ...businessRoutes, ...blogRoutes, ...afroLifeRoutes, ...eventRoutes];
|
||||
} catch (error) {
|
||||
console.error("Error generating sitemap:", error);
|
||||
// Fallback to only static routes if DB connection fails
|
||||
|
||||
Reference in New Issue
Block a user