168 lines
4.8 KiB
TypeScript
168 lines
4.8 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useEffect, useState } from "react";
|
|
import { usePathname } from "next/navigation";
|
|
|
|
type ContactData = {
|
|
email?: string;
|
|
linkedin?: string;
|
|
github?: string;
|
|
};
|
|
|
|
export default function ContactComponent() {
|
|
const pathname = usePathname();
|
|
const onContactPage = pathname === "/contact";
|
|
|
|
const [data, setData] = useState<ContactData | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!onContactPage) return;
|
|
|
|
// Appelle l'API interne Next.js qui proxy vers le BACKEND_URL côté serveur
|
|
const url = "/api/contact";
|
|
|
|
fetch(url, { cache: "no-store" })
|
|
.then((res) => (res.ok ? res.json() : Promise.reject(new Error("fetch contact failed"))))
|
|
.then((json) => setData(json))
|
|
.catch(() => setData(null));
|
|
}, [onContactPage]);
|
|
|
|
// Si on n'est pas sur la page /contact => juste un lien
|
|
if (!onContactPage) {
|
|
return (
|
|
<div className="block">
|
|
<div className="btn-group">
|
|
<Link href="/contact" className="btn btn--primary btn--pill">
|
|
Me contacter
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Page /contact => liens + formulaire
|
|
return (
|
|
<div className="block">
|
|
<div className="stack">
|
|
<div className="btn-group">
|
|
{data?.linkedin ? (
|
|
<a href={data.linkedin} target="_blank" rel="noopener noreferrer" className="link-button">
|
|
LinkedIn
|
|
</a>
|
|
) : null}
|
|
{data?.github ? (
|
|
<a href={data.github} target="_blank" rel="noopener noreferrer" className="link-button">
|
|
GitHub
|
|
</a>
|
|
) : null}
|
|
{data?.email ? (
|
|
<a href={`mailto:${data.email}`} className="link-button">
|
|
Email direct
|
|
</a>
|
|
) : null}
|
|
</div>
|
|
|
|
{data?.email ? (
|
|
<ContactForm />
|
|
) : (
|
|
<p className="u-muted"></p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ContactForm() {
|
|
const [name, setName] = useState("");
|
|
const [email, setEmail] = useState("");
|
|
const [subject, setSubject] = useState("");
|
|
const [message, setMessage] = useState("");
|
|
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
async function handleSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
setError(null);
|
|
|
|
if (!name || !email || !message) {
|
|
setError("Veuillez remplir les champs requis.");
|
|
return;
|
|
}
|
|
|
|
setStatus("loading");
|
|
try {
|
|
const res = await fetch("/api/contact", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ name, email, subject, message }),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const txt = await res.text();
|
|
throw new Error(txt || "Erreur lors de l'envoi du message");
|
|
}
|
|
|
|
setStatus("success");
|
|
setName("");
|
|
setEmail("");
|
|
setSubject("");
|
|
setMessage("");
|
|
} catch (err: any) {
|
|
setStatus("error");
|
|
setError(err?.message || "Une erreur est survenue.");
|
|
}
|
|
}
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} className="stack" noValidate>
|
|
<div>
|
|
<label htmlFor="name">Votre nom</label>
|
|
<input id="name" name="name" type="text" required value={name} onChange={(e) => setName(e.target.value)} />
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="email">Votre email</label>
|
|
<input id="email" name="email" type="email" required value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="subject">Sujet</label>
|
|
<input id="subject" name="subject" type="text" placeholder="Prise de contact" value={subject} onChange={(e) => setSubject(e.target.value)} />
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="message">Message</label>
|
|
<textarea id="message" name="message" required value={message} onChange={(e) => setMessage(e.target.value)} />
|
|
</div>
|
|
|
|
{status === "success" ? (
|
|
<p className="u-success">Votre message a bien été envoyé. Merci !</p>
|
|
) : null}
|
|
{status === "error" && error ? (
|
|
<p className="u-error">{error}</p>
|
|
) : null}
|
|
|
|
<div className="btn-group">
|
|
<button type="submit" className="btn btn--primary btn--pill" disabled={status === "loading"}>
|
|
{status === "loading" ? "Envoi…" : "Envoyer"}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="btn btn--ghost"
|
|
onClick={() => {
|
|
setName("");
|
|
setEmail("");
|
|
setSubject("");
|
|
setMessage("");
|
|
setError(null);
|
|
setStatus("idle");
|
|
}}
|
|
disabled={status === "loading"}
|
|
>
|
|
Réinitialiser
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|