Added resend, fixed CSRF

This commit is contained in:
cdricms
2025-02-21 16:16:24 +01:00
parent dbddf12f25
commit de828d4c13
10 changed files with 86 additions and 76 deletions

View File

@@ -3,9 +3,10 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { API_URL } from "@/lib/constants";
import { ApiResponse } from "@/types/types";
import { useEffect, useState } from "react";
import useApiMutation from "@/hooks/use-api";
import { useToast } from "@/hooks/use-toast";
import { Loader2 } from "lucide-react";
import { useState } from "react";
interface FormData {
firstname: string;
@@ -16,6 +17,7 @@ interface FormData {
}
const Contact = () => {
const { toast } = useToast();
const [formData, setFormData] = useState<FormData>({
firstname: "",
lastname: "",
@@ -24,7 +26,12 @@ const Contact = () => {
message: "",
});
const [csrfToken, setCsrfToken] = useState("");
const {
trigger: sendEmail,
isMutating: isLoading,
isSuccess,
error,
} = useApiMutation<unknown, FormData>(`/contact`, {}, "POST", false, true);
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
@@ -36,34 +43,21 @@ const Contact = () => {
});
};
useEffect(() => {
const fetchCsrfToken = async () => {
try {
const response = await fetch(`${API_URL}/csrf-token`, {
credentials: "include",
});
const data: ApiResponse<{ csrf: string }> =
await response.json();
if (data.data) setCsrfToken(data.data.csrf);
} catch (e: any) {
console.log(e);
}
};
fetchCsrfToken();
}, []);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const res = await fetch(`${API_URL}/contact`, {
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": csrfToken,
},
method: "POST",
body: JSON.stringify(formData),
credentials: "include",
});
const res = await sendEmail(formData);
if (res?.status === "Success") {
toast({
title: "Mail envoyé.",
description:
"On reviendra vers vous le plus rapidement possible.",
});
} else {
toast({
title: "Échec de l'envoie du mail.",
description: res?.message,
});
}
};
return (
@@ -165,8 +159,25 @@ const Contact = () => {
required
/>
</div>
<Button type="submit" className="w-full">
Envoyer
<Button
disabled={
isLoading || isSuccess || error !== undefined
}
type="submit"
className={`w-full transition-all ease-in-out ${isSuccess ? "bg-green-800" : error ? "bg-red-800" : ""}`}
>
{isSuccess ? (
<>Message envoyé</>
) : error ? (
<>Échec de l'envoie du mail.</>
) : (
<>
{isLoading && (
<Loader2 className="animate-spin" />
)}
Envoyer
</>
)}
</Button>
</form>
</div>

View File

@@ -20,7 +20,7 @@ export default async function request<T>(
if (options.csrfToken) {
const res: ApiResponse<{ csrf: string }> = await (
await fetch(`${API_URL}/csrf-token`)
await fetch(`${API_URL}/csrf-token`, { credentials: "include" })
).json();
if (res.data) headers["X-CSRF-Token"] = res.data.csrf;
}