Files
edbridge-scholars/src/pages/student/lessons/EBRWRhetoricalSynthesisLesson.tsx
2026-03-12 02:39:34 +06:00

635 lines
27 KiB
TypeScript
Raw 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.

import React, { useRef, useState, useEffect } from "react";
import {
Check,
BookOpen,
Lightbulb,
Zap,
Target,
AlertTriangle,
} from "lucide-react";
import { PracticeFromDataset } from "../../../components/lessons/LessonShell";
import {
RHETORICAL_EASY,
RHETORICAL_MEDIUM,
} from "../../../data/rw/rhetorical-synthesis";
import EvidenceHunterWidget, {
type EvidenceExercise,
} from "../../../components/lessons/EvidenceHunterWidget";
import RevealCardGrid, {
type RevealCard,
} from "../../../components/lessons/RevealCardGrid";
import useScrollReveal from "../../../components/lessons/useScrollReveal";
interface LessonProps {
onFinish?: () => void;
}
/* ── Data for RevealCardGrid widgets ── */
const RHETORICAL_GOALS: RevealCard[] = [
{
label: "Introduce a Topic",
sublabel: '"introduce," "background," "context"',
content: "Present a new subject with context. No strong argument yet.",
},
{
label: "Make a Comparison",
sublabel: '"compare," "contrast," "differ," "between"',
content:
"Explicitly contrast OR compare two things. Must mention BOTH and their relationship.",
},
{
label: "Emphasize Similarity",
sublabel: '"similarity," "common," "alike," "both"',
content:
'Highlight what two things have IN COMMON. Both must appear; "both" or "similarly" usually required.',
},
{
label: "Illustrate with Example",
sublabel: '"example," "illustrate," "such as"',
content:
"Use a specific case to demonstrate a general principle. Must contain a concrete example.",
},
{
label: "State a Limitation",
sublabel: '"limitation," "drawback," "only," "cannot"',
content:
"Acknowledge a restriction, exception, or weakness of a claim or finding.",
},
{
label: "Present Cause-Effect",
sublabel: '"cause," "result," "lead to," "effect"',
content:
"Show a causal chain: X leads to Y, or X results in Y. The relationship must be directional.",
},
{
label: "Provide Supporting Evidence",
sublabel: '"support," "evidence," "data," "findings"',
content:
"Give data, statistics, or findings that back up a claim already made.",
},
{
label: "Acknowledge Opposing View",
sublabel: '"opposing," "counterargument," "critics"',
content:
'Present a counterargument before making your own point. "Critics argue…" structure.',
},
];
const WRONG_PATTERNS: RevealCard[] = [
{
label: "Wrong Goal",
sublabel: "Check this FIRST",
content:
"Achieves a different purpose from what the question asks. Most common wrong answer type — check before verifying facts.",
},
{
label: "Accurate But Irrelevant",
content:
"Uses real facts from the notes, but from the wrong notes — not the ones that serve the stated goal.",
},
{
label: "Distorted Fact",
content:
"Changes a number, reverses a direction, or misrepresents what a note says. Always verify facts word by word.",
},
{
label: "Incompatible Notes Combined",
content:
"Joins two notes that cannot logically work together, producing individually accurate but collectively incoherent sentences.",
},
{
label: "Wrong Scope",
content:
"Too broad (covers more than goal requires) or too narrow (picks a detail that misses the stated purpose).",
},
{
label: "Outside Information",
content:
"Claims something not found in any provided notes — even if generally true in the real world. If you can't point to the note, eliminate it.",
},
];
const EVIDENCE_EXERCISES: EvidenceExercise[] = [
{
question:
"A student wants to EMPHASIZE A SIMILARITY between two renewable energy sources. Which sentence best accomplishes this goal?",
passage: [
"Wind energy capacity in the US grew by 14% in 2022.",
"Solar energy capacity in the US also grew by 14% in 2022.",
"Wind turbines require more land per megawatt than solar panels.",
"Both wind and solar energy produce no direct carbon emissions during operation.",
"Government subsidies for renewable energy totaled $15 billion in 2022.",
],
evidenceIndex: 3,
explanation:
'Sentence 4 directly emphasizes a shared characteristic of both sources. The word "both" signals similarity, and "no direct carbon emissions" is the specific trait they share — this is exactly what the goal requires.',
},
{
question:
"A student wants to ACKNOWLEDGE AN OPPOSING VIEW about urban farming before presenting their own argument. Which sentence best accomplishes this goal?",
passage: [
"Urban farming initiatives have expanded in over 200 American cities.",
"Critics argue that urban farms cannot produce food at a scale sufficient to affect food insecurity.",
"Urban farms do provide fresh produce in food deserts, regardless of total volume.",
"Community gardens have been shown to strengthen neighborhood social ties.",
"The average urban farm yields 5 times more produce per square foot than conventional farms.",
],
evidenceIndex: 1,
explanation:
'Sentence 2 explicitly presents a counterargument with "Critics argue..." — the standard structure for acknowledging an opposing view. It sets up the concession the student needs before making their own point.',
},
];
const EBRWRhetoricalSynthesisLesson: React.FC<LessonProps> = ({ onFinish }) => {
const [activeSection, setActiveSection] = useState(0);
const sectionsRef = useRef<(HTMLElement | null)[]>([]);
useEffect(() => {
const observers: IntersectionObserver[] = [];
sectionsRef.current.forEach((el, idx) => {
if (!el) return;
const obs = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) setActiveSection(idx);
},
{ threshold: 0.3 },
);
obs.observe(el);
observers.push(obs);
});
return () => observers.forEach((o) => o.disconnect());
}, []);
useScrollReveal();
const scrollToSection = (index: number) => {
setActiveSection(index);
sectionsRef.current[index]?.scrollIntoView({ behavior: "smooth" });
};
const SectionMarker = ({
index,
title,
icon: Icon,
}: {
index: number;
title: string;
icon: React.ElementType;
}) => {
const isActive = activeSection === index;
const isPast = activeSection > index;
return (
<button
onClick={() => scrollToSection(index)}
className={`flex items-center gap-3 p-3 w-full rounded-lg text-left transition-all ${isActive ? "bg-rose-50" : "hover:bg-slate-50"}`}
>
<div
className={`w-8 h-8 rounded-full flex items-center justify-center shrink-0
${isActive ? "bg-rose-600 text-white" : isPast ? "bg-rose-400 text-white" : "bg-slate-200 text-slate-500"}`}
>
{isPast ? (
<Check className="w-4 h-4" />
) : (
// @ts-ignore
<Icon className="w-4 h-4" />
)}
</div>
<p
className={`text-sm font-bold ${isActive ? "text-rose-900" : "text-slate-600"}`}
>
{title}
</p>
</button>
);
};
return (
<div className="flex flex-col lg:flex-row min-h-screen">
<aside className="w-full lg:w-64 lg:fixed lg:top-14 lg:bottom-0 lg:overflow-y-auto p-4 border-r border-slate-200 bg-slate-50 z-0 hidden lg:block">
<nav className="space-y-2 pt-6">
<SectionMarker index={0} title="The Core Concept" icon={BookOpen} />
<SectionMarker
index={1}
title="Goals &amp; Strategy"
icon={AlertTriangle}
/>
<SectionMarker index={2} title="Worked Example" icon={Target} />
<SectionMarker index={3} title="Goal Matcher" icon={Lightbulb} />
<SectionMarker index={4} title="Practice Questions" icon={Zap} />
</nav>
</aside>
<div className="flex-1 lg:ml-64 md:p-12 max-w-full mx-auto">
{/* ── Section 0: The Core Concept ── */}
<section
ref={(el) => {
sectionsRef.current[0] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24 pt-20 lg:pt-0"
>
<div className="inline-flex items-center gap-2 bg-rose-100 text-rose-700 px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider mb-4 w-fit">
Expression of Ideas Domain 4
</div>
<h2 className="text-4xl font-extrabold text-slate-900 mb-2">
Rhetorical Synthesis
</h2>
<p className="text-lg text-slate-500 mb-8">
Every answer is judged on two things: does it achieve the stated
goal, and does every fact come from the notes? Failing either test
means wrong no exceptions.
</p>
{/* §9.1 — What Makes an Answer Correct */}
<div className="scroll-reveal stagger-1 rounded-2xl p-6 mb-8 bg-rose-50 border border-rose-200 space-y-4">
<h3 className="text-lg font-bold text-rose-900">
The Two-Criteria Rule
</h3>
<p className="text-sm text-slate-700">
Unlike most SAT questions, Rhetorical Synthesis does not ask you
to find the "best" answer in a general sense. It asks you to find
the answer that satisfies exactly two requirements simultaneously.
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="card-tilt bg-white border border-rose-200 rounded-xl p-4">
<p className="font-bold text-rose-900 text-sm mb-2">
Criterion 1 GOAL
</p>
<p className="text-xs text-slate-700">
The answer must accomplish exactly the rhetorical purpose
stated in the question no more, no less. An answer that does
something different from the stated goal is automatically
wrong, even if every fact is accurate.
</p>
</div>
<div className="card-tilt bg-white border border-rose-200 rounded-xl p-4">
<p className="font-bold text-rose-900 text-sm mb-2">
Criterion 2 ACCURACY
</p>
<p className="text-xs text-slate-700">
Every fact in the answer must come directly from the provided
notes nothing added, nothing distorted. Even one wrong
number or reversed relationship eliminates an answer, even if
the goal is otherwise met.
</p>
</div>
</div>
<div className="bg-rose-100 border border-rose-300 rounded-xl p-4">
<p className="text-xs text-slate-700">
<span className="font-bold text-rose-900">
The key insight:
</span>{" "}
These two criteria work independently. You can fail on goal
while passing accuracy. You can fail on accuracy while passing
goal. Only the answer that passes both is correct.
</p>
</div>
</div>
{/* §9.2 — Question Anatomy */}
<div className="scroll-reveal stagger-2 rounded-2xl p-6 mb-8 bg-white border border-slate-200 space-y-4">
<h3 className="text-lg font-bold text-slate-900">
Question Anatomy
</h3>
<p className="text-sm text-slate-600">
Every Rhetorical Synthesis question has the same four-part
structure. Each part plays a specific role in determining the
correct answer.
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm border-collapse rounded-xl overflow-hidden">
<thead>
<tr className="bg-rose-600 text-white">
<th className="px-3 py-2 text-left text-xs">Component</th>
<th className="px-3 py-2 text-left text-xs">
What It Contains
</th>
<th className="px-3 py-2 text-left text-xs">
What You Need From It
</th>
</tr>
</thead>
<tbody>
{[
[
"Context Header",
'"While researching a topic, a student took the following notes:"',
"Sets the topic domain. Establishes what field the notes come from.",
],
[
"Notes (24 bullets)",
"Factual information: data, definitions, examples, findings",
"The ONLY source of accurate facts. Every claim in the correct answer must trace back here.",
],
[
"Stated Goal",
'"The student wants to [X]. Which choice best accomplishes this goal?"',
"Read this FIRST — before notes, before answer choices. It tells you exactly what the correct answer must do.",
],
[
"Four Answer Choices",
"Sentences combining facts from the notes",
"Wrong answers fail the goal, distort facts, add outside information, or combine incompatible notes.",
],
].map(([comp, contains, need], i) => (
<tr
key={comp}
className={i % 2 === 0 ? "bg-white" : "bg-rose-50"}
>
<td className="px-3 py-2 font-bold text-rose-800 text-xs whitespace-nowrap">
{comp}
</td>
<td className="px-3 py-2 text-slate-600 text-xs italic">
{contains}
</td>
<td className="px-3 py-2 text-slate-700 text-xs">
{need}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</section>
{/* ── Section 1: Goals & Strategy ── */}
<section
ref={(el) => {
sectionsRef.current[1] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-2">
Goals &amp; Strategy
</h2>
<p className="text-lg text-slate-500 mb-8">
The eight rhetorical goals, the 5-step method, and the six ways
wrong answers fail.
</p>
{/* §9.3 — The 8 Goals */}
<div className="scroll-reveal stagger-1 rounded-2xl p-6 mb-8 bg-rose-50 border border-rose-200 space-y-4">
<h3 className="text-lg font-bold text-rose-900">
The 8 Rhetorical Goals tap to reveal what each answer must do:
</h3>
<p className="text-sm text-slate-700">
The stated goal will always be one of these eight types. Knowing
them lets you immediately identify what structural features the
correct answer must contain.
</p>
<RevealCardGrid
cards={RHETORICAL_GOALS}
columns={4}
accentColor="rose"
/>
</div>
{/* §9.5 — The 5-Step Strategy */}
<div className="scroll-reveal stagger-2 rounded-2xl p-6 mb-8 bg-white border border-slate-200 space-y-4">
<h3 className="text-lg font-bold text-slate-900">
The 5-Step Strategy
</h3>
<div className="space-y-2">
{[
{
step: 1,
action: "Read the GOAL first",
tip: 'Before reading notes or answer choices, read the stated goal. Write the goal type in 34 words on scratch paper: e.g., "comparison — key difference." The goal determines everything else.',
},
{
step: 2,
action: "Read the notes with the goal in mind",
tip: "Identify which 12 notes are relevant to your goal. Cross out off-topic notes — they exist only as material for wrong answers.",
},
{
step: 3,
action: "Predict what the correct answer must contain",
tip: 'Before looking at choices, write a quick sketch: "must mention both species + a difference." Even a rough prediction blocks you from being swayed by sophisticated wrong answers.',
},
{
step: 4,
action: "Eliminate wrong goals first",
tip: "Any answer that achieves a DIFFERENT goal from the one stated is wrong — eliminate it before checking any facts. This alone usually removes 23 choices immediately.",
},
{
step: 5,
action: "Verify accuracy in the remaining answers",
tip: "Read each remaining answer word by word against the notes. One wrong number, reversed relationship, or unsupported claim eliminates the answer.",
},
].map((s) => (
<div
key={s.step}
className="flex gap-3 bg-rose-50 border border-rose-100 rounded-xl px-4 py-3"
>
<span className="w-6 h-6 rounded-full bg-rose-600 text-white flex items-center justify-center text-xs font-bold shrink-0">
{s.step}
</span>
<div>
<p className="font-bold text-slate-800 text-sm">
{s.action}
</p>
<p className="text-xs text-slate-500 mt-0.5">{s.tip}</p>
</div>
</div>
))}
</div>
</div>
{/* §9.4 — Wrong Answer Patterns */}
<div className="scroll-reveal stagger-3 rounded-2xl p-6 mb-8 bg-white border border-slate-200 space-y-4">
<h3 className="text-lg font-bold text-slate-900">
Wrong Answer Patterns tap to reveal each trap:
</h3>
<p className="text-sm text-slate-600">
Every wrong answer fails in one of these six predictable ways.
Naming the failure pattern immediately tells you why to eliminate
it.
</p>
<RevealCardGrid
cards={WRONG_PATTERNS}
columns={3}
accentColor="rose"
/>
</div>
<div className="scroll-reveal-scale golden-rule-glow bg-rose-900 text-white rounded-2xl p-5 mb-8">
<p className="font-bold mb-1">Golden Rule</p>
<p className="text-sm text-rose-100">
Read the GOAL before reading anything else. An accurate answer
that achieves the wrong goal is wrong. An answer that achieves the
right goal with one distorted fact is also wrong. Both criteria
must be met.
</p>
</div>
</section>
{/* ── Section 2: Worked Example ── */}
<section
ref={(el) => {
sectionsRef.current[2] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-2">
Worked Example
</h2>
<p className="text-lg text-slate-500 mb-8">
A complete question with full analysis of why each answer succeeds
or fails against the two criteria.
</p>
<div className="scroll-reveal stagger-1 rounded-2xl p-6 mb-8 bg-slate-50 border border-slate-200 space-y-4">
<p className="text-xs font-bold text-slate-500 uppercase tracking-wider">
While researching a topic, a student took the following notes:
</p>
<ul className="space-y-2">
{[
"Komodo dragons (Varanus komodoensis) are the world's largest living lizard species, reaching up to 3 meters in length.",
"Komodo dragons are found only on five islands in Indonesia: Komodo, Rinca, Flores, Gili Motang, and Padar.",
"Komodo dragons have a venomous bite that prevents blood clotting in prey, causing prey to weaken from blood loss.",
"The IUCN lists Komodo dragons as Endangered, with an estimated 1,3832,531 individuals remaining in the wild.",
"Nile monitor lizards, native to Africa, are also large lizards but are not venomous and grow to only 2 meters.",
].map((note, i) => (
<li key={i} className="flex gap-2 text-sm text-slate-700">
<span className="text-rose-500 font-bold shrink-0">
{i + 1}.
</span>
{note}
</li>
))}
</ul>
<div className="bg-rose-100 border border-rose-300 rounded-xl p-3">
<p className="text-sm font-bold text-rose-900">
The student wants to COMPARE the Komodo dragon with another
large lizard species by highlighting a key difference. Which
choice best accomplishes this goal?
</p>
</div>
<div className="space-y-3">
{[
{
letter: "A",
correct: false,
text: "Komodo dragons, the world's largest living lizards at 3 meters, are endangered, with fewer than 2,531 individuals remaining.",
analysis:
"✗ Wrong goal. Only one species is mentioned — no comparison is made. The goal explicitly requires comparing Komodo dragons WITH another species.",
},
{
letter: "B",
correct: true,
text: "Unlike Nile monitor lizards, which are not venomous and reach only 2 meters, Komodo dragons possess a venomous bite and can grow up to 3 meters.",
analysis:
"✓ Correct. Both species appear. A key difference is highlighted (venomous vs. not venomous, 3m vs. 2m). All facts trace directly to Notes 1 and 5. Goal ✓, Accuracy ✓.",
},
{
letter: "C",
correct: false,
text: "Komodo dragons are venomous lizards found on five Indonesian islands, and their numbers have declined to fewer than 2,531 in the wild.",
analysis:
"✗ Wrong goal. Only one species mentioned — no comparison. The facts are accurate, but the goal is not achieved.",
},
{
letter: "D",
correct: false,
text: "Both Komodo dragons and Nile monitor lizards are large reptiles, with Komodo dragons endangered and Nile monitors thriving across Africa.",
analysis:
'✗ Two failures. First, the goal asks for a KEY DIFFERENCE, not similarity — "both are large reptiles" emphasizes similarity. Second, "Nile monitors thriving" appears in no note — outside information.',
},
].map((opt) => (
<div
key={opt.letter}
className={`rounded-xl p-4 border ${opt.correct ? "bg-green-50 border-green-300" : "bg-red-50 border-red-200"}`}
>
<div className="flex gap-3 items-start">
<span
className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold shrink-0 ${opt.correct ? "bg-green-600 text-white" : "bg-red-500 text-white"}`}
>
{opt.letter}
</span>
<div>
<p className="text-sm text-slate-800 italic mb-2">
"{opt.text}"
</p>
<p className="text-xs text-slate-600">{opt.analysis}</p>
</div>
</div>
</div>
))}
</div>
<div className="bg-amber-50 border border-amber-200 rounded-xl p-4">
<p className="font-bold text-amber-900 text-sm mb-1">Takeaways</p>
<ul className="space-y-1 text-xs text-slate-700">
<li>
"Compare by highlighting a key difference" = two species
must appear AND a difference must be stated.
</li>
<li>
A and C both used accurate facts but both failed the goal
test. Eliminated without checking accuracy.
</li>
<li>
D failed on both criteria: wrong goal type (similarity
instead of difference) AND outside information.
</li>
<li>
B is the only answer that passes both criteria: goal (two
species, key difference stated), accuracy (all facts from
Notes 1 and 5).
</li>
</ul>
</div>
</div>
</section>
{/* ── Section 3: Goal Matcher Widget ── */}
<section
ref={(el) => {
sectionsRef.current[3] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-2">
Goal Matcher
</h2>
<p className="text-lg text-slate-500 mb-8">
Find the sentence that best achieves the stated rhetorical goal
using only facts from the notes.
</p>
<EvidenceHunterWidget
exercises={EVIDENCE_EXERCISES}
accentColor="rose"
/>
</section>
{/* ── Section 4: Practice ── */}
<section
ref={(el) => {
sectionsRef.current[4] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-6">
Practice Questions
</h2>
{RHETORICAL_EASY.slice(0, 2).map((q) => (
<PracticeFromDataset key={q.id} question={q} color="rose" />
))}
{RHETORICAL_MEDIUM.slice(0, 1).map((q) => (
<PracticeFromDataset key={q.id} question={q} color="rose" />
))}
<div className="mt-8 text-center">
<button
onClick={onFinish}
className="px-6 py-3 bg-rose-900 text-white font-bold rounded-full hover:bg-rose-700 transition-colors"
>
Finish Lesson
</button>
</div>
</section>
</div>
</div>
);
};
export default EBRWRhetoricalSynthesisLesson;