From e76b0dcb1348eb1273e8225d290d2a48a30eb6cb Mon Sep 17 00:00:00 2001
From: galenskap <jean.deborah@gmail.com>
Date: Tue, 1 Apr 2025 10:32:54 +0200
Subject: [PATCH] Send contact form via an ajax call instead of directly
 redirecting to the php script

---
 .../partials/components/contact-form.njk      |  77 ++++++++-
 src/form/contact-form-handler.php             | 160 +++++++++---------
 2 files changed, 157 insertions(+), 80 deletions(-)

diff --git a/src/_includes/partials/components/contact-form.njk b/src/_includes/partials/components/contact-form.njk
index 1a6fc1b..422f22b 100644
--- a/src/_includes/partials/components/contact-form.njk
+++ b/src/_includes/partials/components/contact-form.njk
@@ -10,7 +10,10 @@
     {% elif contactTitle %}
       <h2 id="contact-form" class="[ contact-heading ]">{{ contactTitle }}</h2>
     {% endif %}
-    <form name="contact" method="POST" action="/form/contact-form-handler.php">
+    
+    <div class="form-messages" aria-live="polite"></div>
+    
+    <form name="contact" method="POST" action="/form/contact-form-handler.php" class="contact-form">
       <ol class="[ field-list ]">
         <li class="[ field-list__field-group ]">
           {{ label("Nom", "namezzz") }}
@@ -30,7 +33,7 @@
           {% else %}
             {{ select( "select", [ 
               {label: "Obtenir un rendez-vous (décrivez votre projet en quelques lignes)", value: "option 1"},
-              {label: "Obtenir des précisions sur le statut d’entrepreneur salarié", value: "option 2"},
+              {label: "Obtenir des précisions sur le statut d'entrepreneur salarié", value: "option 2"},
               {label: "Proposer une mission à un coopérateur", value: "option 3"},
               {label: "Proposer un partenariat", value: "option 4"}
             ], { required: true, options_before: [""], options_after: ["Autre demande"] } ) }}
@@ -44,7 +47,7 @@
           {{ hidden_field('subscribe', '') }}
         {% else %}
           <li class="[ field-list__field-group ] [ full-width ]">
-            {{ checkboxes("", "subscribe", [ "Je souhaite être tenu au courant de l’actualité Astrolabe"], { description: "" } ) }}
+            {{ checkboxes("", "subscribe", [ "Je souhaite être tenu au courant de l'actualité Astrolabe"], { description: "" } ) }}
           </li>
         {% endif %}
         <!-- H o n e y p o t -->
@@ -67,3 +70,71 @@
     </form>
   </div>
 </section>
+
+<style>
+.form-messages {
+  margin-bottom: 1rem;
+}
+
+.form-messages .error {
+  color: #dc3545;
+  margin-bottom: 0.5rem;
+}
+
+.form-messages .success {
+  color: #28a745;
+}
+
+.field-error {
+  color: #dc3545;
+  font-size: 0.875rem;
+  margin-top: 0.25rem;
+}
+</style>
+
+<script>
+document.addEventListener('DOMContentLoaded', function() {
+  const form = document.querySelector('.contact-form');
+  const messagesContainer = document.querySelector('.form-messages');
+
+  form.addEventListener('submit', async function(e) {
+    e.preventDefault();
+    
+    // Clean previous messages
+    messagesContainer.innerHTML = '';
+    
+    // Get form data
+    const formData = new FormData(form);
+
+    try {
+      const response = await fetch(form.action, {
+        method: 'POST',
+        body: formData
+      });
+
+      const data = await response.json();
+
+      if (data.success) {
+        // Display success message
+        messagesContainer.innerHTML = `<div class="success">${data.message}</div>`;
+        form.reset();
+        // Redirect to thank you page
+        window.location.href = '/thank-you/index.html';
+      } else {
+        // Display errors
+        const errorHtml = data.errors.map(error => 
+          `<div class="error">${error}</div>`
+        ).join('');
+        messagesContainer.innerHTML = errorHtml;
+        
+        // Scroll to error messages
+        messagesContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+      }
+    } catch (error) {
+      messagesContainer.innerHTML = `
+        <div class="error">Une erreur est survenue lors de l'envoi du formulaire. Veuillez réessayer.</div>
+      `;
+    }
+  });
+});
+</script>
diff --git a/src/form/contact-form-handler.php b/src/form/contact-form-handler.php
index 0a93287..5679059 100644
--- a/src/form/contact-form-handler.php
+++ b/src/form/contact-form-handler.php
@@ -3,9 +3,12 @@ require("/usr/share/php/libphp-phpmailer/autoload.php");
 use PHPMailer\PHPMailer\PHPMailer;
 use PHPMailer\PHPMailer\Exception;
 
+// Set header to return JSON
+header('Content-Type: application/json');
+
 $mail = new PHPMailer(true);
 
-$errors = '';
+$errors = [];
 $myEmail = getenv('ASTRO_SMTP_FROM');
 $myEmailSplitted = explode('@', $myEmail);
 $domainFromMyEmail = (
@@ -27,11 +30,11 @@ $hcaptchaSecret = getenv('HCAPTCHA_SECRET_KEY');
 $hcaptchaVerifyUrl = "https://api.hcaptcha.com/siteverify";
 
 if(empty($_POST['namezzz']) || empty($_POST['emailzzz']) || empty($_POST['message'])) {
-    $errors .= "\n Erreur : champs obligatoires manquants.";
+    $errors[] = "Erreur : champs obligatoires manquants.";
 }
 
 if(!empty($_POST['name']) && !empty($_POST['email'])) {
-    $errors .= "\n Erreur : spam détecté.";
+    $errors[] = "Erreur : spam détecté.";
 }
 
 /* Captcha verification */
@@ -53,10 +56,10 @@ if(!empty($_POST['h-captcha-response'])) {
     $responseData = json_decode($response, true);
 
     if(!$responseData['success']) {
-        $errors .= "\n Erreur lors de la validation du captcha.";
+        $errors[] = "Erreur lors de la validation du captcha.";
     }
 } else {
-    $errors .= "\n Erreur lors de la validation du captcha.";
+    $errors[] = "Erreur lors de la validation du captcha.";
 }
 
 $name = $_POST['namezzz'];
@@ -66,81 +69,84 @@ $message = $_POST['message'];
 $subscribe = $_POST['subscribe'];
 
 if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
-    $errors .= "\n Erreur d'adresse e-mail invalide : $emailAddress";
+    $errors[] = "Erreur d'adresse e-mail invalide : $emailAddress";
 }
 
 if(empty($errors)) {
-    $emailSubject = "[Formulaire Astrolabe] Nouveau message";
+    try {
+        $emailSubject = "[Formulaire Astrolabe] Nouveau message";
 
-    switch ($select) {
-        case "option 1":
-            $purpose = "Demande de rendez-vous";
-            break;
-        case "option 2":
-            $purpose = "Demande de précisions sur le statut d’entrepreneur salarié";
-            break;
-        case "option 3":
-            $purpose = "Proposition de misson";
-            break;
-        case "option 4":
-            $purpose = "Proposition de partenariat";
-            break;
-        default:
-            $purpose = "Autre demande";
+        switch ($select) {
+            case "option 1":
+                $purpose = "Demande de rendez-vous";
+                break;
+            case "option 2":
+                $purpose = "Demande de précisions sur le statut d'entrepreneur salarié";
+                break;
+            case "option 3":
+                $purpose = "Proposition de misson";
+                break;
+            case "option 4":
+                $purpose = "Proposition de partenariat";
+                break;
+            default:
+                $purpose = "Autre demande";
+        }
+        $emailSubject .= " : $purpose";
+
+        $emailBody = "Vous avez reçu un nouveau message depuis le formulaire du site Astrolabe :".
+        "\r\n\r\nNom: $name \r\nEmail: $emailAddress \r\nRaison: $purpose\r\nSubscribe: $subscribe\r\n\r\n$message";
+        
+        $emailBodyHTML = str_replace("\r\n", "<br>", $emailBody);
+        
+        $mail->isSMTP();
+        $mail->Host       = getenv('ASTRO_SMTP_HOSTNAME');
+        $mail->SMTPAuth   = true;
+        $mail->Username   = getenv('ASTRO_SMTP_USERNAME');
+        $mail->Password   = getenv('ASTRO_SMTP_PASSWORD');
+        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+        $mail->Port       = 587;
+
+        //Options
+        $mail->CharSet    = 'UTF-8';
+        $mail->WordWrap   = 70;
+                
+        //Recipients
+        $mail->setFrom($myEmail);
+        $mail->addAddress($wantedContact);
+        $mail->addReplyTo($emailAddress, $name);
+                
+        // Content
+        $mail->isHTML(true);
+        $mail->Subject = $emailSubject;
+        $mail->Body    = $emailBodyHTML;
+        $mail->AltBody = $emailBody;
+                
+        $mail->send();
+
+        // if subscribe add to mailing list
+        if(!empty($subscribe)) {
+            // process
+            // enovoi mail add to mailing list
+        }
+        
+        http_response_code(200);
+        echo json_encode([
+            'success' => true,
+            'message' => 'Message envoyé avec succès'
+        ]);
+        
+    } catch (Exception $e) {
+        http_response_code(500);
+        echo json_encode([
+            'success' => false,
+            'errors' => ["Erreur lors de l'envoi du message : " . $mail->ErrorInfo]
+        ]);
     }
-    $emailSubject .= " : $purpose";
-
-    $emailBody = "Vous avez reçu un nouveau message depuis le formulaire du site Astrolabe :".
-    "\r\n\r\nNom: $name \r\nEmail: $emailAddress \r\nRaison: $purpose\r\nSubscribe: $subscribe\r\n\r\n$message";
-        
-    $emailBodyHTML = str_replace("\r\n", "<br>", $emailBody);
-        
-    $mail->isSMTP();
-    $mail->Host       = getenv('ASTRO_SMTP_HOSTNAME');
-    $mail->SMTPAuth   = true;
-    $mail->Username   = getenv('ASTRO_SMTP_USERNAME');
-    $mail->Password   = getenv('ASTRO_SMTP_PASSWORD');
-    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
-    $mail->Port       = 587;
-
-    //Options
-    $mail->CharSet    = 'UTF-8';
-    $mail->WordWrap   = 70;
-            
-    //Recipients
-    $mail->setFrom($myEmail);
-    $mail->addAddress($wantedContact);
-    $mail->addReplyTo($emailAddress, $name);
-            
-    // Content
-    $mail->isHTML(true);
-    $mail->Subject = $emailSubject;
-    $mail->Body    = $emailBodyHTML;
-    $mail->AltBody = $emailBody;
-            
-    $mail->send();
-
-    // if subscribe add to mailing list
-    if(!empty($subscribe)) {
-        // process
-        // enovoi mail add to mailing list
-    }
-        
-    // redirect to the 'thank you' page
-    header("Location: /thank-you/index.html");
+} else {
+    http_response_code(400);
+    echo json_encode([
+        'success' => false,
+        'errors' => $errors
+    ]);
 }
-?>
-<!DOCTYPE html>
-<html>
-	<head>
-		<title>Contact form handler</title>
-	</head>
-
-	<body>
-		<!-- This page is displayed only if there is some error -->
-		<?php
-            echo nl2br($errors);
-        ?>
-        <a href="javascript:history.back()">Retour</a>
-	</body>
-</html>