3. Bouwen - fatihg61/Fatihport GitHub Wiki

In de bouwfase gaan we het hebben over me code.

Benodigdheden

  • Visual Studio Code
  • GitHub (voor code hosting)
  • NodeJS
  • SvelteKit framework

Afspraken

  • Global CSS om niet te herhalen
  • Zo min mogelijk JS
  • Meer focus op SvelteKit functies
  • Gebruik van components

CSP

<!--
De X-Content-Type-Options header wordt ingesteld op "nosniff".
Dit voorkomt dat browsers MIME type sniffing uitvoeren. Dit is belangrijk voor beveiliging omdat het voorkomt dat een aanvaller de content van een bestand manipuleert.
-->
<meta http-equiv="X-Content-Type-Options" content="nosniff" />

<!--
De X-Permitted-Cross-Domain-Policies header wordt ingesteld op "none".
Dit zorgt ervoor dat cross-domain beleidsbestanden worden genegeerd, wat voorkomt dat andere domeinen toegang krijgen tot bronnen op deze server.
-->
<meta http-equiv="X-Permitted-Cross-Domain-Policies" content="none" />

<!--
De Strict-Transport-Security (HSTS) header wordt ingesteld.
Dit dwingt de browser om alleen via HTTPS verbinding te maken met de server voor de opgegeven duur (in dit geval 31536000 seconden of 1 jaar).
includeSubDomains zorgt ervoor dat deze regel ook geldt voor alle subdomeinen.
preload laat de browser weten dat het domein vooraf in de HSTS preload lijst moet worden opgenomen.
-->
<meta
  http-equiv="Strict-Transport-Security"
  content="max-age=31536000; includeSubDomains; preload"
/>

<!--
De referrer meta-tag wordt ingesteld op "no-referrer".
Dit zorgt ervoor dat de referrer informatie niet wordt meegestuurd in de HTTP verzoeken.
-->
<meta name="referrer" content="no-referrer" />

<!--
De X-Frame-Options header wordt ingesteld op "DENY".
Dit voorkomt dat de inhoud van de website in een frame wordt geladen, wat 'clickjacking' aanvallen helpt te voorkomen.
-->
<meta http-equiv="X-Frame-Options" content="DENY" />

<!--
De X-XSS-Protection header wordt ingesteld op "1; mode=block".
Dit zorgt ervoor dat de browser zijn ingebouwde bescherming tegen Cross Site Scripting (XSS) aanvallen inschakelt en inhoud blokkeert als een aanval wordt gedetecteerd.
-->
<meta http-equiv="X-XSS-Protection" content="1; mode=block" />

<!--
De Referrer-Policy header wordt ingesteld op "strict-origin-when-cross-origin".
Dit betekent dat referrer informatie alleen wordt meegestuurd als de verzoeken dezelfde oorsprong hebben, en alleen de oorsprong wordt meegestuurd voor cross-origin verzoeken.
-->
<meta
  http-equiv="Referrer-Policy"
  content="strict-origin-when-cross-origin"
/>

SpeedInsights

// Importeer de functie `injectSpeedInsights` uit het Vercel Speed Insights pakket voor SvelteKit
import { injectSpeedInsights } from '@vercel/speed-insights/sveltekit';

// Roep de functie `injectSpeedInsights` aan om Speed Insights in je SvelteKit project te injecteren
injectSpeedInsights();

Wat doet de code?

injectSpeedInsights is een functie van Vercel's Speed Insights voor SvelteKit projecten. Speed Insights is een tool die gegevens verzamelt en analyseert om te helpen bij het optimaliseren van de loadtime van een site.

Form

Form.svelte

<script>
  // Importeer de `enhance` functie uit de SvelteKit app/forms module
  import { enhance } from "$app/forms";
  // Importeer de `onMount` functie uit Svelte om code uit te voeren zodra de component gemount is
  import { onMount } from 'svelte';

  // Declareer variabelen om de staat van het formulier bij te houden
  let isSubmitting = false;
  let successMessage = "";
  let errorMessage = "";
  // Objecten om foutmeldingen en validiteitsstatussen bij te houden voor de formuliervelden
  let errors = {
    name: "",
    email: "",
    phone: "",
    message: ""
  };
  let validity = {
    name: false,
    email: false,
    phone: false,
    message: false
  };

  // Functie die wordt gebruikt om het formulier te verbeteren met extra functionaliteit
  function handleEnhance({ formElement }) {
    // Deze functie wordt aangeroepen bij het indienen van het formulier
    const handleSubmit = async ({ result }) => {
      isSubmitting = false;
      successMessage = "";
      errorMessage = "";

      // Controleer of het indienen van het formulier succesvol was of niet
      if (result.type === "failure") {
        errorMessage = result.data.error;
      } else if (result.type === "success") {
        formElement.reset();
        successMessage = result.data.message;
        validity = { name: false, email: false, phone: false, message: false };
      }
    };
    return handleSubmit;
  }

  // Functie om individuele velden te valideren op basis van hun naam en waarde
  function validateField(name, value) {
    switch (name) {
      case 'name':
        if (!value) return "Name is required";
        return "";
      case 'email':
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!value) return "Email is required";
        if (!emailRegex.test(value)) return "Invalid email format";
        return "";
      case 'phone':
        const phoneRegex = /^\d{10,15}$/;
        if (!value) return "Phone is required";
        if (!phoneRegex.test(value)) return "Invalid phone number";
        return "";
      case 'message':
        if (!value) return "Message is required";
        return "";
      default:
        return "";
    }
  }

  // Functie om inputveranderingen af te handelen en te valideren
  function handleInput(event) {
    const { name, value } = event.target;
    const error = validateField(name, value);
    errors[name] = error;
    validity[name] = !error;
  }

  // Gebruik de `onMount` lifecycle hook om het formulier in te stellen zodra de component gemount is
  onMount(() => {
    const form = document.querySelector('form');
    form.addEventListener('input', handleInput);
  });
</script>

<!-- HTML voor het formulier -->
<section class="form-container">
  <form
    method="POST"
    use:enhance={handleEnhance}
    on:submit={() => (isSubmitting = true)}
    class="contact-form"
  >
    <fieldset class="form-wrapper">
      <legend class="form-legend">Personal Information</legend>
      <label for="name" class="form-label">
        <span>Name</span>
        <div class="input-wrapper">
          <i class="icon user-icon"></i>
          <input
            type="text"
            name="name"
            id="name"
            required
            placeholder="e.g John Doe"
            class="input-field {errors.name ? 'input-error' : validity.name ? 'input-success' : ''}"
          />
        </div>
      </label>
      <!-- Toon foutmelding als er een fout is voor het naamveld -->
      {#if errors.name}
        <p class="error-message">{errors.name}</p>
      {/if}

      <label for="email" class="form-label">
        <span>Email</span>
        <div class="input-wrapper">
          <i class="icon email-icon"></i>
          <input
            type="email"
            name="email"
            id="email"
            required
            placeholder="e.g [email protected]"
            class="input-field {errors.email ? 'input-error' : validity.email ? 'input-success' : ''}"
          />
        </div>
      </label>
      <!-- Toon foutmelding als er een fout is voor het emailveld -->
      {#if errors.email}
        <p class="error-message">{errors.email}</p>
      {/if}

      <label for="phone" class="form-label">
        <span>Phone</span>
        <div class="input-wrapper">
          <i class="icon phone-icon"></i>
          <input
            type="tel"
            name="phone"
            id="phone"
            required
            placeholder="Mobile number"
            class="input-field {errors.phone ? 'input-error' : validity.phone ? 'input-success' : ''}"
          />
        </div>
      </label>
      <!-- Toon foutmelding als er een fout is voor het telefoonveld -->
      {#if errors.phone}
        <p class="error-message">{errors.phone}</p>
      {/if}
    </fieldset>

    <fieldset class="form-wrapper">
      <label for="message" class="form-label">
        <span>Message</span>
        <textarea
          name="message"
          id="message"
          required
          placeholder="Tell me your message..."
          class="input-field textarea-field {errors.message ? 'input-error' : validity.message ? 'input-success' : ''}"
        ></textarea>
      </label>
      <!-- Toon foutmelding als er een fout is voor het berichtveld -->
      {#if errors.message}
        <p class="error-message">{errors.message}</p>
      {/if}
    </fieldset>

    <!-- Toon succesbericht als het formulier succesvol is ingediend -->
    {#if successMessage}
      <p class="success-message">{successMessage}</p>
    {/if}

    <!-- Toon foutmelding als er een fout is bij het indienen van het formulier -->
    {#if errorMessage}
      <p class="error-message">{errorMessage}</p>
    {/if}

    <!-- Verstuurknop, die wordt uitgeschakeld tijdens het verzenden -->
    <button type="submit" class="btn btn-primary" disabled={isSubmitting}>
      {#if isSubmitting}
        Sending...
      {:else}
        Send
      {/if}
    </button>
  </form>
</section>

Wat doet de code?

  • De scriptsectie initialiseert variabelen en functies die nodig zijn voor de functionaliteit van het formulier.
  • Het formulier gebruikt de enhance functie om extra functionaliteit toe te voegen.
  • Het onMount lifecycle hook wordt gebruikt om een event listener toe te voegen aan het formulier om invoer te valideren.
  • Functies zoals handleInput en validateField valideren de invoer van de gebruiker en zorgen voor een real-time feedback op het formulier.
  • Het formulier toont fout- en succesberichten op basis van de validatie en het indienen van het formulier.
  • Zonder JS is er nog wel validatie maar niet met een succes bericht. Wel verstuurt het formulier.

+page.server.js

// Importeer de `fail` functie uit de SvelteKit library
import { fail } from '@sveltejs/kit';
// Importeer de `fetch` functie van node-fetch om HTTP verzoeken te kunnen doen
import fetch from 'node-fetch';

/** 
 * Definieer de acties voor het formulier 
 * @type {import('./$types').Actions} 
 */
export const actions = {
  // De standaard actie die wordt uitgevoerd wanneer het formulier wordt ingediend
  default: async ({ request }) => {
    // Haal de formulierdata op uit het verzoek
    const formData = await request.formData();
    const name = formData.get('name');
    const email = formData.get('email');
    const phone = formData.get('phone');
    const message = formData.get('message');

    // Controleer of de verplichte velden zijn ingevuld
    if (!name || !email || !message) {
      // Retourneer een fout als verplichte velden ontbreken
      return fail(400, { error: 'Vul alle vereiste velden in.', values: { name, email, phone, message } });
    }

    // Maak een payload met de formulierdata om naar de API te sturen
    const payload = {
      access_key: "b147c0e8-0571-4022-bbb0-06bb8b646914",
      name: name,
      email: email,
      phone: phone,
      message: message
    };

    try {
      // Verstuur de payload naar de externe API via een POST-verzoek
      const response = await fetch('https://api.web3forms.com/submit', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
      });

      // Parseer het antwoord van de API als JSON
      const result = await response.json();

      // Controleer of het antwoord succesvol was
      if (response.ok) {
        return {
          success: true,
          message: 'Uw bericht is verstuurd✅',
          values: { name: '', email: '', phone: '', message: '' }
        };
      } else {
        // Log de fout en retourneer een foutmelding als het verzoek niet succesvol was
        console.error('Response error:', result);
        return fail(500, { error: 'Er is iets misgegaan. Probeer het opnieuw.', values: { name, email, phone, message } });
      }
    } catch (err) {
      // Log de fout en retourneer een foutmelding als er een uitzondering is opgetreden
      console.error('Verzending mislukt:', err);
      return fail(500, { error: 'Er is iets misgegaan. Probeer het opnieuw.', values: { name, email, phone, message } });
    }
  }
};

Wat doet de code?

De code is een server-side actiehandler voor me formulier. Het verwerkt het indienen van een formulier, valideert de invoer, verstuurt de gegevens naar een externe API en geeft een reactie terug aan de eindgebruiker.

⚠️ **GitHub.com Fallback** ⚠️