feat(plugin): pirogue-providers (Phase 3.3)

Modèle PirogueProvider (id, name, contacts, fleuves, tarif, description)
+ enum TransportMode (OWNER_PROVIDES, SELF_ARRANGE, PARTNER_PROVIDER) sur Carbet
+ relation Carbet → PirogueProvider (nullable, ondelete:SetNull)

Composants :
- PirogueTransportBlock (server, gated par plugin) sur fiche carbet :
  affiche le mode + provider partenaire avec contacts/tarif/description
- Page publique /partenaires-pirogue : liste des partenaires actifs

Seed onEnable :
- 3 partenaires démo (Pirogues du Maroni, Approuague Aventures, Oyapock Frontière)
  avec tarifs estimatifs et fleuves desservis réels
- Attribution aux 6 carbets démo :
  · Awara (Maroni), Maripa (Approuague), Paripou (Oyapock) → PARTNER_PROVIDER
  · Wapa (Comté), Mahury CE → OWNER_PROVIDES
  · Kourou Couleuvre → SELF_ARRANGE

onDisable désactive les partenaires démo et détache les carbets démo.
This commit is contained in:
Claude Integration 2026-05-31 11:29:29 +00:00
parent 8c0b849ad7
commit a174f99eba
9 changed files with 438 additions and 7 deletions

View file

@ -17,6 +17,7 @@ import { ReviewsSection } from "../_components/reviews-section";
import { StarRating } from "../_components/star-rating";
import { AccessTypeBadge } from "@/components/AccessTypeBadge";
import { StayConstraints } from "@/components/StayConstraints";
import { PirogueTransportBlock } from "@/components/PirogueTransportBlock";
type PageProps = {
params: Promise<{ slug: string }>;
@ -137,6 +138,11 @@ export default async function PublicCarbetPage({ params }: PageProps) {
</p>
</section>
<PirogueTransportBlock
transportMode={carbet.transportMode}
provider={carbet.pirogueProvider}
/>
{carbet.amenities.length > 0 ? (
<section className="mt-10">
<h2 className="text-xl font-semibold text-zinc-900">

View file

@ -0,0 +1,88 @@
import { notFound } from "next/navigation";
import { isPluginEnabled } from "@/lib/plugins/server";
import { listActiveProviders } from "@/lib/pirogue-providers";
export const dynamic = "force-dynamic";
export async function generateMetadata() {
return { title: "Partenaires pirogue" };
}
export default async function ProvidersPage() {
if (!(await isPluginEnabled("pirogue-providers"))) notFound();
const providers = await listActiveProviders();
return (
<main className="mx-auto max-w-4xl px-6 py-12 sm:px-8 lg:px-12">
<header className="mb-8">
<span className="text-xs font-semibold uppercase tracking-[0.15em] text-[var(--color-karbe-canopy-700)]">
Transport
</span>
<h1 className="mt-2 font-serif text-4xl font-medium tracking-tight text-[var(--color-karbe-ink)] sm:text-5xl">
Nos partenaires pirogue
</h1>
<p className="mt-3 max-w-2xl text-base leading-relaxed text-[var(--color-karbe-ink)]/75">
Pour les carbets accessibles uniquement par le fleuve, on travaille avec des piroguiers
locaux référencés. Tarifs estimatifs ci-dessous ; le détail de votre trajet est calé
directement avec le partenaire après réservation.
</p>
</header>
{providers.length === 0 ? (
<p className="rounded-xl border border-dashed border-[var(--color-karbe-canopy-100)] bg-[var(--color-karbe-canopy-50)]/40 p-6 text-sm text-[var(--color-karbe-ink)]/70">
Aucun partenaire référencé pour le moment.
</p>
) : (
<ul className="space-y-5">
{providers.map((p) => (
<li
key={p.id}
className="rounded-2xl border border-[var(--color-karbe-canopy-100)] bg-white p-6 shadow-sm"
>
<div className="flex flex-wrap items-baseline justify-between gap-3">
<h2 className="font-serif text-2xl font-medium text-[var(--color-karbe-ink)]">{p.name}</h2>
<div className="flex flex-wrap gap-1.5">
{p.rivers.map((r) => (
<span
key={r}
className="rounded-full bg-[var(--color-karbe-maroni-100)] px-2 py-0.5 text-xs font-medium text-[var(--color-karbe-maroni-700)]"
>
{r}
</span>
))}
</div>
</div>
{p.description ? (
<p className="mt-3 text-sm leading-relaxed text-[var(--color-karbe-ink)]/85">{p.description}</p>
) : null}
{p.pricingNote ? (
<p className="mt-2 italic text-sm text-[var(--color-karbe-ink)]/70">{p.pricingNote}</p>
) : null}
<dl className="mt-4 flex flex-wrap gap-x-6 gap-y-1 text-xs">
{p.contactEmail ? (
<div>
<dt className="inline font-semibold text-[var(--color-karbe-canopy-700)]">Email · </dt>
<dd className="inline">
<a
href={`mailto:${p.contactEmail}`}
className="underline hover:text-[var(--color-karbe-laterite-700)]"
>
{p.contactEmail}
</a>
</dd>
</div>
) : null}
{p.contactPhone ? (
<div>
<dt className="inline font-semibold text-[var(--color-karbe-canopy-700)]">Tél. · </dt>
<dd className="inline">{p.contactPhone}</dd>
</div>
) : null}
</dl>
</li>
))}
</ul>
)}
</main>
);
}