karbe/src/components/SiteHeader.tsx
Ubuntu 5607a51980
Some checks failed
CI / test (pull_request) Failing after 1m10s
feat(rental): Sprint E — emails + plugin toggle + tests
3 nouveaux templates email (best-effort, dry-run sans Resend) :
- sendRentalRequestedTenant : récap de demande au locataire (par RB)
- sendRentalRequestedProvider : nouvelle demande au prestataire
- sendRentalConfirmed : confirmation paiement reçu

Branchements :
- POST /api/rentals/checkout : envoie tenant + provider après création
  des RentalBooking (PENDING), catch global pour ne pas bloquer
- Webhook Stripe rental-bundle : envoie sendRentalConfirmed à chaque
  locataire après update CONFIRMED+SUCCEEDED

Plugin gear-rental :
- Ajout au registry (catégorie business)
- layout.tsx /materiel + /espace-prestataire avec requirePluginOr404
- requirePluginOr404 dans /panier et /mes-locations
- isPluginEnabled guard dans POST /api/rentals/checkout (404 si off)
- SiteHeader masque liens Matériel / Mes locations / Espace prestataire
  + CartBadge si plugin désactivé
- CompleteYourStay renvoie null si plugin désactivé
Décision admin → activable depuis /admin/plugins comme tous les autres.

Tests vitest (tests/lib/rentals.test.ts, 16 tests) :
- diffDays (mêmes dates, 1 nuit, 7 jours, négatif)
- parseCart (null/garbage/schéma invalide/valide/format date)
- serializeCart (updatedAt, roundtrip)
- commission formula (0%, 15%, arrondi centime)
- availability arithmetic (totalQty libre, soustractions, plancher 0)

53 tests pass total. Build OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 08:49:39 +00:00

102 lines
3.9 KiB
TypeScript

/**
* Header global affiché sur toutes les pages PUBLIQUES (hors /admin qui a son
* propre shell). Charge la session côté serveur pour adapter les liens.
*/
import Link from "next/link";
import { auth } from "@/auth";
import { UserRole } from "@/generated/prisma/enums";
import { isPluginEnabled } from "@/lib/plugins/server";
import { CartBadge } from "./CartBadge";
import { SignOutButton } from "./SignOutButton";
export async function SiteHeader() {
const session = await auth();
const u = session?.user;
const isAdmin = u?.role === UserRole.ADMIN;
const isOwner = u?.role === UserRole.OWNER || isAdmin;
const isRentalProvider = u?.role === UserRole.RENTAL_PROVIDER || isAdmin;
const rentalEnabled = await isPluginEnabled("gear-rental");
return (
<header className="sticky top-0 z-30 border-b border-zinc-200 bg-white/85 backdrop-blur supports-[backdrop-filter]:bg-white/70">
<div className="mx-auto flex h-12 max-w-7xl items-center justify-between gap-4 px-4">
<Link href="/" className="flex items-center gap-2 text-base font-semibold text-zinc-900">
<span className="inline-flex h-6 w-6 items-center justify-center rounded-md bg-emerald-600 text-xs font-bold text-white">
K
</span>
Karbé
</Link>
<nav className="hidden items-center gap-5 text-sm text-zinc-700 sm:flex">
<Link href="/decouvrir" className="hover:text-zinc-900">
Au fil de l&apos;eau
</Link>
<Link href="/carbets" className="hover:text-zinc-900">
Catalogue
</Link>
{rentalEnabled ? (
<Link href="/materiel" className="hover:text-zinc-900">
Matériel
</Link>
) : null}
</nav>
<div className="flex items-center gap-3 text-sm">
{rentalEnabled ? <CartBadge /> : null}
{u ? (
<>
<Link href="/mes-favoris" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Favoris
</Link>
<Link href="/mes-reservations" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Mes réservations
</Link>
{rentalEnabled ? (
<Link href="/mes-locations" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Mes locations
</Link>
) : null}
<Link href="/mon-compte" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Mon compte
</Link>
{isOwner ? (
<Link href="/espace-hote" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Espace hôte
</Link>
) : null}
{isRentalProvider && rentalEnabled ? (
<Link href="/espace-prestataire" className="hidden text-zinc-700 hover:text-zinc-900 sm:inline">
Espace prestataire
</Link>
) : null}
{isAdmin ? (
<Link href="/admin" className="hidden rounded-md bg-zinc-900 px-2.5 py-1 text-xs font-semibold text-white hover:bg-zinc-800 sm:inline-block">
Admin
</Link>
) : null}
<span className="hidden max-w-[14ch] truncate text-xs text-zinc-500 md:inline" title={u.email ?? ""}>
{u.name || u.email}
</span>
<SignOutButton />
</>
) : (
<>
<Link href="/connexion" className="text-zinc-700 hover:text-zinc-900">
Connexion
</Link>
<Link
href="/inscription"
className="rounded-md bg-zinc-900 px-3 py-1 text-xs font-semibold text-white hover:bg-zinc-800"
>
Créer un compte
</Link>
</>
)}
</div>
</div>
</header>
);
}