// 이 파일이 하는 일: "React 입문" 코스 — 화면이 왜 '상태의 함수'인지에서 출발해
// 컴포넌트·JSX·props/state·이벤트·목록 렌더링·useEffect까지, 우리 학습 플랫폼
// 프론트엔드 코드를 실제 교재 삼아 8개 섹션으로 안내하는 정적 학습 페이지.
// 학습 포인트: API 호출이 없는 '내용 고정' 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색을 여기서 하드코딩하지 않는다.
// 예제 코드는 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.
// (이 파일 자체가 React 컴포넌트라서, "React를 설명하는 React 코드"라는 재귀 개그가 성립해요.)

import { Link } from 'react-router-dom';

// ── 예제 코드 상수들 ──

const CODE_STATE_FN = `React의 핵심 아이디어 딱 한 줄:

    화면(UI) = f(상태)

옛날 방식 (직접 조작):            React 방식 (선언):
──────────────────────       ──────────────────────
"버튼 눌리면 저 글자를           "count가 3이면 화면엔
 찾아서 3으로 바꿔"              '3'이 보여야 해" 라고
 (내가 화면을 일일이 수정)        선언만 하면, 바뀐 부분은
                                React가 알아서 갱신

비유: 옛날 방식은 칠판에 쓴 글씨를 지우개로 지우고 다시 쓰는 것.
React는 "정답지(상태)"만 고치면 칠판(화면)이 스스로 따라 바뀌는 마법 칠판.`;

const CODE_COMPONENT = `// 컴포넌트 = 내가 만든 나만의 HTML 태그 (레고 블록 한 개)
function Badge({ label }) {
  return <span className="badge">{label}</span>;
}

// 한 번 만들면 어디서든 조립!
function ProfileCard() {
  return (
    <div className="card">
      <h3>김미림</h3>
      <Badge label="3학년" />
      <Badge label="프론트엔드" />   {/* 같은 블록, 다른 글자 */}
    </div>
  );
}

// 우리 플랫폼 화면도 전부 이런 블록들의 조립이에요:
// <App> → <Layout> → <DashboardPage> → <Card> → <Badge> ...`;

const CODE_JSX_RULES = `JSX 필수 규칙 4가지 — 처음에 100% 한 번씩 틀리는 것들!

1) 태그는 반드시 닫는다
   <img src="...">        ❌  HTML에선 됐지만
   <img src="..." />      ✅  JSX에선 셀프 클로징 필수

2) class 대신 className
   <div class="card">     ❌  class는 자바스크립트 예약어
   <div className="card"> ✅

3) 중괄호 { } = 자바스크립트 구멍
   <p>안녕, {name}님! 내년엔 {grade + 1}학년</p>
   → 따옴표 안이 아니라 중괄호 안이 '살아있는 코드'

4) 형제 태그는 하나로 감싼다
   return <h1>제목</h1><p>내용</p>       ❌  둘을 동시에 반환 불가
   return <><h1>제목</h1><p>내용</p></>  ✅  <>...</> (Fragment)로 포장`;

const CODE_PROPS_STATE = `props — 부모가 자식에게 주는 선물          state — 내가 관리하는 내 소지품
─────────────────────────────       ─────────────────────────────
부모 → 자식, 한 방향으로만 전달          컴포넌트 자신이 만들고 바꿈
받은 쪽에서 바꿀 수 없음(읽기 전용)       바꾸면 화면이 다시 그려짐!
"이름표에 이 글자를 써 줘"              "지금 몇 번 클릭됐는지 기억해 줘"

// props: 부모가 값을 내려 줌
<Badge label="3학년" />

// state: useState로 내 상태 만들기
import { useState } from 'react';

function LikeButton() {
  const [count, setCount] = useState(0);  // [현재값, 바꾸는 함수]

  return (
    <button onClick={() => setCount(count + 1)}>
      좋아요 {count}
    </button>
  );
}

⚠ count = count + 1 처럼 직접 바꾸면 화면이 안 바뀌어요.
   반드시 setCount()를 불러야 React가 "아, 다시 그려야겠구나" 알아챕니다.`;

const CODE_EVENTS = `// 이벤트 처리 — HTML의 onclick과 비슷하지만, 문자열이 아니라 '함수'를 건네요
function LoginForm() {
  const [email, setEmail] = useState('');

  function handleSubmit(e) {
    e.preventDefault();          // 폼의 기본 동작(새로고침) 막기
    alert(email + ' 확인!');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="이메일"
      />
      <button type="submit">확인</button>
    </form>
  );
}

// 포인트: onClick={handleSubmit}   ✅ 함수를 '건네줌' (눌리면 실행해 줘)
//         onClick={handleSubmit()} ❌ 지금 당장 '실행'해 버림 (초보 함정 1위!)`;

const CODE_LIST_KEY = `// 목록 렌더링 — 배열.map()으로 데이터를 JSX 블록으로 '변신'시키기
const courses = [
  { id: 1, title: '네트워크의 이해' },
  { id: 2, title: 'React 입문' },
  { id: 3, title: 'Docker 첫걸음' },
];

function CourseList() {
  return (
    <ul>
      {courses.map((c) => (
        <li key={c.id}>{c.title}</li>   // ← key 필수!
      ))}
    </ul>
  );
}

// key는 왜? React가 목록을 다시 그릴 때 "누가 누구인지" 알아보는 이름표예요.
// 출석부에 이름 없이 '앞에서 3번째 애'로만 부르면, 자리만 바뀌어도
// 다 헷갈리죠. 학번(id)으로 부르면 자리를 바꿔도 정확히 그 사람.
// 그래서 key={index}(자리 번호)보다 key={c.id}(학번)가 좋습니다.`;

const CODE_USE_EFFECT = `// useEffect — "화면을 그린 다음에 이 일을 해 줘" (우리 대시보드 실제 패턴)
import { useState, useEffect } from 'react';

function DashboardPage() {
  const [stats, setStats] = useState(null);     // ① 처음엔 데이터 없음

  useEffect(() => {                             // ② 화면이 먼저 그려진 '뒤에'
    fetch('/api/dashboard/stats')               //    서버에 데이터 요청
      .then((res) => res.json())
      .then((data) => setStats(data));          // ③ 도착하면 state에 저장
  }, []);                                       // ④ [] = 처음 한 번만 실행

  if (!stats) return <p>불러오는 중...</p>;      // ⑤ 데이터 오기 전 화면
  return <p>이번 주 학습 {stats.hours}시간!</p>; // ⑥ 도착 후 자동 재렌더!

  // 흐름: 빈 화면 렌더 → 요청 출발 → 응답 도착 → setStats →
  //       "상태가 바뀌었네?" → React가 화면을 다시 그림. 끝.
}

// 마지막 [](의존성 배열)이 실행 타이밍 스위치:
// []        → 처음 등장할 때 한 번만 (데이터 로딩의 단골)
// [userId]  → userId가 바뀔 때마다 다시
// 없음      → 매 렌더마다 (거의 실수! 무한 요청 폭탄 주의)`;

const CODE_FOLDER = `우리 프론트엔드 폴더 — 이제 다르게 보일 거예요 (frontend/src/)

src/
├── pages/          ← 화면 한 장 = 컴포넌트 한 개 (지금 이 페이지도 여기!)
│   ├── DashboardPage.jsx    섹션 7의 useEffect 패턴이 진짜로 있음
│   ├── NetworkPage.jsx      "네트워크의 이해" 코스
│   └── courses/
│       └── ReactIntroPage.jsx   ← 지금 읽고 있는 바로 이 파일!
├── components/     ← 여러 페이지가 같이 쓰는 레고 블록 (섹션 2의 Badge·Card)
├── App.jsx         ← react-router-dom으로 "URL → 어느 페이지" 연결
└── main.jsx        ← React를 index.html에 꽂아 넣는 시동 버튼

읽는 순서 추천: main.jsx → App.jsx(라우팅) → pages 하나 → 그 안의 components.
큰 데서 작은 데로, 조립도 → 블록 순서로 읽으면 길을 잃지 않아요.`;

const CODE_PRACTICE = `STUDY.md 미니 과제 3종 — 오늘 배운 걸 손으로 굳히기

과제 A. 나만의 Badge 만들기 (섹션 2·4)
   components/에 MyBadge.jsx를 만들고, props로 label과 color를
   받아 표시. 아무 페이지에나 <MyBadge label="연습중" /> 붙여 보기.

과제 B. 좋아요 버튼 (섹션 4·5)
   useState + onClick으로 누를 때마다 숫자가 올라가는 버튼.
   심화: 10 이상이면 "🔥 인기!" 글자가 나타나게 (조건부 렌더링).

과제 C. 내 코스 목록 (섹션 6)
   배열 상수를 만들어 .map()으로 <li> 목록 렌더링.
   key를 일부러 빼고 저장 → 브라우저 콘솔(F12)의 경고를 직접 목격!

제출: Gitea(edu.awesomedevapp.com:3000)에 브랜치 만들어 커밋 & PR.
멘토가 코드 리뷰로 피드백을 답니다 — 실무 흐름 그대로!`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. props만 바꿔 재사용.
// (섹션 2에서 배우는 내용을 이 파일이 스스로 실천하고 있어요.)
function Section({ n, title, sub, children }) {
  return (
    <section className="step-card" id={`sec-${n}`}>
      <div className="step-head">
        <span className="step-num">{n}</span>
        <div>
          <h3>{title}</h3>
          {sub && <span className="step-sub">{sub}</span>}
        </div>
      </div>
      <div className="step-body">{children}</div>
    </section>
  );
}

function Code({ children }) {
  return <pre className="code-block"><code>{children}</code></pre>;
}

const SECTIONS = [
  { n: 1, label: '왜 React인가' },
  { n: 2, label: '컴포넌트 = 레고' },
  { n: 3, label: 'JSX 규칙' },
  { n: 4, label: 'props와 state' },
  { n: 5, label: '이벤트 처리' },
  { n: 6, label: '목록과 key' },
  { n: 7, label: 'useEffect 한 입' },
  { n: 8, label: '폴더 구조 + 실습' },
];

export default function ReactIntroPage() {
  return (
    <div>
      {/* 히어로: 이 코스가 어디서 출발해 어디까지 가는지 */}
      <div className="hero">
        <div className="eyebrow">Course · 소프트웨어</div>
        <h1>React 입문<br />— 화면은 상태의 함수다</h1>
        <p>
          지금 보고 있는 이 학습 플랫폼의 화면 전부가 React로 만들어졌어요.
          "화면 = 상태의 함수"라는 한 문장에서 출발해, 컴포넌트·props·state·useEffect까지 —
          <strong> 우리 코드베이스를 교재 삼아</strong> React의 뼈대를 세워 봅니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 90분</span>
          <span className="chip">실습 과제 3개</span>
          <span className="chip">선수 지식: HTML·JS 기초</span>
        </div>
      </div>

      {/* 섹션 바로가기 */}
      <nav className="pill-nav">
        {SECTIONS.map((s) => (
          <a key={s.n} href={`#sec-${s.n}`}>
            <b>{s.n}</b>
            {s.label}
          </a>
        ))}
      </nav>

      <Section n={1} title="왜 React인가" sub="화면 = f(상태), 이 한 줄이 전부">
        <p>
          자바스크립트만으로도 화면을 바꿀 수 있어요. 문제는 <strong>규모</strong>입니다.
          버튼 하나가 화면 다섯 군데를 바꿔야 한다면? "어느 글자를 찾아서, 뭘로 바꾸고,
          저 목록도 갱신하고..." — 화면을 <strong>직접 조작</strong>하는 코드는 페이지가
          커질수록 스파게티가 돼요.
        </p>
        <p>
          React의 답은 발상의 전환이에요. 화면을 조작하지 말고, <strong>"상태가 이러면
          화면은 이렇게 생겨야 한다"고 선언만 하자.</strong> 상태(데이터)가 바뀌면 React가
          바뀐 부분만 골라 다시 그려 줍니다. 우리는 정답지만 고치면 돼요.
        </p>
        <Code>{CODE_STATE_FN}</Code>
        <div className="tip">
          <b>미리 보는 큰 그림</b> 이 코스 전체가 이 한 줄의 각주예요.
          컴포넌트(2)는 f를 쪼개는 법, state(4)는 '상태' 그 자체,
          useEffect(7)는 상태를 서버에서 채우는 법입니다.
        </div>
      </Section>

      <Section n={2} title="컴포넌트 = 레고 블록" sub="우리 플랫폼의 Badge·Card가 살아있는 실례">
        <p>
          React 앱은 거대한 한 덩어리가 아니라 <strong>레고 블록(컴포넌트)의 조립</strong>이에요.
          컴포넌트는 "JSX를 반환하는 자바스크립트 함수" — 즉, <strong>내가 만든 나만의
          HTML 태그</strong>입니다. 한 번 만들면 <span className="icode">&lt;Badge /&gt;</span>처럼
          몇 번이고 꽂아 쓸 수 있죠.
        </p>
        <Code>{CODE_COMPONENT}</Code>
        <p>
          멀리 갈 것 없이 <strong>우리 플랫폼이 실례</strong>예요. 대시보드의 코스 카드,
          "수강 중" 뱃지, 위쪽 내비게이션 — 전부{' '}
          <span className="icode">frontend/src/components/</span>에 사는 블록들이고,
          페이지마다 재조립되고 있을 뿐입니다.
        </p>
        <svg className="diagram" viewBox="0 0 640 380" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="컴포넌트 트리: App에서 Layout, 페이지, Card, Badge로 이어지는 조립 구조와 위에서 아래로 한 방향으로 흐르는 props">
          <line x1="320" y1="54" x2="320" y2="86" stroke="var(--line)" strokeWidth="2" />
          <line x1="320" y1="124" x2="185" y2="160" stroke="var(--line)" strokeWidth="2" />
          <line x1="320" y1="124" x2="455" y2="160" stroke="var(--line)" strokeWidth="2" />
          <line x1="185" y1="198" x2="165" y2="234" stroke="var(--line)" strokeWidth="2" />
          <line x1="165" y1="270" x2="110" y2="308" stroke="var(--line)" strokeWidth="2" />
          <line x1="165" y1="270" x2="230" y2="308" stroke="var(--line)" strokeWidth="2" />
          <rect x="270" y="16" width="100" height="38" rx="8" fill="var(--card)" stroke="var(--primary)" strokeWidth="2" />
          <text x="320" y="40" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">&lt;App&gt;</text>
          <rect x="270" y="86" width="100" height="38" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="320" y="110" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;Layout&gt;</text>
          <rect x="95" y="160" width="180" height="38" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="185" y="184" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;DashboardPage&gt;</text>
          <rect x="365" y="160" width="180" height="38" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="455" y="184" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;ReactIntroPage&gt;</text>
          <rect x="110" y="234" width="110" height="36" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="165" y="257" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;Card&gt;</text>
          <rect x="60" y="308" width="100" height="36" rx="8" fill="var(--card)" stroke="var(--teal)" />
          <text x="110" y="331" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;Badge /&gt;</text>
          <rect x="180" y="308" width="100" height="36" rx="8" fill="var(--card)" stroke="var(--teal)" />
          <text x="230" y="331" textAnchor="middle" fontSize="13" fill="var(--ink)">&lt;Badge /&gt;</text>
          <text x="110" y="366" textAnchor="middle" fontSize="12" fill="var(--muted)">label="3학년"</text>
          <text x="230" y="366" textAnchor="middle" fontSize="12" fill="var(--muted)">label="프론트엔드"</text>
          <line x1="600" y1="44" x2="600" y2="326" stroke="var(--primary)" strokeWidth="2" strokeDasharray="5 4" />
          <path d="M600 338 L593 324 L607 324 Z" fill="var(--primary)" />
          <text x="600" y="32" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--primary)">props</text>
          <text x="592" y="250" textAnchor="end" fontSize="12" fill="var(--muted)">부모 → 자식</text>
          <text x="592" y="268" textAnchor="end" fontSize="12" fill="var(--muted)">한 방향</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 우리 플랫폼의 컴포넌트 트리 — App에서 Badge까지 블록의 조립, props는 위에서 아래로만 흐른다</p>
        <div className="tip">
          <b>직접 확인해 보기</b> 에디터로{' '}
          <span className="icode">frontend/src/components/</span> 폴더를 열어
          <span className="icode"> Badge.jsx</span>와 <span className="icode">Card.jsx</span>를
          읽어 보세요. "함수 하나 + return 속 JSX" 구조가 위 예제와 똑같은지 확인!
          그리고 대시보드 화면에서 그 블록이 몇 번 재사용되는지 세어 보세요.
        </div>
      </Section>

      <Section n={3} title="JSX 규칙" sub="HTML을 닮았지만 HTML이 아니다">
        <p>
          컴포넌트가 반환하는 <span className="icode">&lt;div&gt;...&lt;/div&gt;</span> 부분이{' '}
          <strong>JSX</strong>예요. HTML처럼 생겼지만 사실은 <strong>자바스크립트 속에 태그를
          쓰게 해 주는 특수 문법</strong>이라, HTML과 미묘하게 다른 규칙이 몇 개 있어요.
          이걸 모르면 첫날부터 빨간 에러의 늪에 빠집니다.
        </p>
        <Code>{CODE_JSX_RULES}</Code>
        <p>
          특히 3번, <strong>중괄호</strong>가 JSX의 심장이에요. 따옴표 안 글자는 그냥 글자지만
          중괄호 안은 <strong>살아있는 자바스크립트</strong> — 변수·계산식·함수 호출이 전부
          들어갑니다. "정적인 문서(HTML)"와 "살아있는 코드(JS)"를 잇는 창문인 셈이죠.
        </p>
        <div className="warn">
          <b>에러 메시지 번역기</b> <span className="icode">Adjacent JSX elements must be
          wrapped...</span>가 뜨면 4번 규칙 위반(형제 태그를 안 감쌈),{' '}
          <span className="icode">Unexpected token</span>이 태그 근처에서 뜨면 대개 1번(안 닫은
          태그)이에요. 이 두 개만 알아도 초반 에러의 절반은 해결됩니다.
        </div>
      </Section>

      <Section n={4} title="props와 state" sub="부모가 준 선물 vs 내가 관리하는 소지품">
        <p>
          컴포넌트를 움직이는 데이터는 딱 두 종류예요. <strong>props</strong>는 부모 컴포넌트가
          자식에게 내려 주는 <strong>선물</strong> — 받아서 쓸 수는 있지만 내 마음대로 바꿀 수
          없어요(선물에 낙서하면 안 되죠). <strong>state</strong>는 컴포넌트가 스스로 갖고
          관리하는 <strong>소지품</strong> — 바꿀 수 있고, 바꾸는 순간 화면이 다시 그려집니다.
        </p>
        <Code>{CODE_PROPS_STATE}</Code>
        <p>
          <span className="icode">useState(0)</span>이 돌려주는 건 <strong>[현재값, 바꾸는
          함수]</strong> 쌍이에요. 값을 직접 고치지 않고 굳이 함수를 거치는 이유는 딱 하나 —
          그 함수를 불러야 React가 <strong>"상태가 바뀌었으니 화면을 다시 그리자"</strong>는
          신호를 받기 때문입니다. 섹션 1의 "마법 칠판"을 울리는 종이 바로{' '}
          <span className="icode">setCount</span>예요.
        </p>
        <svg className="diagram" viewBox="0 0 640 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="props는 부모가 자식에게 한 방향으로 내려 주는 읽기 전용 값이고, state는 컴포넌트 안에서 setCount로 바뀌며 화면을 다시 그리게 하는 순환 구조">
          <text x="165" y="36" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">props — 부모가 주는 선물</text>
          <rect x="95" y="56" width="140" height="38" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="165" y="80" textAnchor="middle" fontSize="13" fill="var(--ink)">부모 컴포넌트</text>
          <line x1="165" y1="94" x2="165" y2="154" stroke="var(--primary)" strokeWidth="2" />
          <path d="M165 162 L159 150 L171 150 Z" fill="var(--primary)" />
          <text x="176" y="128" textAnchor="start" fontSize="12" fill="var(--primary)">label="3학년"</text>
          <rect x="95" y="162" width="140" height="38" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="165" y="186" textAnchor="middle" fontSize="13" fill="var(--ink)">자식 &lt;Badge /&gt;</text>
          <text x="165" y="258" textAnchor="middle" fontSize="12" fill="var(--muted)">한 방향 · 자식은 읽기 전용</text>
          <text x="475" y="36" textAnchor="middle" fontSize="14" fontWeight="600" fill="var(--ink)">state — 내가 관리하는 소지품</text>
          <rect x="355" y="56" width="240" height="180" rx="10" fill="var(--card)" stroke="var(--line)" />
          <text x="475" y="76" textAnchor="middle" fontSize="12" fill="var(--muted)">LikeButton 컴포넌트</text>
          <rect x="405" y="86" width="140" height="30" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="2" />
          <text x="475" y="106" textAnchor="middle" fontSize="13" fill="var(--ink)">state: count = 3</text>
          <line x1="475" y1="116" x2="475" y2="136" stroke="var(--muted)" strokeWidth="2" />
          <path d="M475 142 L469 131 L481 131 Z" fill="var(--muted)" />
          <rect x="405" y="142" width="140" height="30" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="475" y="162" textAnchor="middle" fontSize="13" fill="var(--ink)">화면: 좋아요 3</text>
          <line x1="475" y1="172" x2="475" y2="192" stroke="var(--muted)" strokeWidth="2" />
          <path d="M475 198 L469 187 L481 187 Z" fill="var(--muted)" />
          <rect x="395" y="198" width="160" height="30" rx="8" fill="var(--card)" stroke="var(--amber)" strokeWidth="2" />
          <text x="475" y="218" textAnchor="middle" fontSize="13" fill="var(--ink)">클릭 → setCount(4)</text>
          <polyline points="555,213 576,213 576,101 558,101" fill="none" stroke="var(--rose)" strokeWidth="2" strokeDasharray="4 3" />
          <path d="M548 101 L558 96 L558 106 Z" fill="var(--rose)" />
          <text x="475" y="258" textAnchor="middle" fontSize="12" fill="var(--muted)">setCount → state 변경 → 화면 자동 갱신</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: props는 부모→자식 한 방향, state는 setCount가 울리면 화면이 다시 그려지는 순환</p>
        <div className="tip">
          <b>구분 공식</b> "이 값을 부모가 정해 주나?" → props.
          "이 값이 사용자 행동(클릭·입력)으로 변하나?" → state.
          우리 플랫폼의 코스 카드로 치면 코스 제목은 props, "찜" 하트의 켜짐/꺼짐은 state.
        </div>
      </Section>

      <Section n={5} title="이벤트 처리" sub="클릭·입력에 반응하기 — 함수를 '건네주는' 감각">
        <p>
          버튼 클릭, 글자 입력 같은 사용자 행동을 <strong>이벤트</strong>라고 해요.
          React에선 <span className="icode">onClick</span>·<span className="icode">onChange</span>{' '}
          같은 속성에 <strong>함수 자체를 건네줍니다</strong>. "지금 실행해"가 아니라
          "이 일이 생기면 <strong>그때</strong> 실행해 줘" — 비상벨 옆에 매뉴얼을 걸어 두는
          것과 같아요. 벨이 울릴 때 읽는 거지, 걸자마자 읽는 게 아니죠.
        </p>
        <Code>{CODE_EVENTS}</Code>
        <p>
          입력창 패턴도 눈여겨보세요. <span className="icode">value</span>는 state에서 오고,{' '}
          <span className="icode">onChange</span>가 state를 갱신하고, 갱신된 state가 다시
          화면에 — 데이터가 <strong>한 방향으로 도는 순환</strong>이에요. 우리 플랫폼의
          로그인 화면, 과제 제출 폼이 전부 이 패턴 하나로 만들어져 있습니다.
        </p>
        <div className="warn">
          <b>초보 함정 1위</b> <span className="icode">onClick={'{handleSubmit()}'}</span>처럼
          괄호를 붙이면 <strong>렌더링되는 순간 즉시 실행</strong>돼 버려요. 건네줄 땐 괄호 없이
          이름만 — <span className="icode">onClick={'{handleSubmit}'}</span>. "실행 결과"가 아니라
          "함수 그 자체"를 주는 겁니다.
        </div>
      </Section>

      <Section n={6} title="목록 렌더링과 key" sub="배열을 화면으로 — 그리고 이름표의 정체">
        <p>
          코스 목록, 과제 목록, 랭킹... 실제 화면의 절반은 <strong>목록</strong>이에요.
          React에선 배열의 <span className="icode">.map()</span>으로 데이터 하나하나를
          JSX 블록으로 변신시킵니다. "데이터 배열 → 화면 블록 배열"의 공장 라인이라고
          생각하면 돼요.
        </p>
        <Code>{CODE_LIST_KEY}</Code>
        <p>
          <span className="icode">key</span>는 장식이 아니라 <strong>React의 출석부</strong>예요.
          목록이 바뀔 때(추가·삭제·정렬) React는 key로 "이 블록이 아까 그 블록인지"를
          알아봅니다. key가 없거나 자리 번호(index)면, 순서만 바뀌어도 엉뚱한 항목을
          다시 그리거나 입력값이 뒤섞이는 유령 버그가 생겨요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 우리 플랫폼에서 <span className="kbd">F12</span> →{' '}
          <span className="kbd">Console</span> 탭을 열어 두고 코스 목록 페이지를 새로고침해
          보세요. 경고가 없다면 key가 잘 달린 거예요. 그다음 에디터에서 목록을 그리는
          컴포넌트를 찾아 <span className="icode">key=</span>에 뭘 넣었는지 확인 — 십중팔구
          DB가 준 <span className="icode">id</span>일 겁니다. (일부러 key를 지우고 경고를
          목격하는 건 섹션 8의 과제 C!)
        </div>
      </Section>

      <Section n={7} title="useEffect 한 입" sub="우리 대시보드가 데이터를 불러오는 진짜 방법">
        <p>
          지금까지의 컴포넌트는 자기 안의 데이터만 그렸어요. 그런데 진짜 데이터는{' '}
          <strong>서버(Spring Boot + PostgreSQL)</strong>에 있죠. "화면을 먼저 그리고,
          그린 <strong>다음에</strong> 서버에 다녀와서, 도착하면 다시 그린다" — 이
          타이밍을 관리하는 도구가 <span className="icode">useEffect</span>입니다.
        </p>
        <Code>{CODE_USE_EFFECT}</Code>
        <p>
          식당에 비유하면: 일단 자리에 앉히고(빈 화면 렌더), 주방에 주문을 넣고(fetch),
          음식이 나오면 상을 차리는(setStats → 재렌더) 순서예요. 손님을 문밖에 세워 두고
          음식이 다 될 때까지 기다리게 하지 않는 것 — 그래서 "불러오는 중..." 화면이
          꼭 필요한 겁니다.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 두 단계로 해부해 봅시다. ① 에디터에서{' '}
          <span className="icode">frontend/src/pages/DashboardPage.jsx</span>를 열어 위 예제와
          같은 useEffect + fetch 패턴을 직접 찾아보세요. ② 브라우저에서 대시보드를 열고{' '}
          <span className="kbd">F12</span> → <span className="kbd">Network</span> 탭 →
          새로고침 — 화면이 뜨고 <strong>잠깐 뒤에</strong>{' '}
          <span className="icode">/api/...</span> 요청이 출발하는 순서를 눈으로 확인!
          "렌더 먼저, 데이터 나중"이 실화임을 목격하게 됩니다.
        </div>
        <div className="warn">
          <b>의존성 배열 [] 을 빼먹으면</b> 렌더될 때마다 fetch → setStats → 재렌더 → 또
          fetch... <strong>무한 요청 루프</strong>가 됩니다. 서버에 DDoS를 거는 셈이니,
          useEffect를 쓸 땐 마지막 배열부터 확인하는 습관을!
        </div>
      </Section>

      <Section n={8} title="폴더 구조 다시 보기 + 실습" sub="이제 우리 코드가 읽힌다 — STUDY.md 과제로 마무리">
        <p>
          첫 출근날 봤을 땐 암호 같았을 <span className="icode">frontend/src/</span> 폴더,
          이제 다시 봅시다. 오늘 배운 개념이 폴더 하나하나에 그대로 대응돼요.
        </p>
        <Code>{CODE_FOLDER}</Code>
        <p>
          개념은 손으로 굳혀야 내 것이 됩니다. 저장소 루트의 <strong>STUDY.md</strong>에
          있는 미니 과제 3종으로 마무리하세요 — 전부 오늘 배운 섹션의 직행 응용이에요.
        </p>
        <Code>{CODE_PRACTICE}</Code>
        <p>
          로컬 실행은 <span className="icode">frontend/</span>에서{' '}
          <span className="icode">npm install</span> 후 <span className="icode">npm run dev</span> —
          코드를 저장하는 순간 브라우저가 즉시 갱신되는 것(HMR)도 함께 느껴 보세요.
          "저장 → 새로고침" 없이 개발하는 이 경험이 React 개발의 일상입니다.
        </p>
        <div className="tip">
          <b>막혔을 때</b> 에러 메시지를 그대로 복사해 검색하기 전에, 먼저 섹션 3의
          "에러 메시지 번역기"와 섹션 5의 "초보 함정"을 다시 읽어 보세요. 입문 단계
          에러의 대부분은 그 안에 있어요. 그래도 막히면 멘토에게 — 단, "어디까지 시도했는지"를
          함께 들고 가면 배우는 속도가 두 배가 됩니다.
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>⚛️ 여기까지 왔다면</h3>
          <p className="muted">
            이제 "화면 = 상태의 함수"라는 문장을 컴포넌트·JSX·props/state·이벤트·목록·useEffect라는
            여섯 개의 단어로 설명할 수 있게 됐어요. 그리고 무엇보다 — <strong>우리 플랫폼의
            프론트 코드가 읽히기 시작했을 겁니다.</strong> STUDY.md 과제 3종을 Gitea에 PR로
            제출하고, 다음은 그 화면이 부르는 서버 쪽 —{' '}
            <Link to="/learn/network"><strong>네트워크의 이해</strong></Link> 코스에서 요청이
            달리는 길을, 이어지는 백엔드 코스에서 응답을 만드는 Spring Boot를 만나 보세요.
          </p>
        </div>
      </div>
    </div>
  );
}
