diff --git a/src/app/adherents/[id]/page.tsx b/src/app/adherents/[id]/page.tsx new file mode 100644 index 0000000..ca4d5a1 --- /dev/null +++ b/src/app/adherents/[id]/page.tsx @@ -0,0 +1,332 @@ +import Link from "next/link"; +import { notFound } from "next/navigation"; +import type { Metadata } from "next"; +import { Sparkle } from "@/components/Sparkle"; +import { getMemberLivePromotions, getPublicMember } from "@/lib/queries"; + +export const dynamic = "force-dynamic"; + +const STRIPE_WARM = + "repeating-linear-gradient(45deg,#efe9da,#efe9da 12px,#e6ddc9 12px,#e6ddc9 24px)"; + +function badgeColor(badge: string | null) { + if (!badge) return "#1f8a5b"; + return badge.includes("%") ? "#d8472b" : "#1f8a5b"; +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ id: string }>; +}): Promise { + const { id } = await params; + const member = await getPublicMember(Number(id)); + if (!member) return { title: "Adhérent — Plein R" }; + return { + title: `${member.name} — Plein R`, + description: member.description ?? undefined, + }; +} + +export default async function FicheAdherentPage({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + const memberId = Number(id); + if (!memberId) notFound(); + + const member = await getPublicMember(memberId); + if (!member || member.status !== "active") notFound(); + + const promos = await getMemberLivePromotions(memberId); + const accent = member.accent ?? "#E0A63C"; + const location = [member.address, member.city].filter(Boolean).join(" · "); + + return ( +
+ {/* header */} +
+ + {/* eslint-disable-next-line @next/next/no-img-element */} + Plein R + + Plein R + + + +
+ +
+
+ + ← Retour à l'annuaire + +
+ + {/* hero card */} +
+ + + + {/* vitrine photo */} +
+ {!member.logoUrl && ( + + photo vitrine + + )} +
+ + {/* info */} +
+ {member.categoryLabel && ( + + {member.categoryLabel} + + )} +

+ {member.name} +

+ {location && ( +
+ + {location} +
+ )} + {member.description && ( +

+ {member.description} +

+ )} +
+ {member.email && ( + + Contacter + + )} + {promos.length > 0 && ( + + Voir les promotions + + )} +
+
+
+ + {/* promotions */} +
+

+ Promotions en cours +

+ + {promos.length === 0 ? ( +
+ Cet adhérent n'a pas de promotion en cours pour le moment. +
+ ) : ( +
+ {promos.map((p) => ( +
+
+ {!p.imageUrl && ( + + photo de l'offre + + )} + {p.badge && ( + + {p.badge} + + )} + {p.category && ( + + {p.category} + + )} +
+
+

+ {p.title} +

+

+ {p.text} +

+ {p.validUntil && ( +
+ {p.validUntil} +
+ )} +
+
+ ))} +
+ )} +
+
+ + {/* footer */} +
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + Plein R + + Plein R + +
+
+ contact@plein-r.fr · Bassin de Pompey +
+ Réseau · Rencontre · Réussite +
+
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 89321ca..151d821 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -470,10 +470,11 @@ export default async function AccueilPage() {
{highlighted.map((m, i) => ( -
-
+ ))}
diff --git a/src/lib/queries.ts b/src/lib/queries.ts index 94be7d2..0be7353 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -44,6 +44,43 @@ export async function getLivePromotions(limit = 6) { return rows; } +export async function getPublicMember(id: number) { + const [m] = await db + .select({ + id: members.id, + name: members.name, + email: members.email, + description: members.description, + city: members.city, + address: members.address, + status: members.status, + logoUrl: members.logoUrl, + categoryLabel: categories.label, + accent: categories.accent, + tint: categories.tint, + }) + .from(members) + .leftJoin(categories, eq(members.categoryId, categories.id)) + .where(eq(members.id, id)); + return m ?? null; +} + +export async function getMemberLivePromotions(memberId: number) { + return db + .select({ + id: promotions.id, + title: promotions.title, + text: promotions.text, + category: promotions.category, + badge: promotions.badge, + imageUrl: promotions.imageUrl, + validUntil: promotions.validUntil, + }) + .from(promotions) + .where(and(eq(promotions.memberId, memberId), eq(promotions.status, "live"))) + .orderBy(desc(promotions.createdAt)); +} + export async function getHighlightedMembers(limit = 3) { const rows = await db .select({