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:
parent
8c0b849ad7
commit
a174f99eba
9 changed files with 438 additions and 7 deletions
|
|
@ -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">
|
||||
|
|
|
|||
88
src/app/partenaires-pirogue/page.tsx
Normal file
88
src/app/partenaires-pirogue/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue