Initial commit: WaMarket MVP
Marketplace inversée (Next.js 16 App Router + Supabase Cloud) : auth, schéma + RLS, publication de besoins avec upload d'images, feed avec filtres, offres, acceptation via RPC, messagerie temps réel, dashboards, et Dockerfile pour déploiement Coolify.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { useActionState } from "react";
|
||||
import { createOffer } from "@/lib/actions/offers";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { ImageUploader } from "@/components/shared/image-uploader";
|
||||
|
||||
export function OfferForm({ needId }: { needId: string }) {
|
||||
const [state, action, pending] = useActionState(createOffer, undefined);
|
||||
|
||||
return (
|
||||
<form action={action} className="flex flex-col gap-4">
|
||||
<input type="hidden" name="needId" value={needId} />
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="offer-title">Titre de l'offre</Label>
|
||||
<Input
|
||||
id="offer-title"
|
||||
name="title"
|
||||
placeholder="Ex: Intervention sous 48h avec garantie"
|
||||
/>
|
||||
{state?.errors?.title && (
|
||||
<p className="text-sm text-destructive">{state.errors.title[0]}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="offer-description">Description</Label>
|
||||
<Textarea
|
||||
id="offer-description"
|
||||
name="description"
|
||||
rows={4}
|
||||
placeholder="Détaille ce que tu proposes, tes conditions, ton expérience..."
|
||||
/>
|
||||
{state?.errors?.description && (
|
||||
<p className="text-sm text-destructive">
|
||||
{state.errors.description[0]}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="offer-price">Prix (€)</Label>
|
||||
<Input id="offer-price" name="price" type="number" min="0" step="0.01" />
|
||||
{state?.errors?.price && (
|
||||
<p className="text-sm text-destructive">{state.errors.price[0]}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ImageUploader name="images" maxFiles={5} />
|
||||
|
||||
{state?.message && (
|
||||
<p className="text-sm text-destructive">{state.message}</p>
|
||||
)}
|
||||
|
||||
<Button type="submit" disabled={pending} className="mt-2 w-fit">
|
||||
{pending ? "Envoi..." : "Envoyer l'offre"}
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user