|
75 | 75 | projectFilter === "all" ? projects : projects.filter(p => p.category === projectFilter) |
76 | 76 | ); |
77 | 77 |
|
78 | | - // Contact Form Mocking |
| 78 | + // Contact Form Submission |
79 | 79 | let fullname = $state(""); |
80 | 80 | let email = $state(""); |
81 | 81 | let message = $state(""); |
82 | 82 | let isSending = $state(false); |
83 | 83 | let showToast = $state(false); |
| 84 | + let toastMessage = $state("Message envoyé avec succès !"); |
| 85 | + let toastError = $state(false); |
84 | 86 |
|
85 | | - function handleMockSubmit(e: SubmitEvent) { |
| 87 | + async function handleFormSubmit(e: SubmitEvent) { |
86 | 88 | e.preventDefault(); |
87 | 89 | isSending = true; |
88 | | - setTimeout(() => { |
89 | | - isSending = false; |
| 90 | + toastError = false; |
| 91 | +
|
| 92 | + try { |
| 93 | + const response = await fetch(`https://formsubmit.co/ajax/${personalInfo.email}`, { |
| 94 | + method: "POST", |
| 95 | + headers: { |
| 96 | + "Content-Type": "application/json", |
| 97 | + "Accept": "application/json" |
| 98 | + }, |
| 99 | + body: JSON.stringify({ |
| 100 | + name: fullname, |
| 101 | + email: email, |
| 102 | + message: message, |
| 103 | + _subject: `Nouveau message Portfolio de ${fullname}` |
| 104 | + }) |
| 105 | + }); |
| 106 | +
|
| 107 | + const result = await response.json(); |
| 108 | +
|
| 109 | + if (response.ok && result.success === "true") { |
| 110 | + toastMessage = "Message envoyé avec succès !"; |
| 111 | + toastError = false; |
| 112 | + showToast = true; |
| 113 | + fullname = ""; |
| 114 | + email = ""; |
| 115 | + message = ""; |
| 116 | + } else { |
| 117 | + throw new Error(result.message || "Erreur de service"); |
| 118 | + } |
| 119 | + } catch (err) { |
| 120 | + console.error(err); |
| 121 | + toastMessage = "Une erreur est survenue lors de l'envoi."; |
| 122 | + toastError = true; |
90 | 123 | showToast = true; |
91 | | - fullname = ""; |
92 | | - email = ""; |
93 | | - message = ""; |
| 124 | + } finally { |
| 125 | + isSending = false; |
94 | 126 | setTimeout(() => { |
95 | 127 | showToast = false; |
96 | 128 | }, 5000); |
97 | | - }, 1500); |
| 129 | + } |
98 | 130 | } |
99 | 131 | </script> |
100 | 132 |
|
|
105 | 137 |
|
106 | 138 | <!-- Toast Notification --> |
107 | 139 | {#if showToast} |
108 | | - <div class="fixed top-5 right-5 bg-white border-2 border-green-600 text-green-700 px-4 py-3 rounded-xl shadow-xl flex items-center gap-3 z-[9999] border-sketch font-hand animate-fade-in"> |
109 | | - <div class="w-2.5 h-2.5 rounded-full bg-green-600"></div> |
110 | | - <p class="text-xs font-semibold">Message envoyé avec succès ! (Simulation locale)</p> |
| 140 | + <div class="fixed top-5 right-5 bg-white border-2 px-4 py-3 rounded-xl shadow-xl flex items-center gap-3 z-[9999] border-sketch font-hand animate-fade-in |
| 141 | + {toastError ? 'border-red-600 text-red-700' : 'border-green-600 text-green-700'}"> |
| 142 | + <div class="w-2.5 h-2.5 rounded-full {toastError ? 'bg-red-600' : 'bg-green-600'}"></div> |
| 143 | + <p class="text-xs font-semibold">{toastMessage}</p> |
111 | 144 | </div> |
112 | 145 | {/if} |
113 | 146 |
|
|
369 | 402 |
|
370 | 403 | <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> |
371 | 404 | <!-- Form --> |
372 | | - <form onsubmit={handleMockSubmit} class="flex flex-col gap-4"> |
| 405 | + <form onsubmit={handleFormSubmit} class="flex flex-col gap-4"> |
373 | 406 | <div class="flex flex-col gap-1.5"> |
374 | 407 | <label for="fullname" class="text-sm text-slate-700 font-hand font-bold">Nom complet</label> |
375 | 408 | <input |
|
0 commit comments