import React, { useRef, useState, useEffect } from "react"; import { ArrowDown, Check, BookOpen, AlertTriangle, Zap } from "lucide-react"; import { PracticeFromDataset } from "../../../components/lessons/LessonShell"; import { BOUNDARIES_EASY, BOUNDARIES_MEDIUM, } from "../../../data/rw/boundaries"; import ClauseBreakdownWidget, { type ClauseExample, } from "../../../components/lessons/ClauseBreakdownWidget"; import DecisionTreeWidget, { type TreeScenario, type TreeNode, } from "../../../components/lessons/DecisionTreeWidget"; interface LessonProps { onFinish?: () => void; } // ── Clause Breakdown data ────────────────────────────────────────────────── const CLAUSE_EXAMPLES: ClauseExample[] = [ { title: "Rule 1 — FANBOYS Comma", segments: [ { text: "The study was carefully designed", type: "ic", label: "Independent Clause", }, { text: ",", type: "punct" }, { text: " but", type: "conjunction", label: "FANBOYS Conjunction" }, { text: " the results were inconclusive", type: "ic", label: "Independent Clause", }, { text: ".", type: "punct" }, ], }, { title: "Rule 2 — Introductory Element", segments: [ { text: "After reviewing the data", type: "modifier", label: "Introductory Phrase", }, { text: ",", type: "punct" }, { text: " the researchers revised their hypothesis", type: "ic", label: "Main Clause", }, { text: ".", type: "punct" }, ], }, { title: "Rule 3 — Nonessential Phrase", segments: [ { text: "The experiment", type: "subject", label: "Subject" }, { text: ",", type: "punct" }, { text: " conducted in 2021", type: "modifier", label: "Nonessential Phrase", }, { text: ",", type: "punct" }, { text: " yielded unexpected results", type: "verb", label: "Predicate" }, { text: ".", type: "punct" }, ], }, ]; // ── Decision Tree data ───────────────────────────────────────────────────── const NO_FANBOYS_SUBTREE: TreeNode = { id: "no-fanboys", question: "Can BOTH sides stand alone as complete sentences (independent clauses)?", hint: "Check each side for its own subject + verb. A phrase or fragment cannot stand alone.", yesLabel: "Yes — both sides are complete sentences", noLabel: "No — one side is a phrase/fragment", yes: { id: "comma-splice", result: "⚠ Comma Splice! A comma alone cannot join two independent clauses. Fix: add a FANBOYS conjunction after the comma, or replace the comma with a semicolon.", resultType: "warning", ruleRef: "Fix: [IC]; [IC] or [IC], [FANBOYS] [IC]", }, no: { id: "no-fanboys-no-two-ic", question: "Is there an introductory element (phrase or clause) at the START of the sentence?", hint: 'Introductory elements include: participial phrases ("Running quickly"), prepositional phrases ("After the meeting"), or adverb clauses ("Because she studied").', yesLabel: "Yes — opens with an introductory phrase/clause", noLabel: "No — sentence starts with the subject", yes: { id: "intro-element", result: "✓ Use a comma AFTER the introductory element to separate it from the main clause.", resultType: "correct", ruleRef: "[Introductory element], [Main clause]", }, no: { id: "no-intro", question: "Is there a nonessential phrase in the MIDDLE that can be removed without changing the core meaning?", hint: "Removal test: delete the phrase — does the sentence still make complete sense? If yes, it's nonessential.", yesLabel: "Yes — removable nonessential phrase", noLabel: "No — no removable phrase", yes: { id: "nonessential", result: "✓ Use a comma on EACH SIDE of the nonessential phrase (two commas total).", resultType: "correct", ruleRef: "[Subject], [nonessential phrase], [predicate]", }, no: { id: "no-comma", result: "✓ No comma needed here. Commas are only used for FANBOYS, introductory elements, nonessential info, or lists.", resultType: "info", ruleRef: "No comma — essential or uninterrupted structure", }, }, }, }; const COMMA_TREE: TreeNode = { id: "root", question: "Is there a FANBOYS conjunction (for, and, nor, but, or, yet, so) in this sentence?", hint: "Scan for these 7 words: For · And · Nor · But · Or · Yet · So", yesLabel: "Yes — there's a FANBOYS word", noLabel: "No FANBOYS conjunction", yes: { id: "has-fanboys", question: "Can BOTH sides of the conjunction stand alone as complete sentences?", hint: "Cover each side with your hand. Can it stand alone with its own subject and verb?", yesLabel: "Yes — both sides are complete sentences", noLabel: "No — one side is a phrase or fragment", yes: { id: "fanboys-both-ic", result: "✓ Use a comma BEFORE the FANBOYS conjunction.", resultType: "correct", ruleRef: "[Independent Clause], [FANBOYS] [Independent Clause]", }, no: { id: "fanboys-not-both-ic", result: "✗ No comma needed before the conjunction. It is not joining two independent clauses.", resultType: "warning", ruleRef: "[IC] [FANBOYS] [phrase] — no comma", }, }, no: NO_FANBOYS_SUBTREE, }; const TREE_SCENARIOS: TreeScenario[] = [ { label: "Sentence 1", sentence: "The study was carefully designed, the results were inconclusive.", tree: COMMA_TREE, }, { label: "Sentence 2", sentence: "After reviewing the data the researchers revised their hypothesis.", tree: COMMA_TREE, }, { label: "Sentence 3", sentence: "The experiment conducted in 2021 yielded unexpected results.", tree: COMMA_TREE, }, ]; // ── Lesson component ─────────────────────────────────────────────────────── const EBRWCommasLesson: React.FC = ({ 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()); }, []); const scrollToSection = (index: number) => { setActiveSection(index); sectionsRef.current[index]?.scrollIntoView({ behavior: "smooth" }); }; const SectionMarker = ({ index, title, icon: Icon, }: { index: number; title: string; icon: React.ComponentType>; }) => { const isActive = activeSection === index; const isPast = activeSection > index; return ( ); }; return (
{/* Section 0 — Concept + Clause Breakdown */}
{ sectionsRef.current[0] = el; }} className="min-h-screen flex flex-col justify-center mb-24 pt-20 lg:pt-0" >
Standard English Conventions

Punctuation: Commas

See how sentences are built — then learn exactly where commas go.

{/* Rule summary */}
{[ { num: 1, rule: "FANBOYS", desc: "Comma before for/and/nor/but/or/yet/so when joining two complete sentences.", }, { num: 2, rule: "Introductory Element", desc: "Comma after any word, phrase, or clause that opens the sentence.", }, { num: 3, rule: "Nonessential Phrase", desc: "Two commas around any removable mid-sentence insertion.", }, { num: 4, rule: "Lists of 3+", desc: "Commas between items in a series; SAT prefers the Oxford comma.", }, ].map((r) => (
{r.num} {r.rule}

{r.desc}

))}
{/* Clause Breakdown */}

Sentence Anatomy

Hover over any colored span to see its label. Use the tabs to switch between examples.

Golden Rule

A comma alone can never join two independent clauses — that's a comma splice. Every comma needs a job: FANBOYS, intro element, nonessential info, or list.

{/* Section 1 — Decision Tree */}
{ sectionsRef.current[1] = el; }} className="min-h-screen flex flex-col justify-center mb-24" >

Decision Tree Lab

Work through the grammar logic one question at a time. Click your answer at each step.

{/* Trap callouts */}
{[ { label: "Comma Splice", desc: "Two full sentences joined by a comma alone. The most tested comma error.", }, { label: "Missing Second Comma", desc: "Nonessential phrases need a comma on EACH side — never just one.", }, { label: "Subject–Verb Comma", desc: "Never put a single comma between a subject and its verb.", }, ].map((t) => (

{t.label}

{t.desc}

))}
{/* Section 2 — Quiz */}
{ sectionsRef.current[2] = el; }} className="min-h-screen flex flex-col justify-center mb-24" >

Practice Questions

{BOUNDARIES_EASY.slice(0, 2).map((q) => ( ))} {BOUNDARIES_MEDIUM.slice(0, 1).map((q) => ( ))}
); }; export default EBRWCommasLesson;