feat(plugins): seasonality + min-stay (Phase 3.2 + 3.4)

Plugin seasonality :
- Migration : Carbet.seasonalConstraints JSONB nullable
- lib/seasonality.ts : enum Season (DRY|LOW_WATER|WET), currentSeason() helper
  Guyane (juil-sept sèche, oct-nov étiage, déc-juin pluies), parseSeasonalConstraints,
  isCurrentlyOpen, SEASON_META (label/emoji/tone)
- Composant <SeasonBanner /> server, gated par plugin, ajouté dans layout
  au-dessus de tout le contenu — bandeau couleur+emoji+message contextuel

Plugin min-stay :
- Migration : Carbet.minStayNights, maxStayNights, minCapacity nullable
- Composant <StayConstraints /> client, gated par plugin — pill text
  '2 nuits minimum', '2-7 nuits', 'groupe 4+ recommandé'
- Carbet card et fiche enrichies avec les contraintes

Tous deux désactivables : sans le toggle, comportement legacy inchangé.
This commit is contained in:
Claude Integration 2026-05-31 08:50:26 +00:00
parent 4842a44746
commit be2391998d
7 changed files with 196 additions and 1 deletions

View file

@ -16,6 +16,7 @@ import { CarbetGallery } from "../_components/carbet-gallery";
import { ReviewsSection } from "../_components/reviews-section";
import { StarRating } from "../_components/star-rating";
import { AccessTypeBadge } from "@/components/AccessTypeBadge";
import { StayConstraints } from "@/components/StayConstraints";
type PageProps = {
params: Promise<{ slug: string }>;
@ -197,6 +198,18 @@ export default async function PublicCarbetPage({ params }: PageProps) {
{formatCoordinate(carbet.longitude)}
</dd>
</div>
{(carbet.minStayNights || carbet.maxStayNights || carbet.minCapacity) ? (
<div>
<dt className="font-medium text-zinc-500">Séjour</dt>
<dd>
<StayConstraints
minNights={carbet.minStayNights}
maxNights={carbet.maxStayNights}
minCapacity={carbet.minCapacity}
/>
</dd>
</div>
) : null}
<div>
<dt className="font-medium text-zinc-500">Capacité</dt>
<dd>

View file

@ -3,6 +3,7 @@ import { Geist, Geist_Mono, Cormorant_Garamond } from "next/font/google";
import "./globals.css";
import { PluginProvider } from "@/lib/plugins/client";
import { getEnabledPluginKeys, syncPluginsFromRegistry } from "@/lib/plugins/server";
import { SeasonBanner } from "@/components/SeasonBanner";
// Le layout interroge la DB Plugin à chaque request → rendu dynamique forcé.
// Sans ça, le layout (et donc data-theme + enabledKeys passés au client) est
@ -76,7 +77,10 @@ export default async function RootLayout({
data-theme={themeGuyane ? "guyane" : undefined}
className="min-h-full flex flex-col font-sans"
>
<PluginProvider enabledKeys={enabledKeys}>{children}</PluginProvider>
<PluginProvider enabledKeys={enabledKeys}>
<SeasonBanner />
{children}
</PluginProvider>
</body>
</html>
);