karbe/src/app/admin/rental-providers/_components/ProviderForm.tsx
Claude Integration e2f3f070fa
Some checks failed
CI / test (pull_request) Failing after 1m52s
feat(rental): Sprint A — modèle Prisma + admin CRUD + seed 13 items
2026-06-02 03:26:04 +00:00

132 lines
4.5 KiB
TypeScript

"use client";
import { useState, useTransition } from "react";
import { FormField, inputCls, textareaCls } from "@/components/admin/FormField";
type Props = {
initial?: {
name?: string;
isSystemD?: boolean;
contactEmail?: string | null;
contactPhone?: string | null;
rivers?: string[];
description?: string | null;
commissionPct?: number | string;
active?: boolean;
};
action: (fd: FormData) => Promise<{ ok: false; error: string } | { ok: true } | undefined>;
submitLabel?: string;
};
export function ProviderForm({ initial = {}, action, submitLabel = "Enregistrer" }: Props) {
const [pending, startTransition] = useTransition();
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
function onSubmit(fd: FormData) {
setError(null);
setSuccess(null);
startTransition(async () => {
const res = await action(fd);
if (res && res.ok === false) setError(res.error);
else if (res && res.ok === true) setSuccess("Enregistré.");
});
}
return (
<form action={onSubmit} className="space-y-4">
<fieldset disabled={pending} className="space-y-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<FormField label="Nom du prestataire" required>
<input name="name" defaultValue={initial.name ?? ""} required maxLength={200} className={inputCls} />
</FormField>
<FormField label="Type">
<label className="flex items-center gap-2 px-1 py-2 text-sm">
<input
type="checkbox"
name="isSystemD"
defaultChecked={initial.isSystemD ?? false}
className="h-4 w-4 rounded border-zinc-300"
/>
Fournisseur officiel System D (0 % commission)
</label>
</FormField>
<FormField label="Email contact">
<input
name="contactEmail"
type="email"
defaultValue={initial.contactEmail ?? ""}
maxLength={200}
className={inputCls}
/>
</FormField>
<FormField label="Téléphone contact">
<input
name="contactPhone"
defaultValue={initial.contactPhone ?? ""}
maxLength={50}
className={inputCls}
/>
</FormField>
<FormField label="Commission (%)" hint="0 pour System D, 5-15 % pour les prestataires externes.">
<input
name="commissionPct"
type="number"
min={0}
max={50}
step="0.5"
defaultValue={initial.commissionPct?.toString() ?? "10"}
className={inputCls}
/>
</FormField>
<FormField label="Statut">
<label className="flex items-center gap-2 px-1 py-2 text-sm">
<input
type="checkbox"
name="active"
defaultChecked={initial.active ?? true}
className="h-4 w-4 rounded border-zinc-300"
/>
Actif
</label>
</FormField>
</div>
<FormField label="Fleuves desservis" required hint="Séparer par virgule, point-virgule ou retour à la ligne.">
<input
name="rivers"
defaultValue={(initial.rivers ?? []).join(", ")}
placeholder="Maroni, Approuague, Oyapock"
className={inputCls}
/>
</FormField>
<FormField label="Description" hint="Présentation, points forts, conditions particulières.">
<textarea
name="description"
rows={4}
defaultValue={initial.description ?? ""}
maxLength={5000}
className={textareaCls}
/>
</FormField>
{error ? (
<div className="rounded border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-700">{error}</div>
) : null}
{success ? (
<div className="rounded border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-800">{success}</div>
) : null}
<div className="flex items-center justify-end gap-2">
<button
type="submit"
className="rounded-md bg-zinc-900 px-5 py-2 text-sm font-semibold text-white hover:bg-zinc-800 disabled:opacity-50"
>
{pending ? "Enregistrement…" : submitLabel}
</button>
</div>
</fieldset>
</form>
);
}