Wat Gaan We Maken?

We bouwen een compleet registratie en login systeem met 2 pagina's:

  • Register pagina - nieuwe gebruikers aanmaken (eerste stap!)
  • Login pagina - inloggen met bestaand account

Hoe werkt de flow?

Nieuwe gebruiker
    |
    v
/register - Roep register() aan uit AuthContext
    |
    | AuthContext slaat account op in localStorage["users"]
    |
    v
/login - Roep login() aan uit AuthContext
    |
    | AuthContext checkt credentials in localStorage["users"]
    | Bij succes: zet user in state + localStorage["user"]
    |
    v
/dashboard - Gebruiker is ingelogd!
    |
    | AuthContext weet wie ingelogd is
    |
    v
Refresh? → Nog steeds ingelogd! (AuthContext leest localStorage["user"])

Belangrijk: Dit is een simpele versie met localStorage. Voor een echte app heb je een backend nodig met een database! Passwords worden nu in plain text opgeslagen - dit is ALLEEN voor oefenen.

Wat gaan we bouwen?

  1. Register form - gebruik register() uit AuthContext
  2. Login form - gebruik login() uit AuthContext
  3. Feedback - toon success/error berichten aan de gebruiker
  4. Navigatie - stuur gebruiker automatisch naar de juiste pagina

Het voordeel: We hoeven niet zelf met localStorage te werken! AuthContext doet al het werk. We roepen alleen de functies aan.

Start met de Register pagina hieronder - je moet eerst een account hebben voordat je kunt inloggen!

Register Page - Stap 1: Account Aanmaken

Voordat iemand kan inloggen, moet er eerst een account zijn! Daarom beginnen we met de register pagina.

Wat doet deze pagina?

1. Gebruiker vult username en password in
2. We roepen register() aan uit AuthContext
3. AuthContext checkt of username al bestaat en slaat account op
4. Bij succes: gebruiker wordt doorgestuurd naar login pagina

Maak een nieuw bestand: src/pages/Register.jsx

import { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";

function Register() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  
  const { register } = useContext(AuthContext);
  const navigate = useNavigate();

  const handleSubmit = (e) => {
    e.preventDefault();
    
    // Check of velden zijn ingevuld
    if (!username || !password) {
      setError("Vul alle velden in!");
      return;
    }

    // Roep register functie aan uit AuthContext
    const result = register(username, password);

    if (result.success) {
      // Succes! Ga naar login
      alert(result.message); // "Account aangemaakt!"
      navigate("/login");
    } else {
      // Er ging iets mis
      setError(result.message); // "Username bestaat al!"
    }
  };

  return (
    <div className="auth-container">
      <h1>Registreren</h1>
      
      <form onSubmit={handleSubmit}>
        <div>
          <label>Username:</label>
          <input
            type="text"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
        </div>

        <div>
          <label>Password:</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>

        {error && <p className="error">{error}</p>}

        <button type="submit">Registreren</button>
      </form>

      <p>
        Al een account? <a href="/login">Log hier in</a>
      </p>
    </div>
  );
}

export default Register;

Veel simpeler!

We hoeven niet zelf met localStorage te werken. De register() functie uit AuthContext doet al het werk voor ons!

Wat gebeurt er?

  1. User vult username en password in
  2. We roepen register(username, password) aan
  3. AuthContext checkt of username al bestaat
  4. AuthContext slaat het account op in localStorage["users"]
  5. We krijgen { success: true/false, message: "..." } terug
  6. Bij succes: navigate naar /login
  7. Bij fout: toon error message

Security warning:

Passwords worden in PLAIN TEXT opgeslagen! Dit is ALLEEN voor oefenen. In een echte app moet je passwords hashen met een backend!

Wat gebeurt er als je probeert in te loggen zonder eerst te registreren?

Dan zie je de error: "Verkeerde username of password!"
Want er staan nog geen users in localStorage["users"]. Je MOET eerst registreren voordat je kunt inloggen.

Login Page - Stap 2: Inloggen met Bestaand Account

Nu de gebruiker een account heeft (via register), kunnen ze inloggen!

Wat doet deze pagina?

1. Gebruiker vult username en password in
2. We roepen login() aan uit AuthContext
3. AuthContext checkt of de credentials kloppen
4. Bij succes: AuthContext slaat de ingelogde user op (in state + localStorage)
5. Gebruiker wordt doorgestuurd naar dashboard

Maak een nieuw bestand: src/pages/Login.jsx

import { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";

function Login() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  
  const { login } = useContext(AuthContext);
  const navigate = useNavigate();

  const handleSubmit = (e) => {
    e.preventDefault();
    
    // Check of velden zijn ingevuld
    if (!username || !password) {
      setError("Vul alle velden in!");
      return;
    }

    // Roep login functie aan uit AuthContext
    const result = login(username, password);
    
    if (result.success) {
      // Succes! Ga naar dashboard
      navigate("/dashboard");
    } else {
      // Er ging iets mis
      setError(result.message); // "Verkeerde username of password!"
    }
  };

  return (
    <div className="auth-container">
      <h1>Inloggen</h1>
      
      <form onSubmit={handleSubmit}>
        <div>
          <label>Username:</label>
          <input
            type="text"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
        </div>

        <div>
          <label>Password:</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>

        {error && <p className="error">{error}</p>}

        <button type="submit">Inloggen</button>
      </form>

      <p>
        Nog geen account? <a href="/register">Registreer hier</a>
      </p>
    </div>
  );
}

export default Login;

De magie gebeurt hier!

We gebruiken login() uit de AuthContext. Deze functie doet alles: checkt de credentials, logt de user in, en slaat het op in localStorage. Nu weet de hele app dat deze user is ingelogd!

Hoe werkt het?

  1. User vult username + password in
  2. We roepen login(username, password) aan
  3. AuthContext checkt in localStorage["users"] of dit account bestaat
  4. Als het klopt: AuthContext zet user in state en localStorage["user"]
  5. We krijgen { success: true, message: "Ingelogd!" } terug
  6. We navigeren naar dashboard
  7. Nu blijft de user ingelogd, zelfs na refresh!

Simpele Validatie

Je kunt makkelijk extra checks toevoegen:

1. Minimale Password Lengte

const handleSubmit = (e) => {
  e.preventDefault();
  
  if (password.length < 6) {
    setError("Password moet minimaal 6 karakters zijn!");
    return;
  }
  
  // Roep register/login aan...
};

2. Email Check (optioneel)

const handleSubmit = (e) => {
  e.preventDefault();
  
  if (!username.includes("@")) {
    setError("Gebruik een geldig email adres!");
    return;
  }
  
  // Roep register/login aan...
};

3. Password Match (voor register)

const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");

const handleSubmit = (e) => {
  e.preventDefault();
  
  if (password !== confirmPassword) {
    setError("Passwords komen niet overeen!");
    return;
  }
  
  // Roep register aan...
};

Tip: Laat de error message verdwijnen als de user weer begint te typen:

onChange={(e) => {
  setUsername(e.target.value);
  setError(""); // Error verdwijnt
}}

Styling Tips

Voeg wat basis CSS toe om het er professioneel uit te laten zien:

/* src/index.css */
.auth-container {
  max-width: 400px;
  margin: 50px auto;
  padding: 30px;
  border: 1px solid #ddd;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.auth-container h1 {
  text-align: center;
  margin-bottom: 30px;
}

.auth-container form div {
  margin-bottom: 20px;
}

.auth-container label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

.auth-container input {
  width: 100%;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.auth-container button {
  width: 100%;
  padding: 12px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
}

.auth-container button:hover {
  background: #0056b3;
}

.auth-container .error {
  color: red;
  margin: 10px 0;
  text-align: center;
}

.auth-container p {
  text-align: center;
  margin-top: 20px;
}

.auth-container a {
  color: #007bff;
  text-decoration: none;
}

.auth-container a:hover {
  text-decoration: underline;
}

Vergeet Routes Niet!

Voeg de routes toe in je App.jsx:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Login from "./pages/Login";
import Dashboard from "./pages/Dashboard";

function App() {
  return (
    <AuthProvider>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/register" element={<Register />} />
          <Route path="/login" element={<Login />} />
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </BrowserRouter>
    </AuthProvider>
  );
}

Test de Complete Flow!

Volg deze stappen om te testen of alles werkt:

Eerste Keer - Registreren

  1. Start je app met npm run dev
  2. Ga naar localhost:5173/register
  3. Vul een username in (bijvoorbeeld: "jan")
  4. Vul een password in (bijvoorbeeld: "test123")
  5. Klik op "Registreren"
  6. Je ziet een alert: "Account aangemaakt!"
  7. Je wordt automatisch doorgestuurd naar /login

Inloggen

  1. Op de login pagina, vul dezelfde username en password in
  2. Klik op "Inloggen"
  3. Je wordt doorgestuurd naar /dashboard
  4. Je ziet: "Welkom, jan!" op het dashboard

Check localStorage

  1. Open Chrome DevTools (F12)
  2. Ga naar tab "Application"
  3. Klik links op "Local Storage" → "http://localhost:5173"
  4. Je ziet nu 2 items:
    • users - array met alle geregistreerde accounts
    • user - de huidige ingelogde gebruiker

Test Persistentie

  1. Refresh de pagina (F5)
  2. Je bent nog steeds ingelogd!
  3. De username staat nog steeds in het dashboard

Het werkt! Je hebt nu een compleet registratie en login systeem:

  • Nieuwe users kunnen een account aanmaken via register()
  • Users kunnen inloggen via login()
  • Alle auth logica staat in AuthContext (consistent!)
  • Login blijft werken na refresh (dankzij localStorage)
  • AuthContext zorgt dat alle componenten weten wie ingelogd is

Tip voor testen:

Wil je opnieuw testen? Clear localStorage:
DevTools → Application → Local Storage → Rechtermuisklik → Clear

Volgende Stap

Nu gaan we routes beveiligen zodat alleen ingelogde users bij bepaalde pagina's kunnen!

Volgende

Protected Routes

Beveilig routes zodat alleen ingelogde users toegang hebben