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.
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { useActionState } from "react";
|
|
import Link from "next/link";
|
|
import { signup } from "@/lib/actions/auth";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
|
|
export function SignupForm() {
|
|
const [state, action, pending] = useActionState(signup, undefined);
|
|
|
|
return (
|
|
<Card className="w-full max-w-sm">
|
|
<CardHeader>
|
|
<CardTitle>Créer un compte</CardTitle>
|
|
<CardDescription>
|
|
Postez un besoin ou répondez aux besoins des autres.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form action={action} className="flex flex-col gap-4">
|
|
<div className="flex flex-col gap-2">
|
|
<Label htmlFor="fullName">Nom complet</Label>
|
|
<Input id="fullName" name="fullName" placeholder="Jean Dupont" />
|
|
{state?.errors?.fullName && (
|
|
<p className="text-sm text-destructive">
|
|
{state.errors.fullName[0]}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col gap-2">
|
|
<Label htmlFor="email">Email</Label>
|
|
<Input id="email" name="email" type="email" placeholder="vous@exemple.com" />
|
|
{state?.errors?.email && (
|
|
<p className="text-sm text-destructive">{state.errors.email[0]}</p>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col gap-2">
|
|
<Label htmlFor="password">Mot de passe</Label>
|
|
<Input id="password" name="password" type="password" />
|
|
{state?.errors?.password && (
|
|
<ul className="text-sm text-destructive">
|
|
{state.errors.password.map((error) => (
|
|
<li key={error}>{error}</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
{state?.message && (
|
|
<p className="text-sm text-destructive">{state.message}</p>
|
|
)}
|
|
<Button type="submit" disabled={pending} className="mt-2">
|
|
{pending ? "Création..." : "Créer mon compte"}
|
|
</Button>
|
|
</form>
|
|
<p className="mt-4 text-center text-sm text-muted-foreground">
|
|
Déjà un compte ?{" "}
|
|
<Link href="/auth/login" className="underline">
|
|
Se connecter
|
|
</Link>
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|