diff --git a/sites/mainweb/app/(portal)/club/bootcamp/page.tsx b/sites/mainweb/app/(portal)/club/bootcamp/page.tsx index b913b7ea..ecafa8a2 100644 --- a/sites/mainweb/app/(portal)/club/bootcamp/page.tsx +++ b/sites/mainweb/app/(portal)/club/bootcamp/page.tsx @@ -8,14 +8,12 @@ import { Clock, ExternalLink, CalendarDays, - Check, } from "lucide-react"; import { LoadingScreen } from "@/components/portal/LoadingScreen"; import { BootcampAddOn } from "@/components/portal/BootcampAddOn"; import { BootcampMaterialsTable } from "@/components/portal/BootcampMaterialsTable"; import { trpc } from "@/lib/trpc"; import { - BOOTCAMP_CURRICULUM, BOOTCAMP_MEETING_TIME, BOOTCAMP_ROOM, BOOTCAMP_START_DATE, @@ -35,15 +33,6 @@ function termLabel(term: string) { return `${season.charAt(0).toUpperCase()}${season.slice(1)} ${year}`; } -const dateLabel = (date: Date) => - new Date(date).toLocaleString(undefined, { - weekday: "short", - month: "short", - day: "numeric", - hour: "numeric", - minute: "2-digit", - }); - /** Where and when it meets — the thing somebody checks walking to class. */ function MeetingCard() { return ( @@ -85,54 +74,6 @@ function WorkspaceLink() { ); } -/** For an enrolled member when there is genuinely nothing to show yet. */ -function NothingScheduledYet({ term }: { term: string }) { - return ( -
-

- You are in the {term} bootcamp -

-

- Your spot is confirmed — nothing else to do. We are still putting the - weeks together; sessions, slides and notebooks all appear here as they - are set, and you will hear from us before the first meeting. -

-
- ); -} - -/** Attended, missed, or not taught yet. Only the clock separates the last two. */ -function AttendanceBadge({ - attended, - past, -}: { - attended: boolean; - past: boolean; -}) { - if (attended) { - return ( - - - ); - } - - if (past) { - return ( - - Missed - - ); - } - - return ( - - Upcoming - - ); -} - /** Members buy the add-on here; non-members go to the flow that sells both. */ function NotEnrolled({ term }: { term: string }) { const memberStatus = trpc.member.checkStatus.useQuery(); @@ -144,7 +85,7 @@ function NotEnrolled({ term }: { term: string }) { You are not in the {termLabel(term)} bootcamp

- Twelve weeks of Python and data science, taught in person, with the + Nine weeks of Python and data science, taught in person, with the notebooks to keep. It runs for one semester, so joining covers this term {isMember ? "" @@ -166,20 +107,6 @@ function NotEnrolled({ term }: { term: string }) { ); } -type Week = { - week: number; - title: string; - desc: string; - deepnoteUrl?: string; - session?: { - id: string; - eventDate: Date; - location: string | null; - attended: boolean; - past: boolean; - }; -}; - export default function BootcampPortalPage() { const { data: session, status } = useSession(); const progress = trpc.bootcamp.myProgress.useQuery(undefined, { @@ -195,29 +122,6 @@ export default function BootcampPortalPage() { const data = progress.data; const enrolled = !!data?.enrolled; - const sessions = data?.sessions ?? []; - const byWeek = new Map(sessions.map((row) => [row.week, row])); - - // Curriculum is the spine, so an unscheduled week still shows. - const extras = sessions.filter( - (row) => !BOOTCAMP_CURRICULUM.some((entry) => entry.week === row.week), - ); - const weeks: Week[] = [ - ...BOOTCAMP_CURRICULUM.map((entry) => ({ - week: entry.week, - title: entry.title, - desc: entry.desc, - deepnoteUrl: entry.deepnoteUrl, - session: byWeek.get(entry.week), - })), - ...extras.map((row) => ({ - week: row.week ?? 0, - title: row.title, - desc: row.description ?? "", - deepnoteUrl: undefined, - session: row, - })), - ]; return (

@@ -302,83 +206,6 @@ export default function BootcampPortalPage() {
- - {enrolled && weeks.length === 0 && data ? ( - - ) : ( -
-

- Syllabus -

- - {weeks.length === 0 && ( -

- Updating soon — the week-by-week syllabus is being written and - will appear here before the first session. -

- )} - -
    - {weeks.map((entry) => ( -
  1. -
    -
    -

    - Week {String(entry.week).padStart(2, "0")} -

    -

    - {entry.title} -

    - {entry.desc && ( -

    - {entry.desc} -

    - )} - - {entry.session && ( -

    - - - {dateLabel(entry.session.eventDate)} - - {entry.session.location && ( - - - {entry.session.location} - - )} -

    - )} - - {entry.deepnoteUrl && ( - - - Notebook - - )} - -
    - - {enrolled && entry.session && ( - - )} -
    -
  2. - ))} -
-
- )}
); diff --git a/sites/mainweb/app/bootcamp/page.tsx b/sites/mainweb/app/bootcamp/page.tsx index d2db0aa0..61018c31 100644 --- a/sites/mainweb/app/bootcamp/page.tsx +++ b/sites/mainweb/app/bootcamp/page.tsx @@ -8,8 +8,6 @@ import { BOOTCAMP_START_DATE, } from "@/lib/bootcamp-schedule"; -// Shared with the portal's bootcamp page, so the syllabus a member sees signed -// in is the one that was advertised. const curriculum = BOOTCAMP_CURRICULUM; export default function BootcampPage() { @@ -39,7 +37,7 @@ export default function BootcampPage() {

- Master Python for data science in 12 weeks. From the fundamentals to + Master Python for data science in 9 weeks. From the fundamentals to machine learning, build the skills you need to succeed.

{BOOTCAMP_START_DATE && ( @@ -80,9 +78,11 @@ export default function BootcampPage() {

{item.title}

-

- {item.desc} -

+ {item.desc && ( +

+ {item.desc} +

+ )} diff --git a/sites/mainweb/lib/bootcamp-schedule.test.ts b/sites/mainweb/lib/bootcamp-schedule.test.ts index c51dae8e..d04fdc85 100644 --- a/sites/mainweb/lib/bootcamp-schedule.test.ts +++ b/sites/mainweb/lib/bootcamp-schedule.test.ts @@ -7,9 +7,8 @@ import { weekEntry, } from "./bootcamp-schedule"; -// A hand-edited constant published on a public page. Most of this is vacuous -// while it is empty — these arm themselves the moment the real weeks are typed -// in, which is the one moment nobody runs a test on purpose. +// A hand-edited constant published on a public page, so the guards are here to +// catch a typo in the edit rather than a bug in the code. describe("BOOTCAMP_CURRICULUM", () => { it("numbers each week once", () => { @@ -32,8 +31,9 @@ describe("BOOTCAMP_CURRICULUM", () => { it("gives every week something to render", () => { for (const entry of BOOTCAMP_CURRICULUM) { + // A week may be a title alone, but a blank one renders as an empty card. expect(entry.title.trim()).not.toBe(""); - expect(entry.desc.trim()).not.toBe(""); + if (entry.desc !== undefined) expect(entry.desc.trim()).not.toBe(""); } }); diff --git a/sites/mainweb/lib/bootcamp-schedule.ts b/sites/mainweb/lib/bootcamp-schedule.ts index 52051ed1..a3c5b20a 100644 --- a/sites/mainweb/lib/bootcamp-schedule.ts +++ b/sites/mainweb/lib/bootcamp-schedule.ts @@ -1,12 +1,14 @@ /** - * The public bootcamp syllabus. The portal's downloadable weekly material is - * edited separately, while the marketing page still needs stable public copy. + * The bootcamp syllabus shown on the public marketing page. The portal lists + * real scheduled workshops from the database instead, so nothing here reaches + * a signed-in member. */ export type BootcampWeek = { week: number; title: string; - desc: string; + /** Optional: a week may be published as a title alone. */ + desc?: string; /** Overrides the default room for a week that moves. */ room?: string; /** The notebook for this week, if it has its own link. */ @@ -26,68 +28,16 @@ export const BOOTCAMP_START_DATE: string | null = "September 22, 2026"; /** The Deepnote workspace every session works out of. */ export const BOOTCAMP_WORKSPACE_URL: string | null = null; -// Restored from f515a3d9. Confirm the titles before the term starts. export const BOOTCAMP_CURRICULUM: BootcampWeek[] = [ - { - week: 1, - title: "Python Basics & Setup", - desc: "Variables, data types, and environment configuration.", - }, - { - week: 2, - title: "Control Flow & Structures", - desc: "Loops, conditionals, lists, and dictionaries.", - }, - { - week: 3, - title: "Functions & Modules", - desc: "Writing reusable code and organizing projects.", - }, - { - week: 4, - title: "Object-Oriented Programming", - desc: "Classes, inheritance, and Pythonic design.", - }, - { - week: 5, - title: "File Handling & APIs", - desc: "Reading files, writing data, and making web requests.", - }, - { - week: 6, - title: "Pandas & NumPy", - desc: "Introduction to fast numerical computing and DataFrames.", - }, - { - week: 7, - title: "Data Cleaning", - desc: "Handling missing values, merging, and data transformations.", - }, - { - week: 8, - title: "Exploratory Data Analysis", - desc: "Extracting insights and statistical summaries from data.", - }, - { - week: 9, - title: "Data Visualization", - desc: "Creating stunning charts using Matplotlib and Seaborn.", - }, - { - week: 10, - title: "Intro to Machine Learning", - desc: "Core concepts, train/test splits, and Scikit-Learn.", - }, - { - week: 11, - title: "Supervised Learning", - desc: "Linear regression, logistic regression, and decision trees.", - }, - { - week: 12, - title: "Capstone Project", - desc: "Build an end-to-end data science portfolio piece.", - }, + { week: 1, title: "Core Library & Data Wrangling" }, + { week: 2, title: "Linear Regression" }, + { week: 3, title: "Logistic Regression" }, + { week: 4, title: "Decision Trees / Ensemble Methods" }, + { week: 5, title: "Clustering" }, + { week: 6, title: "Deep Learning" }, + { week: 7, title: "Creative Projects" }, + { week: 8, title: "Creative Projects" }, + { week: 9, title: "Creative Projects" }, ]; /** The curriculum entry a session's week number refers to, if there is one. */