Files
novi-lessons/v2/Les03-Cursor-Basics/Les03-Debug-Challenge-Hard-ANTWOORDEN.md
2026-02-27 13:56:19 +01:00

323 lines
9.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Debug Challenge HARD - Antwoordenblad (ALLEEN VOOR TIM)
**⚠️ NIET DELEN MET STUDENTEN**
---
## Overzicht
Dit project is aanzienlijk complexer dan de easy versie. Het bevat:
- Blog met dynamische routes
- Dashboard met statistieken
- API route voor quotes
- Utility functions
- TypeScript types
**12 fouten verspreid over 4 categorieën:**
- Blokkerende fouten (compile/runtime)
- Logische fouten (code draait maar werkt verkeerd)
- Pattern fouten (React anti-patterns)
- Styling fouten (inline styles + custom CSS → Tailwind)
**Geschatte tijd: 2-3 uur met AI**
---
## CATEGORIE 1: BLOKKERENDE FOUTEN
### Fout 1: Missing dependency — `clsx`
**Bestand:** `lib/utils.ts` (regel 2)
**Symptoom:**
```
Module not found: Can't resolve 'clsx'
```
**Oorzaak:** `clsx` wordt geïmporteerd maar staat niet in package.json.
`formatDate()` wordt overal gebruikt, dus dit blokkeert ALLES.
**Fix:**
```bash
npm install clsx
```
**Moeilijkheid:** ⭐ (makkelijk, zelfde als easy versie)
---
### Fout 2: Verkeerde import path — NextResponse
**Bestand:** `app/api/quotes/route.ts` (regel 2)
**Symptoom:**
```
Module not found: Can't resolve 'next/servers'
```
**Oorzaak:** `"next/servers"` moet `"next/server"` zijn (zonder s).
**Fix:**
```ts
// FOUT:
import { NextResponse } from "next/servers";
// CORRECT:
import { NextResponse } from "next/server";
```
**Moeilijkheid:** ⭐⭐ (subtiel — 1 letter verschil)
---
## CATEGORIE 2: LOGISCHE FOUTEN
### Fout 3: Array.slice() met verkeerde parameters
**Bestand:** `components/BlogPreview.tsx` (regel 7)
**Symptoom:** BlogPreview sectie op homepage toont GEEN posts (lege grid)
**Oorzaak:** `blogPosts.slice(-2, 0)` retourneert een lege array.
`slice(-2, 0)` betekent: start bij index -2 (2e van achteren), stop bij index 0 — dat is leeg!
**Fix:**
```ts
// FOUT:
const recentPosts = blogPosts.slice(-2, 0);
// CORRECT:
const recentPosts = blogPosts.slice(0, 2);
```
**Moeilijkheid:** ⭐⭐⭐ (geen error, gewoon lege output — student moet debuggen WAAROM)
---
### Fout 4: Icon mapping mist "star" entry
**Bestand:** `app/dashboard/page.tsx` (regel 25-30)
**Symptoom:** De "Rating" stat card toont geen icon (undefined rendered als leeg)
**Oorzaak:** `getIcon()` functie heeft entries voor "users", "eye", "clock" maar NIET voor "star". De stats array bevat wel `icon: "star"`.
**Fix:**
```ts
function getIcon(iconName: string) {
const icons: Record<string, React.ReactNode> = {
users: <Users size={24} />,
eye: <Eye size={24} />,
clock: <Clock size={24} />,
star: <Star size={24} />, // ← TOEVOEGEN
};
return icons[iconName];
}
```
**Moeilijkheid:** ⭐⭐⭐ (geen crash, subtiel visueel verschil)
---
### Fout 5: Mobile menu altijd verborgen
**Bestand:** `components/Header.tsx` (regel 62 + 73)
**Symptoom:** Hamburger menu knop is onzichtbaar, en zelfs als je `display: none` verwijdert van de button, is het dropdown menu ALSOOK `display: none`.
**Oorzaak:** Twee problemen:
1. De hamburger button heeft `display: 'none'` → onzichtbaar
2. Het mobile menu div heeft `display: 'none'` → zelfs als `menuOpen` true is
**Fix:** Dit moet volledig naar responsive Tailwind met `md:hidden`/`md:flex`:
```tsx
// Button: verberg op desktop, toon op mobiel
<button className="md:hidden" ...>
// Desktop nav: verberg op mobiel
<nav className="hidden md:flex gap-6" ...>
// Mobile menu: toon als flex wanneer open
{menuOpen && (
<div className="flex flex-col md:hidden p-3 border-t bg-white">
```
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist begrijpen van responsive design patterns)
---
## CATEGORIE 3: REACT PATTERN FOUTEN
### Fout 6: async functie in useEffect
**Bestand:** `app/dashboard/page.tsx` (regel 35-39)
**Symptoom:** React warning in console:
```
Warning: useEffect must not return anything besides a function
```
En mogelijke infinite loop.
**Oorzaak:** `useEffect(async () => {...})` is een React anti-pattern. async functie retourneert een Promise, maar useEffect verwacht `void` of een cleanup functie.
**Fix:**
```tsx
// FOUT:
useEffect(async () => {
const res = await fetch("/api/quotes");
...
}, [quote]);
// CORRECT:
useEffect(() => {
async function fetchQuote() {
const res = await fetch("/api/quotes");
const data = await res.json();
setQuote(data.text);
setLoading(false);
}
fetchQuote();
}, []); // ← ook dependency array gefixed (zie Fout 7)
```
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist kennis van React hooks patterns)
---
### Fout 7: Verkeerde dependency array → infinite loop
**Bestand:** `app/dashboard/page.tsx` (regel 39)
**Symptoom:** Dashboard pagina loopt vast, continue fetch requests in Network tab
**Oorzaak:** `[quote]` als dependency betekent: "run opnieuw als `quote` verandert". Maar de effect ZET quote, wat de effect OPNIEUW triggert → infinite loop.
**Fix:**
```tsx
// FOUT:
}, [quote]);
// CORRECT:
}, []); // Lege array = run 1x bij mount
```
**Moeilijkheid:** ⭐⭐⭐⭐ (vereist begrip van useEffect dependency arrays)
---
### Fout 8: Null check mist op quote state
**Bestand:** `components/QuoteOfTheDay.tsx` (regel 22)
**Symptoom:** `TypeError: Cannot read properties of null (reading 'text')`
**Oorzaak:** `quote` begint als `null`, maar zodra loading false is, probeert de component `quote.text` te lezen. Als de API fails of traag is, kan dit crashen.
**Fix:** Voeg TypeScript type toe en null check:
```tsx
// Verbeterde state typing:
const [quote, setQuote] = useState<{ text: string; author: string } | null>(null);
// In de render:
{!loading && quote && (
<>
<blockquote>"{quote.text}"</blockquote>
<cite> {quote.author}</cite>
</>
)}
```
**Moeilijkheid:** ⭐⭐⭐ (runtime error, maar duidelijke error message)
---
## CATEGORIE 4: STYLING FOUTEN (Inline Styles → Tailwind)
### Fout 9: Custom CSS classes in globals.css
**Bestand:** `app/globals.css`
**Probleem:** `.card`, `.page-container`, `.section-title` zijn custom CSS classes. Deze horen Tailwind utility classes te zijn.
**Fix:** Verwijder custom CSS uit globals.css. Vervang in alle componenten:
- `.card``className="p-6 bg-white rounded-xl border border-gray-200 hover:shadow-lg hover:-translate-y-0.5 transition-all"`
- `.page-container``className="max-w-[1200px] mx-auto px-5"`
- `.section-title``className="text-3xl font-bold text-center mb-10 text-gray-900"`
**Moeilijkheid:** ⭐⭐⭐ (moet begrijpen waarom Tailwind beter is dan custom CSS)
---
### Fout 10-12: Inline styles in alle componenten
**Bestanden met inline styles:**
| # | Bestand | Complexiteit |
|---|---------|-------------|
| 10 | `components/Hero.tsx` | Hoog (gradient, positioning) |
| 11 | `components/Header.tsx` | Hoog (responsive, sticky) |
| 12 | `components/Footer.tsx` | Medium (grid, links) |
| - | `components/StatsSection.tsx` | Medium (grid) |
| - | `components/BlogPreview.tsx` | Medium (grid, cards) |
| - | `components/QuoteOfTheDay.tsx` | Laag |
| - | `app/blog/page.tsx` | Medium (grid, tags) |
| - | `app/blog/[slug]/page.tsx` | Medium (article layout) |
| - | `app/dashboard/page.tsx` | Hoog (stats grid, cards) |
**Studenten moeten minimaal 3-4 bestanden omzetten.**
**Aanpak:**
1. Selecteer inline style code
2. `Ctrl+K` → "Converteer inline styles naar Tailwind CSS. Gebruik de brand- kleuren uit tailwind.config.ts waar mogelijk."
3. Review + Accept
**Moeilijkheid:** ⭐⭐ per bestand (maar het zijn er VEEL)
---
## Samenvatting Alle Fouten
| # | Type | Bestand | Ernst | Moeilijkheid |
|---|------|---------|-------|-------------|
| 1 | Missing dependency (clsx) | lib/utils.ts | 🔴 Blokkerend | ⭐ |
| 2 | Verkeerde import (next/servers) | api/quotes/route.ts | 🔴 Blokkerend | ⭐⭐ |
| 3 | Verkeerde slice() params | BlogPreview.tsx | 🟡 Logisch | ⭐⭐⭐ |
| 4 | Missende icon mapping | dashboard/page.tsx | 🟡 Logisch | ⭐⭐⭐ |
| 5 | Mobile menu altijd hidden | Header.tsx | 🟡 Logisch | ⭐⭐⭐⭐ |
| 6 | async in useEffect | dashboard/page.tsx | 🟠 Anti-pattern | ⭐⭐⭐⭐ |
| 7 | Infinite loop dep array | dashboard/page.tsx | 🔴 Runtime crash | ⭐⭐⭐⭐ |
| 8 | Null check quote state | QuoteOfTheDay.tsx | 🔴 Runtime crash | ⭐⭐⭐ |
| 9 | Custom CSS → Tailwind | globals.css | 🟡 Styling | ⭐⭐⭐ |
| 10-12 | Inline styles (9+ bestanden) | Overal | 🟡 Styling | ⭐⭐ elk |
---
## Verwachte Oplos-Volgorde
1. `npm install` → werkt
2. `npm run dev``Can't resolve 'clsx'``npm install clsx`
3. `npm run dev``Can't resolve 'next/servers'` → fix import
4. Site laadt! Maar:
- BlogPreview is leeg → fix slice()
- Dashboard crasht/loopt vast → fix useEffect + dep array
- Quote component crasht → fix null check
- Rating icon mist → fix icon mapping
- Mobile menu werkt niet → fix responsive
5. Inline styles → Tailwind conversie
6. Custom CSS → Tailwind refactor
---
## Verwacht Request Gebruik
| Actie | Requests |
|-------|----------|
| Debug blokkerende errors (Chat) | 2-3 |
| Fix logische fouten (Chat + Edit) | 3-4 |
| Fix React patterns (Chat) | 2-3 |
| Inline styles → Tailwind (Inline Edit × 4-5) | 4-5 |
| **Totaal** | **11-15 requests** |
⚠️ Dit is meer dan de easy versie. Studenten op Hobby plan moeten efficiënt werken. Student plan (500/maand) is ruim voldoende.
---
## Tips voor Tim
- **Dit is echt moeilijk.** Fout 5, 6, 7 zijn lastig voor beginners. Verwacht dat studenten hier hulp bij nodig hebben.
- **De useEffect fouten** zijn een goed leermoment — dit is een HEEL veelvoorkomende bug in React.
- **De slice() bug** is een subtiele logische fout. Studenten moeten leren: "het werkt zonder errors, maar het resultaat klopt niet" → debuggen.
- **Mobile menu** is bewust moeilijk. Dit vereist dat ze responsive design begrijpen. Goede Cursor prompt: "Maak deze header responsive met een hamburger menu dat werkt op mobiel met Tailwind."
- **Geef de easy zip als standaard.** Hard is voor studenten die de easy versie snel af hebben of die extra uitdaging willen.