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

15 KiB

DevDash - Super Hard Debug Challenge (16-18 Errors)

Challenge Overview

This is the super hard tier debug challenge with 16-18 intentional errors distributed across 6 categories. Students must identify and fix all errors to make the project run successfully.


CATEGORY 1: BLOCKING ERRORS (3 Errors)

Error 1: Missing Dependency - date-fns

File: src/lib/utils.ts

Issue: The code imports format from date-fns:

import { format } from "date-fns";

But date-fns is NOT listed in package.json.

Symptom: Runtime error: "Cannot find module 'date-fns'"

Fix: Add to package.json dependencies:

"dependencies": {
  "date-fns": "^2.30.0"
}

Error 2: Wrong Import Path - next/navigations (with 's')

File: src/components/Header.tsx

Issue:

import { usePathname } from "next/navigations";  // WRONG - has 's'

Should be:

import { usePathname } from "next/navigation";   // CORRECT

Symptom: Module not found error at build time

Fix: Remove the 's' from the import path.


Error 3: Circular Dependency Crash

Files: src/lib/types.ts and src/lib/utils.ts

Issue:

In src/lib/utils.ts:

import { formatDate } from "./utils";  // Value import, not type

In src/lib/types.ts:

import { formatDate } from "./utils";

export function createPost(data: Omit<Post, "formattedDate">): Post {
  return { ...data, formattedDate: formatDate(data.date) };  // formatDate is undefined!
}

Symptom: TypeError: formatDate is not a function at runtime

Fix: Use import type for types to avoid the circular dependency:

In src/lib/utils.ts:

import type { Post } from "./types";  // Change to type import

Alternatively, restructure to avoid circular imports altogether.


CATEGORY 2: NEXT.JS SPECIFIC ERRORS (4 Errors)

Error 4: Missing "use client" Directive

File: src/components/ThemeToggle.tsx

Issue: The component uses useState (a client-side hook) but lacks "use client" at the top.

// MISSING "use client" at the top!
import { useState } from 'react';
export function ThemeToggle() {
  const [isHovered, setIsHovered] = useState(false);
  // ...
}

Symptom: Next.js error: "You're importing a component that needs useState. It only works in Client Components."

Fix: Add at the very top of the file:

"use client";

import { useState } from 'react';

Error 5: Hooks in Server Component

File: src/app/dashboard/page.tsx

Issue: The page uses useState and useEffect directly:

// MISSING "use client" at the top!
import { useState, useEffect } from 'react';

export default function DashboardPage() {
  const [isLoading, setIsLoading] = useState(false);
  // ...
}

Symptom: Hydration error or "You're importing a component that needs useState"

Fix: Add "use client" directive at the top:

"use client";

import { useState, useEffect } from 'react';

Error 6: Wrong Middleware Matcher Pattern

File: middleware.ts

Issue:

export const config = {
  matcher: ['/dashboard/:path'],  // WRONG - missing asterisk
};

This matches /dashboard/:path but NOT /dashboard/page/subpage. The sub-routes won't be protected.

Also, the middleware looks for 'auth-token' cookie but the app doesn't set one:

const authToken = request.cookies.get('auth-token')?.value;

Symptom: Sub-routes of dashboard bypass middleware; authentication doesn't work

Fix:

export const config = {
  matcher: ['/dashboard/:path*'],  // Add asterisk for all sub-routes
};

And update cookie name to match what's actually used or create a mock auth mechanism.


Error 7: metadata Export in Client Component

File: src/app/blog/[slug]/page.tsx

Issue:

'use client';  // This is a CLIENT component

export const metadata = {  // Can't export metadata from client!
  title: 'Blog Post',
  description: 'Read the full article',
};

import { useParams } from 'next/navigation';

Symptom: Build error: "Metadata exports must be in a Server Component"

Fix (Option 1): Remove 'use client' and use function parameters instead of useParams():

// Remove "use client"
import { generateMetadata } from 'next';
import type { Metadata } from 'next';

export async function generateMetadata({ params }): Promise<Metadata> {
  const post = getPostBySlug(params.slug);
  return {
    title: post?.title || 'Blog Post',
    description: post?.content.substring(0, 100) || '',
  };
}

export default function BlogPostPage({ params }: { params: { slug: string } }) {
  const post = getPostBySlug(params.slug);
  // ...
}

Fix (Option 2): Keep as client component and remove metadata export:

'use client';

// Remove metadata export

import { useParams } from 'next/navigation';
// ... rest of component

CATEGORY 3: LOGIC ERRORS (3 Errors)

Error 8: Wrong Filter Condition

File: src/data/posts.ts

Issue:

export function getPublishedPosts(): Post[] {
  return posts.filter(p => p.draft);  // WRONG - returns DRAFTS!
}

Should check for !p.draft (NOT drafted):

export function getPublishedPosts(): Post[] {
  return posts.filter(p => !p.draft);  // CORRECT
}

Symptom: Blog page shows only draft posts (only 1 post visible instead of 2 published ones)

Fix: Change condition to !p.draft.


Error 9: Stale Closure in Event Handler

File: src/components/Testimonials.tsx

Issue:

useEffect(() => {
  const timer = setInterval(() => {
    setCurrentIndex(currentIndex + 1);  // STALE CLOSURE!
  }, 4000);
  return () => clearInterval(timer);
}, []);  // Empty dependency array captures initial value

The currentIndex is captured from the initial render (0). The interval always increments from 0 to 1, causing the carousel to jump back repeatedly.

Symptom: Testimonial carousel doesn't advance smoothly; always jumps to position 1

Fix: Use the functional update form of setState:

useEffect(() => {
  const timer = setInterval(() => {
    setCurrentIndex(prev => (prev + 1) % testimonials.length);  // Use prev!
  }, 4000);
  return () => clearInterval(timer);
}, []);

Error 10: Using Index as Key

File: src/components/Features.tsx

Issue:

{displayedFeatures.map((feature, index) => (
  <div key={index}>  // WRONG - using index as key
    {/* ... */}
  </div>
))}

Using index as key is problematic if the list reorders or filters.

Symptom: Visual glitches when filtering features; component state gets mixed up

Fix: Use unique identifier:

{displayedFeatures.map((feature) => (
  <div key={feature.id}>  // Use feature.id
    {/* ... */}
  </div>
))}

CATEGORY 4: TYPESCRIPT ERRORS (2 Errors)

Error 11: Wrong API Response Type

File: src/app/api/stats/route.ts and src/components/StatsGrid.tsx

Issue:

API returns wrapped response:

// src/app/api/stats/route.ts
return NextResponse.json({ data: stats });  // Wrapped in { data: ... }

But component expects unwrapped array:

// src/components/StatsGrid.tsx
const data = await response.json();
setStats(data);  // Expects data to be array, but gets { data: [...] }

Later:

{stats.map((stat, index) => (  // stats is an object, not array!

Symptom: TypeError: stats.map is not a function

Fix - Option 1: Unwrap in component:

const data = await response.json();
setStats(data.data);  // Extract the array

Fix - Option 2: Change API response:

return NextResponse.json(stats);  // Return array directly

Error 12: Missing Optional Chaining

File: src/components/UserProfile.tsx

Issue:

{user.profile.avatar}  // profile could be undefined!

The API might return a user without a profile object:

const user: User = {
  id: '1',
  name: 'John',
  email: 'john@example.com',
  // profile is undefined!
};

Symptom: TypeError: Cannot read property 'avatar' of undefined

Fix: Use optional chaining:

{user.profile?.avatar}  // Safe access

Or add a null check:

{user.profile && user.profile.avatar}

CATEGORY 5: REACT PATTERN ERRORS (3 Errors)

Error 13: Missing useEffect Cleanup

File: src/app/dashboard/page.tsx

Issue:

useEffect(() => {
  window.addEventListener('resize', handleResize);
  // Missing cleanup!
  // Should have: return () => window.removeEventListener('resize', handleResize);
}, []);

Symptom: Memory leak; listeners accumulate when component remounts; "Can't perform a React state update on an unmounted component" warnings

Fix: Add cleanup function:

useEffect(() => {
  function handleResize() {
    setIsLoading(window.innerWidth < 768);
  }

  window.addEventListener('resize', handleResize);
  
  // Add cleanup
  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);

Error 14: Incorrect Context Provider Wrapping

File: src/app/layout.tsx

Issue:

<body>
  <Header />  {/* Header tries to use theme context but provider hasn't wrapped it yet! */}
  <ThemeProvider>
    <main>
      {children}
    </main>
    <Footer />
  </ThemeProvider>
</body>

The Header component is rendered BEFORE the ThemeProvider, so it can't access the theme context.

Symptom: Error in Header when trying to use useTheme(): "useTheme must be used within ThemeProvider"

Fix: Move provider to wrap everything:

<body>
  <ThemeProvider>
    <Header />
    <main>
      {children}
    </main>
    <Footer />
  </ThemeProvider>
</body>

Error 15: Prop Drilling Mistake - Wrong Prop Name

File: src/app/blog/page.tsx and src/components/BlogCard.tsx

Issue:

BlogCard expects post:

// src/components/BlogCard.tsx
export function BlogCard({ post }: { post: Post }) {
  return (
    <article>
      <h3>{post?.title || 'Untitled'}</h3>
      {/* ... */}
    </article>
  );
}

But blog page passes blogPost:

// src/app/blog/page.tsx
{posts.map((post) => (
  <BlogCard key={post.slug} blogPost={post} />  // WRONG prop name!
))}

Symptom: BlogCard displays "Untitled" and "Date unknown"; content is empty

Fix: Use correct prop name:

{posts.map((post) => (
  <BlogCard key={post.slug} post={post} />  // Correct
))}

CATEGORY 6: STYLING ERRORS (3 Errors)

Error 16: Custom CSS Classes Instead of Tailwind

File: src/app/globals.css

Issue: The stylesheet defines custom classes:

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1rem;
}

.card {
  background-color: white;
  border-radius: 0.5rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  padding: 1.5rem;
}

.btn-primary {
  background-color: #3b82f6;
  color: white;
  /* ... more styles ... */
}

In a Tailwind project, these should be Tailwind classes, not custom CSS.

Symptom: Custom classes work but don't align with Tailwind approach; styling is scattered between CSS and inline styles

Fix: Replace with Tailwind classes or @apply directives:

@layer components {
  .container {
    @apply max-w-5xl mx-auto px-4;
  }
  
  .card {
    @apply bg-white rounded-lg shadow p-6;
  }
  
  .btn-primary {
    @apply bg-blue-500 text-white px-6 py-3 rounded transition-colors hover:bg-blue-600;
  }
}

Error 17-18: Inline Styles Instead of Tailwind Classes

Files: Multiple components use inline style={{}} instead of Tailwind:

  • src/components/Header.tsx - All styling is inline
  • src/components/Hero.tsx - All styling is inline
  • src/components/Features.tsx - All styling is inline
  • src/components/Testimonials.tsx - All styling is inline
  • src/components/StatsGrid.tsx - All styling is inline
  • src/components/BlogCard.tsx - All styling is inline
  • src/components/UserProfile.tsx - All styling is inline
  • And more...

Example Issue:

<header style={{ 
  backgroundColor: '#ffffff', 
  borderBottom: '1px solid #e5e7eb', 
  padding: '1rem 0' 
}}>
  {/* ... */}
</header>

Should be:

<header className="bg-white border-b border-gray-200 py-4">
  {/* ... */}
</header>

Symptom: Project uses Tailwind but styling isn't using Tailwind; inconsistent; not maintainable

Fix: Convert all inline styles to Tailwind classes. Example conversions:

backgroundColor: '#ffffff' → bg-white
borderBottom: '1px solid #e5e7eb' → border-b border-gray-200
padding: '1rem 0' → py-4
fontSize: '1.5rem' → text-2xl
fontWeight: 'bold' → font-bold
display: 'flex' → flex
gap: '1rem' → gap-4
justifyContent: 'center' → justify-center
alignItems: 'center' → items-center

Summary Table

# Category Error File Severity
1 Blocking Missing date-fns lib/utils.ts CRITICAL
2 Blocking Wrong import next/navigations components/Header.tsx CRITICAL
3 Blocking Circular dependency lib/types.ts, lib/utils.ts CRITICAL
4 Next.js Missing "use client" components/ThemeToggle.tsx CRITICAL
5 Next.js Hooks in server component app/dashboard/page.tsx CRITICAL
6 Next.js Wrong matcher pattern middleware.ts HIGH
7 Next.js Metadata in client component app/blog/[slug]/page.tsx CRITICAL
8 Logic Wrong filter condition data/posts.ts MEDIUM
9 Logic Stale closure components/Testimonials.tsx MEDIUM
10 Logic Index as key components/Features.tsx MEDIUM
11 TypeScript API response type mismatch api/stats/route.ts, components/StatsGrid.tsx HIGH
12 TypeScript Missing optional chaining components/UserProfile.tsx MEDIUM
13 React Missing useEffect cleanup app/dashboard/page.tsx HIGH
14 React Wrong provider wrapping app/layout.tsx CRITICAL
15 React Wrong prop name app/blog/page.tsx, components/BlogCard.tsx MEDIUM
16 Styling Custom CSS classes app/globals.css LOW
17-18 Styling Inline styles (8+ components) Multiple components LOW

Debugging Strategy

  1. Start with blocking errors (1-3) - These prevent the app from running at all
  2. Fix Next.js errors (4-7) - These cause build-time failures
  3. Address logic errors (8-10) - These cause runtime misbehavior
  4. Resolve TypeScript errors (11-12) - These break specific features
  5. Fix React patterns (13-15) - These cause memory leaks and state issues
  6. Clean up styling (16-18) - These improve code quality and maintainability

Testing Checklist

After fixing all errors:

  • App builds without errors: npm run build
  • Dev server runs: npm run dev
  • Homepage loads with Hero, Features, Testimonials
  • All navigation links work
  • Blog page shows published posts (2 posts, not drafts)
  • Blog post pages load correctly
  • Dashboard page loads with stats and user profile
  • Theme toggle works (if fixed)
  • Carousel auto-advances smoothly
  • No console errors
  • No memory leaks in browser dev tools