Files
edbridge-scholars/src/pages/student/lessons/CollectingDataLesson.tsx

406 lines
17 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 {
ArrowDown,
Check,
BookOpen,
Target,
Scale,
Layers,
} from "lucide-react";
import SamplingVisualizerWidget from "../../../components/lessons/SamplingVisualizerWidget";
import StudyDesignWidget from "../../../components/lessons/StudyDesignWidget";
import ConfidenceIntervalWidget from "../../../components/lessons/ConfidenceIntervalWidget";
import Quiz from "../../../components/lessons/Quiz";
import {
COLLECTING_DATA_QUIZ,
INFERENCES_QUIZ_DATA,
} from "../../../utils/constants";
interface LessonProps {
onFinish?: () => void;
}
const CollectingDataLesson: React.FC<LessonProps> = ({ onFinish }) => {
const [activeSection, setActiveSection] = useState(0);
const sectionsRef = useRef<(HTMLElement | null)[]>([]);
const scrollToSection = (index: number) => {
setActiveSection(index);
sectionsRef.current[index]?.scrollIntoView({
behavior: "smooth",
block: "start",
});
};
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const index = sectionsRef.current.indexOf(
entry.target as HTMLElement,
);
if (index !== -1) setActiveSection(index);
}
});
},
{ rootMargin: "-20% 0px -60% 0px" },
);
sectionsRef.current.forEach((section) => {
if (section) observer.observe(section);
});
return () => observer.disconnect();
}, []);
const SectionMarker = ({
index,
title,
icon: Icon,
}: {
index: number;
title: string;
icon: any;
}) => {
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 transition-all ${isActive ? "bg-white shadow-md border border-amber-100" : "hover:bg-slate-100"}`}
>
<div
className={`w-8 h-8 rounded-full flex items-center justify-center shrink-0 ${isActive ? "bg-amber-600 text-white" : isPast ? "bg-amber-400 text-white" : "bg-slate-200 text-slate-500"}`}
>
{isPast ? (
<Check className="w-4 h-4" />
) : (
<Icon className="w-4 h-4" />
)}
</div>
<div className="text-left">
<p
className={`text-sm font-bold ${isActive ? "text-amber-900" : "text-slate-600"}`}
>
{title}
</p>
</div>
</button>
);
};
const allQuizzes = [...COLLECTING_DATA_QUIZ, ...INFERENCES_QUIZ_DATA];
return (
<div className="flex flex-col lg:flex-row min-h-screen">
<aside className="w-full lg:w-64 lg:fixed lg:top-20 lg:bottom-0 lg:overflow-y-auto p-4 border-r border-slate-200 bg-slate-50 lg:bg-transparent z-0 hidden lg:block">
<nav className="space-y-2">
<SectionMarker index={0} title="Sampling & Bias" icon={Scale} />
<SectionMarker index={1} title="Study Design" icon={Layers} />
<SectionMarker index={2} title="Confidence Intervals" icon={Target} />
<SectionMarker index={3} title="Practice" icon={BookOpen} />
</nav>
</aside>
<div className="flex-1 lg:ml-64 p-6 md:p-12 max-w-4xl mx-auto">
{/* Section 1: Sampling & Bias */}
<section
ref={(el) => {
sectionsRef.current[0] = el;
}}
className="min-h-screen flex flex-col justify-center mb-24 pt-20 lg:pt-0"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-6">
Sampling & Bias
</h2>
<div className="prose prose-slate text-lg text-slate-600 mb-8">
<p>
To generalize results to a population, your sample must be{" "}
<strong>representative</strong>. The best way to achieve this is
through <strong>random sampling</strong>. Convenience samples
(e.g., asking friends) introduce <strong>bias</strong> they
systematically over- or under-represent parts of the population.
</p>
<div className="mt-5 overflow-x-auto">
<table className="w-full text-sm border-collapse">
<thead>
<tr className="bg-amber-100 text-amber-900">
<th className="border border-amber-300 px-3 py-2 text-left font-bold">
Method
</th>
<th className="border border-amber-300 px-3 py-2 text-left font-bold">
Description
</th>
<th className="border border-amber-300 px-3 py-2 text-left font-bold">
Bias Risk
</th>
</tr>
</thead>
<tbody className="text-slate-700">
<tr className="bg-white">
<td className="border border-slate-200 px-3 py-2 font-semibold">
Simple Random
</td>
<td className="border border-slate-200 px-3 py-2">
Every individual has an equal chance of selection
</td>
<td className="border border-slate-200 px-3 py-2 text-emerald-700 font-semibold">
Very Low
</td>
</tr>
<tr className="bg-slate-50">
<td className="border border-slate-200 px-3 py-2 font-semibold">
Stratified
</td>
<td className="border border-slate-200 px-3 py-2">
Population divided into subgroups; random sample from each
</td>
<td className="border border-slate-200 px-3 py-2 text-emerald-700 font-semibold">
Very Low
</td>
</tr>
<tr className="bg-white">
<td className="border border-slate-200 px-3 py-2 font-semibold">
Cluster
</td>
<td className="border border-slate-200 px-3 py-2">
Randomly select entire subgroups (e.g., classrooms)
</td>
<td className="border border-slate-200 px-3 py-2 text-amber-700 font-semibold">
LowMedium
</td>
</tr>
<tr className="bg-slate-50">
<td className="border border-slate-200 px-3 py-2 font-semibold">
Systematic
</td>
<td className="border border-slate-200 px-3 py-2">
Select every kth individual from a list
</td>
<td className="border border-slate-200 px-3 py-2 text-amber-700 font-semibold">
LowMedium
</td>
</tr>
<tr className="bg-white">
<td className="border border-slate-200 px-3 py-2 font-semibold">
Convenience
</td>
<td className="border border-slate-200 px-3 py-2">
Whoever is easiest to reach (friends, passersby)
</td>
<td className="border border-slate-200 px-3 py-2 text-rose-700 font-semibold">
High
</td>
</tr>
</tbody>
</table>
</div>
<div className="mt-4 grid md:grid-cols-2 gap-4">
<div className="bg-emerald-50 border border-emerald-200 rounded-xl p-4">
<p className="font-bold text-emerald-900 mb-1">
Representative Sample
</p>
<p className="text-sm text-slate-700">
Mirrors the population in all key characteristics. Allows you
to generalize findings to the whole group. Achieved through
random selection.
</p>
</div>
<div className="bg-rose-50 border border-rose-200 rounded-xl p-4">
<p className="font-bold text-rose-900 mb-1">Biased Sample</p>
<p className="text-sm text-slate-700">
Systematically excludes or over-includes certain groups.
Results cannot be generalized. Watch for voluntary response
and convenience sampling.
</p>
</div>
</div>
<div className="mt-4 p-3 bg-amber-50 border-l-4 border-amber-500 rounded-r-lg text-sm">
<strong className="text-amber-900">Margin of Error:</strong> Even
a well-designed random sample has some uncertainty. The margin of
error (e.g., ±3%) tells you the range where the true population
value likely falls. Larger samples produce smaller margins of
error.
</div>
</div>
<SamplingVisualizerWidget />
<button
onClick={() => scrollToSection(1)}
className="mt-12 group flex items-center text-amber-600 font-bold hover:text-amber-800 transition-colors"
>
Next: Study Design{" "}
<ArrowDown className="ml-2 w-5 h-5 group-hover:translate-y-1 transition-transform" />
</button>
</section>
{/* Section 2: Study Design */}
<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-6">
Study Design: Generalization vs Causation
</h2>
<div className="prose prose-slate text-lg text-slate-600 mb-8">
<p>
Two concepts are critical here. <strong>Random sampling</strong>{" "}
determines whether you can extend your conclusions to the broader
population. <strong>Random assignment</strong> (used in
experiments) determines whether you can claim cause-and-effect.
</p>
<div className="mt-5 overflow-x-auto">
<table className="w-full text-sm border-collapse">
<thead>
<tr className="bg-amber-100 text-amber-900">
<th className="border border-amber-300 px-3 py-2"></th>
<th className="border border-amber-300 px-3 py-2 text-center font-bold">
Random Assignment? YES
</th>
<th className="border border-amber-300 px-3 py-2 text-center font-bold">
Random Assignment? NO
</th>
</tr>
</thead>
<tbody className="text-slate-700">
<tr className="bg-white">
<td className="border border-slate-200 px-3 py-2 font-bold bg-amber-50 text-amber-900">
Random Sampling? YES
</td>
<td className="border border-slate-200 px-3 py-2 text-center bg-emerald-50 text-emerald-800 font-semibold">
Generalize + Cause & Effect
</td>
<td className="border border-slate-200 px-3 py-2 text-center bg-blue-50 text-blue-800 font-semibold">
Generalize only
</td>
</tr>
<tr className="bg-slate-50">
<td className="border border-slate-200 px-3 py-2 font-bold bg-amber-50 text-amber-900">
Random Sampling? NO
</td>
<td className="border border-slate-200 px-3 py-2 text-center bg-purple-50 text-purple-800 font-semibold">
Cause & Effect only (for this group)
</td>
<td className="border border-slate-200 px-3 py-2 text-center bg-rose-50 text-rose-800 font-semibold">
Neither observe only
</td>
</tr>
</tbody>
</table>
</div>
<div className="mt-4 p-3 bg-amber-50 border-l-4 border-amber-500 rounded-r-lg text-sm">
<strong className="text-amber-900">SAT Key Rule:</strong>{" "}
Observational studies (no random assignment) can show{" "}
<em>association</em> but never <em>causation</em>. Only randomized
controlled experiments can establish cause-and-effect.
</div>
</div>
<StudyDesignWidget />
<button
onClick={() => scrollToSection(2)}
className="mt-12 group flex items-center text-amber-600 font-bold hover:text-amber-800 transition-colors"
>
Next: Confidence Intervals{" "}
<ArrowDown className="ml-2 w-5 h-5 group-hover:translate-y-1 transition-transform" />
</button>
</section>
{/* Section 3: Confidence Intervals & Comparing Groups */}
<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-6">
Confidence Intervals & Comparing Groups
</h2>
<div className="prose prose-slate text-lg text-slate-600 mb-8">
<p>
A <strong>Confidence Interval</strong> (Estimate ± Margin of
Error) gives a range where the true population value likely lies.
When comparing two groups, check for <strong>overlap</strong> if
the intervals do not overlap, you can conclude a significant
difference.
</p>
<div className="mt-4 bg-amber-50 border border-amber-200 rounded-xl p-5 space-y-3">
<p className="font-bold text-amber-900">
Key Rules for Confidence Intervals
</p>
<div className="grid md:grid-cols-2 gap-3 text-sm">
<div className="bg-white rounded-lg p-3 border border-amber-100">
<p className="font-bold text-amber-800 mb-1">
Intervals Overlap
</p>
<p className="text-slate-700">
Cannot claim a significant difference between the two
groups.
</p>
</div>
<div className="bg-white rounded-lg p-3 border border-amber-100">
<p className="font-bold text-amber-800 mb-1">
Intervals Don't Overlap
</p>
<p className="text-slate-700">
There is a significant difference the groups are
statistically distinct.
</p>
</div>
</div>
<div className="bg-amber-100 rounded-lg p-3 text-sm">
<p className="font-bold text-amber-900 mb-1">
Larger Samples Smaller Margin of Error
</p>
<p className="text-slate-700">
Increasing the sample size narrows the confidence interval,
giving you a more precise estimate.
</p>
</div>
</div>
</div>
<ConfidenceIntervalWidget />
<button
onClick={() => scrollToSection(3)}
className="mt-12 group flex items-center text-amber-600 font-bold hover:text-amber-800 transition-colors"
>
Next: Practice Quiz{" "}
<ArrowDown className="ml-2 w-5 h-5 group-hover:translate-y-1 transition-transform" />
</button>
</section>
{/* Section 4: Quiz */}
<section
ref={(el) => {
sectionsRef.current[3] = el;
}}
className="min-h-screen flex flex-col justify-center"
>
<h2 className="text-4xl font-extrabold text-slate-900 mb-8">
Practice Time
</h2>
{allQuizzes.map((quiz, idx) => (
<div key={`quiz-${idx}`} className="mb-12">
<Quiz data={quiz} />
</div>
))}
<div className="p-8 bg-amber-900 rounded-2xl text-white text-center mt-12">
<h3 className="text-2xl font-bold mb-4">Topic Mastered!</h3>
<button
onClick={onFinish}
className="px-6 py-3 bg-white text-amber-900 font-bold rounded-full hover:bg-amber-50 transition-colors"
>
Finish Lesson
</button>
</div>
</section>
</div>
</div>
);
};
export default CollectingDataLesson;