diff --git a/src/app/admin/carbets/[id]/page.tsx b/src/app/admin/carbets/[id]/page.tsx index 7799bef..bf7a972 100644 --- a/src/app/admin/carbets/[id]/page.tsx +++ b/src/app/admin/carbets/[id]/page.tsx @@ -94,6 +94,10 @@ export default async function EditCarbetPage({ params }: PageProps) { capacity: carbet.capacity, nightlyPrice: carbet.nightlyPrice.toString(), accessType: carbet.accessType, + roadAccess: carbet.roadAccess, + electricity: carbet.electricity, + gsmAtCarbet: carbet.gsmAtCarbet, + gsmExitDistanceKm: carbet.gsmExitDistanceKm !== null ? carbet.gsmExitDistanceKm.toString() : null, roadAccessNote: carbet.roadAccessNote, pirogueDurationMin: carbet.pirogueDurationMin, minStayNights: carbet.minStayNights, diff --git a/src/app/admin/carbets/_components/CarbetForm.tsx b/src/app/admin/carbets/_components/CarbetForm.tsx index 260996b..4ddabe8 100644 --- a/src/app/admin/carbets/_components/CarbetForm.tsx +++ b/src/app/admin/carbets/_components/CarbetForm.tsx @@ -20,6 +20,10 @@ export type CarbetFormInitial = { capacity?: number; nightlyPrice?: number | string; accessType?: string; + roadAccess?: string | null; + electricity?: string | null; + gsmAtCarbet?: boolean; + gsmExitDistanceKm?: number | string | null; roadAccessNote?: string | null; pirogueDurationMin?: number | null; minStayNights?: number | null; @@ -189,6 +193,63 @@ export function CarbetForm({ initial = {}, owners, providers, action, submitLabe + {/* Critères opérationnels */} +
+

+ Critères opérationnels +

+

+ Les 4 dealbreakers d'un séjour en carbet guyanais. Indispensable pour les filtres recherche. +

+
+ + + + + + + + + + + + + + + +
+
+ {/* Séjour & tarif */}

Séjour & tarif

diff --git a/src/app/admin/carbets/actions.ts b/src/app/admin/carbets/actions.ts index 9e2fbff..2004bd8 100644 --- a/src/app/admin/carbets/actions.ts +++ b/src/app/admin/carbets/actions.ts @@ -10,7 +10,9 @@ import { prisma } from "@/lib/prisma"; import { AccessType, CarbetStatus, + Electricity, MediaType, + RoadAccess, TransportMode, UserRole, } from "@/generated/prisma/enums"; @@ -29,6 +31,16 @@ const baseCarbetSchema = z.object({ capacity: z.coerce.number().int().min(1).max(100), nightlyPrice: z.coerce.number().min(0).max(100000), accessType: z.enum([AccessType.ROAD_AND_RIVER, AccessType.RIVER_ONLY]), + roadAccess: z + .enum([RoadAccess.NONE, RoadAccess.DRY_SEASON_ONLY, RoadAccess.ALL_YEAR]) + .optional() + .nullable(), + electricity: z + .enum([Electricity.NONE, Electricity.SOLAR, Electricity.GENERATOR_READY, Electricity.EDF]) + .optional() + .nullable(), + gsmAtCarbet: z.preprocess((v) => v === "yes" || v === true, z.boolean()), + gsmExitDistanceKm: z.coerce.number().min(0).max(50).optional().nullable(), roadAccessNote: z.string().trim().max(1000).optional().nullable(), pirogueDurationMin: z.coerce.number().int().min(0).max(1440).optional().nullable(), minStayNights: z.coerce.number().int().min(1).max(365).optional().nullable(), @@ -53,9 +65,11 @@ function parseFromFormData(fd: FormData) { if (typeof v === "string") obj[k] = v; } // Normalise les champs optionnels nullables - ["roadAccessNote", "pirogueDurationMin", "minStayNights", "maxStayNights", "minCapacity", "transportMode", "pirogueProviderId"].forEach( + ["roadAccessNote", "pirogueDurationMin", "minStayNights", "maxStayNights", "minCapacity", "transportMode", "pirogueProviderId", "roadAccess", "electricity", "gsmExitDistanceKm"].forEach( (k) => (obj[k] = normalizeNullable(obj[k] as string | null | undefined)), ); + // gsmAtCarbet : si pas posté, on garde la valeur (sera traité par preprocess Zod) + if (!("gsmAtCarbet" in obj)) obj.gsmAtCarbet = "no"; return obj; } diff --git a/src/app/espace-hote/carbets/[carbetId]/page.tsx b/src/app/espace-hote/carbets/[carbetId]/page.tsx index 2b8b069..39ae0f9 100644 --- a/src/app/espace-hote/carbets/[carbetId]/page.tsx +++ b/src/app/espace-hote/carbets/[carbetId]/page.tsx @@ -32,6 +32,10 @@ export default async function EditCarbetPage({ embarkPoint: true, pirogueDurationMin: true, capacity: true, + roadAccess: true, + electricity: true, + gsmAtCarbet: true, + gsmExitDistanceKm: true, status: true, media: { orderBy: { sortOrder: "asc" }, @@ -54,6 +58,10 @@ export default async function EditCarbetPage({ embarkPoint: carbet.embarkPoint, pirogueDurationMin: String(carbet.pirogueDurationMin), capacity: String(carbet.capacity), + roadAccess: carbet.roadAccess ?? "", + electricity: carbet.electricity ?? "", + gsmAtCarbet: carbet.gsmAtCarbet, + gsmExitDistanceKm: carbet.gsmExitDistanceKm !== null ? carbet.gsmExitDistanceKm.toString() : "", status: carbet.status, amenityKeys: carbet.amenities.map((entry) => entry.amenity.key), }; diff --git a/src/app/espace-hote/carbets/_components/carbet-form.tsx b/src/app/espace-hote/carbets/_components/carbet-form.tsx index ac2d234..3a484c6 100644 --- a/src/app/espace-hote/carbets/_components/carbet-form.tsx +++ b/src/app/espace-hote/carbets/_components/carbet-form.tsx @@ -17,6 +17,10 @@ export type CarbetFormDefaults = { embarkPoint: string; pirogueDurationMin: string; capacity: string; + roadAccess: string; + electricity: string; + gsmAtCarbet: boolean; + gsmExitDistanceKm: string; status: CarbetStatus; amenityKeys: string[]; }; @@ -216,6 +220,90 @@ export function CarbetForm({
+
+
+

+ Critères opérationnels +

+

+ Les 4 dealbreakers d'un séjour en carbet. Ces critères apparaissent + en grand sur votre fiche et alimentent les filtres recherche. +

+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + +

+ Laissez vide si réseau au carbet +

+ +
+
+
+

Commodités

diff --git a/src/app/espace-hote/carbets/actions.ts b/src/app/espace-hote/carbets/actions.ts index 8964376..ba29ac4 100644 --- a/src/app/espace-hote/carbets/actions.ts +++ b/src/app/espace-hote/carbets/actions.ts @@ -9,7 +9,7 @@ import { prisma } from "@/lib/prisma"; import { ensureUniqueCarbetSlug } from "@/lib/slug"; import { deleteObject } from "@/lib/storage"; import { Prisma } from "@/generated/prisma/client"; -import { CarbetStatus } from "@/generated/prisma/enums"; +import { CarbetStatus, Electricity, RoadAccess } from "@/generated/prisma/enums"; import type { CarbetFormState } from "./form-types"; @@ -22,10 +22,26 @@ type ParsedCarbet = { embarkPoint: string; pirogueDurationMin: number; capacity: number; + roadAccess: RoadAccess | null; + electricity: Electricity | null; + gsmAtCarbet: boolean; + gsmExitDistanceKm: number | null; status: CarbetStatus; amenities: string[]; }; +function isRoadAccess(v: string): v is RoadAccess { + return v === RoadAccess.NONE || v === RoadAccess.DRY_SEASON_ONLY || v === RoadAccess.ALL_YEAR; +} +function isElectricity(v: string): v is Electricity { + return ( + v === Electricity.NONE || + v === Electricity.SOLAR || + v === Electricity.GENERATOR_READY || + v === Electricity.EDF + ); +} + function isCarbetStatus(value: string): value is CarbetStatus { return (Object.values(CarbetStatus) as string[]).includes(value); } @@ -107,6 +123,29 @@ function parseCarbetForm(formData: FormData): { const status = isCarbetStatus(statusRaw) ? statusRaw : CarbetStatus.DRAFT; + // Critères opérationnels + const roadAccessRaw = String(formData.get("roadAccess") ?? "").trim(); + const roadAccess = isRoadAccess(roadAccessRaw) ? roadAccessRaw : null; + + const electricityRaw = String(formData.get("electricity") ?? "").trim(); + const electricity = isElectricity(electricityRaw) ? electricityRaw : null; + + const gsmAtCarbet = String(formData.get("gsmAtCarbet") ?? "no") === "yes"; + + const gsmExitRaw = String(formData.get("gsmExitDistanceKm") ?? "").trim(); + let gsmExitDistanceKm: number | null = null; + if (gsmExitRaw) { + const n = Number(gsmExitRaw); + if (Number.isFinite(n) && n >= 0 && n <= 50) { + gsmExitDistanceKm = n; + } else { + errors.gsmExitDistanceKm = "Distance invalide (0 à 50 km)."; + } + } + + // Cohérence : si GSM au carbet, on ignore la distance + const finalGsmExitDistanceKm = gsmAtCarbet ? null : gsmExitDistanceKm; + return { data: { title, @@ -117,6 +156,10 @@ function parseCarbetForm(formData: FormData): { embarkPoint, pirogueDurationMin, capacity, + roadAccess, + electricity, + gsmAtCarbet, + gsmExitDistanceKm: finalGsmExitDistanceKm, status, amenities, }, @@ -183,6 +226,10 @@ export async function createCarbet( embarkPoint: data.embarkPoint, pirogueDurationMin: data.pirogueDurationMin, capacity: data.capacity, + roadAccess: data.roadAccess, + electricity: data.electricity, + gsmAtCarbet: data.gsmAtCarbet, + gsmExitDistanceKm: data.gsmExitDistanceKm, status: CarbetStatus.DRAFT, }, select: { id: true }, @@ -239,6 +286,10 @@ export async function updateCarbet( embarkPoint: data.embarkPoint, pirogueDurationMin: data.pirogueDurationMin, capacity: data.capacity, + roadAccess: data.roadAccess, + electricity: data.electricity, + gsmAtCarbet: data.gsmAtCarbet, + gsmExitDistanceKm: data.gsmExitDistanceKm, status: data.status, }, });