fix: debug challenge

This commit is contained in:
Tim Rijkse
2026-02-24 21:16:03 +01:00
parent 35bbc50c06
commit db43842d51
13 changed files with 3933 additions and 253 deletions

View File

@@ -0,0 +1,322 @@
# 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.