From 26951a633d3e38416555c30e725b3172bd02facc Mon Sep 17 00:00:00 2001 From: Sarah Tucker Date: Tue, 15 Sep 2026 12:24:20 +0100 Subject: [PATCH 1/2] Add a restyled copy of the club card action prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A copy of onboarding-mentor/dashboard-primary-action with the confirm screen rebuilt. Copied rather than restyled in place, per the repo rule — the original belongs to someone else, and two treatments of one route only compare if both are still there to compare. Everything but the confirm screen is unchanged, including the cast, so a session can attribute a reaction to the presentation rather than the route. The confirm screen is now one centred card modelled on the Experience CS interstitial: the three points about Code Classroom are green panels with a Material Symbols icon instead of bullets, the copy is rewritten around "creators", and the primary action sits bottom right after the explanation rather than beside it. No illustration yet — what it should show has not been designed, and an invented one would get reacted to as though it had. The hypothesis in meta.ts is marked DRAFT for Sarah to confirm: that the confirm screen is where a mentor learns what Code Classroom is, and that a mentor who has read this version can say what they agreed to. Co-Authored-By: Claude Opus 5 --- .../DashboardWithClassroom.tsx | 154 +++++++++ .../card-action-restyled/FeatureBox.tsx | 61 ++++ .../card-action-restyled/meta.ts | 20 ++ .../card-action-restyled/notes.md | 85 +++++ .../card-action-restyled/prototype.tsx | 295 ++++++++++++++++++ 5 files changed, 615 insertions(+) create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/DashboardWithClassroom.tsx create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/FeatureBox.tsx create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/meta.ts create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/notes.md create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/DashboardWithClassroom.tsx b/src/prototypes/onboarding-mentor/card-action-restyled/DashboardWithClassroom.tsx new file mode 100644 index 0000000..e141dfd --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/DashboardWithClassroom.tsx @@ -0,0 +1,154 @@ +import { Alert, Button } from '../../../kit' +import type { School } from '../../../fixtures' + +// A COPY of screens/code-club/MentorDashboard, changed here rather than there. +// +// The shared screen has no prop for another club action, and the change this +// prototype is making is not a prop — it is a reordering of the card's +// actions, which is the whole hypothesis. So it is copied in, per the repo +// rule: never edit a shared screen, copy it and change your copy. +// +// What is different from the live dashboard: +// +// - "Code Classroom" is the primary button on each club card, first in the row. +// - "Create an event" is gone from the card entirely. That is a real cost, not +// a detail — events are how a club fills its sessions and how Code Club +// counts activity — and it is the trade this variant is making on purpose. +// - Nothing on the card is labelled as a proposal. The page reads as if it +// shipped, so a mentor in a session reacts to the product rather than to a +// prototype. What is and is not real is in notes.md. +// +// Everything else is left exactly as the shared screen has it. + +interface Props { + clubsManaged: School[] + pendingRequests: string[] + onDismissRequest: (request: string) => void + onManageClub: (schoolId: string) => void + onViewPublicProfile: (schoolId: string) => void + onStartAClub: () => void + onFindAClub: () => void + clubsVolunteeredAt?: School[] + /** Which of these clubs already has a Code Classroom behind it. */ + isSetUp: (schoolId: string) => boolean + onCodeClassroom: (schoolId: string) => void +} + +export function DashboardWithClassroom({ + clubsManaged, + pendingRequests, + onDismissRequest, + onManageClub, + onViewPublicProfile, + onStartAClub, + onFindAClub, + clubsVolunteeredAt = [], + isSetUp, + onCodeClassroom, +}: Props) { + return ( +
+ + +
+

Your Clubs

+ + {pendingRequests.map((request) => ( + onDismissRequest(request)} + /> + ))} + +
+

Clubs you manage

+ +
+ + {clubsManaged.map((club) => ( +
+
{club.name}
+
+
+

+ Nearest 4.5 miles +

+

{club.venue ?? 'No venue set'}

+
+
+

{club.schedule ?? 'No sessions scheduled'}

+

+ {club.online ? 'Online Sessions' : 'In-person Sessions'} +

+
+
+
+ {/* The proposal. Primary, and first — a mentor arriving with + "what are we doing on Thursday?" should not have to know + the words "Manage club". "Create an event" is not here at + all: this variant gives the card's top slot to Code + Classroom rather than sharing it. */} +
+
+ ))} + +
+

Clubs you volunteer at

+ +
+ + {clubsVolunteeredAt.length === 0 ? ( +
+

You have not volunteered at any Clubs

+

+ Why not explore our resources on{' '} + recruiting volunteers for your Club +

+
+ ) : ( +
    + {clubsVolunteeredAt.map((club) => ( +
  • + {club.name} +
  • + ))} +
+ )} +
+
+ ) +} diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/FeatureBox.tsx b/src/prototypes/onboarding-mentor/card-action-restyled/FeatureBox.tsx new file mode 100644 index 0000000..4371bba --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/FeatureBox.tsx @@ -0,0 +1,61 @@ +import type { ReactNode } from 'react' + +interface Props { + /** + * A Material Symbols ligature name, e.g. "checklist". The font renders the + * text content as the glyph, so this IS the icon. + */ + icon: string + title: string + children: ReactNode +} + +/** + * A pale green panel with an icon, a bold title and a line underneath — what + * the three "what Code Classroom is" points are shown as, instead of bullets. + * + * Local to this prototype rather than added to kit/: the kit has no equivalent, + * and the repo rule is that a prototype adds to its own folder. If a second + * prototype wants one of these, copy it. + * + * Material Symbols Outlined is already loaded by the design system's + * stylesheet — the same family Surface uses for its breadcrumb chevron and + * safeguarding flag — so there is no font to add and no dependency to install. + * + * The icon is decorative and hidden from screen readers: the title next to it + * says the same thing, and a reader announcing the ligature name would just + * read "checklist" twice. + */ +export function FeatureBox({ icon, title, children }: Props) { + return ( +
+ + {/* Body size, bold — still an h3, so the heading structure survives + it reading at the same scale as the line underneath. */} +

+ {title} +

+

+ {children} +

+
+ ) +} diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/meta.ts b/src/prototypes/onboarding-mentor/card-action-restyled/meta.ts new file mode 100644 index 0000000..44398a2 --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/meta.ts @@ -0,0 +1,20 @@ +import type { PrototypeMeta } from '../../types' + +export const meta: PrototypeMeta = { + title: 'Club card action, restyled', + + owner: 'Sarah Tucker', + + // DRAFT — Sarah to correct. The flow is a straight copy of + // "Code Classroom as the club card action", so the route is not what is + // being tested here; only how the confirm screen is presented. + hypothesis: + 'The confirm screen is where a mentor decides whether Code Classroom is for them, and two dense cards of prose get skimmed. Presented as one centred explainer — a short claim per panel, each with an icon — a mentor will be able to say in their own words what Code Classroom is before they press yes, rather than agreeing and finding out afterwards.', + + status: 'sketch', + + // The same mentor as the prototype this copies, on purpose: two visual + // treatments of one route only compare if the club, the code and the class + // name are identical. + cast: { piAccount: 'pi-mentor-jo' }, +} diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/notes.md b/src/prototypes/onboarding-mentor/card-action-restyled/notes.md new file mode 100644 index 0000000..d04a1cd --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/notes.md @@ -0,0 +1,85 @@ +A copy of **Code Classroom as the club card action** (Divya Mahadevan) with one +screen restyled. The route, the fixtures, the fake latency and every other step +are unchanged, on purpose — if more than the presentation varied, a session +could not tell which change caused the reaction. + +## What question is this answering? + +The `onboarding-mentor` lane, but not the part about where the entry point +lives. The prototype this copies already bets on that: Code Classroom as the +primary button on the club card. This one takes that bet as settled and asks +the next question down. + +**Does a mentor know what they have agreed to?** + +The confirm screen is the only place a mentor is told what Code Classroom is. +They arrive from a button on a dashboard, having possibly never heard the +product name, and one press later they have a school, a club code and a class. +If that screen gets skimmed, the route succeeds on the measure it set itself — +one click to a working Code Classroom — while leaving a mentor who cannot say +what they now own. + +## Why this approach + +Two dense cards of prose, stacked full width, is a layout people scroll past. +So the confirm screen is rebuilt as a single centred explainer, modelled on the +Experience CS → Code Classroom interstitial that already exists in the real +products: + +- **One card, not two.** Title inside it, narrow measure, floating on the page + green. It reads as a thing to be read rather than a form to get past. +- **Three green panels instead of bullets.** One claim each, an icon, a short + line. A bullet list invites skimming to the end; separated panels are harder + to skip without noticing you skipped them. +- **Primary action last, bottom right.** Matching the reference. It also puts + the button after the explanation rather than beside it. + +**Rejected:** a "Learn more" link out to a marketing page, as the reference has. +It solves the comprehension problem by moving it somewhere a mentor in a club +session will not go. If the explanation cannot fit on the screen that asks for +consent, the ask is in the wrong place. + +**Rejected:** a second confirm step. The one-press claim is the whole point of +the route being copied; adding a step would test a different thing. + +## What is not real + +- **The confirm screen does not exist in either product.** The entire thing is + a proposal. Nothing in Code Club today offers to create a Code Classroom + school for you. +- **There is no illustration.** The reference card carries a diagram of the two + products handing off, between the list and the buttons. Left out for now — + what it should show has not been designed, and an invented one would get + reacted to in a session as though it had been. Worth deciding before this + goes in front of anyone: the card currently explains Code Classroom in words + only. +- Automatic setup infers **one** class from the club's session time. Westlands + really runs a Scratch group and a Python group — the same honest limit as the + prototype this copies. + +## What I'd want to watch in testing + +- **At the moment they press yes:** ask them to say what Code Classroom is + without looking. That is the whole hypothesis, and it is the only question + here that the original prototype does not already answer. +- **Whether the green panels get read or counted.** Three panels may just be a + bulleted list with more furniture. If people's eyes go straight to the + button, the restyle has not earned its keep and the finding is worth as much + as a positive one. +- **"Creators".** The confirm card now says creators throughout — it is the + word Code Club uses. Two places still do not: the created screen says "an + account for each young person at your club", and Code Classroom itself will + say students the moment a mentor arrives in it. So the handover is where the + word changes, which is exactly where a mentor is least able to absorb it. + Worth watching whether anyone notices they have become a teacher with + students. +- **The word "school"**, still. A volunteer at a library is told they are + getting a school. The card no longer glosses it — the earlier draft said + "Code Classroom's word, not ours", which was the prototype apologising for + the product. Without the aside the screen is a fairer test of whether the + word actually lands, but it also means nobody is warned. This is the sharpest + edge on the screen. + +## What we learned + +Not tested yet. diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx b/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx new file mode 100644 index 0000000..81f8fdd --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx @@ -0,0 +1,295 @@ +import { useEffect, useState, type CSSProperties } from 'react' +import { Alert, Button, Card, ProgressBar } from '../../../kit' +import { schoolsForMentor, type ClassGroup, type School } from '../../../fixtures' +import { EducatorClassPage } from '../../../screens' +import { Surface } from '../../../surfaces' +import { meta } from './meta' +import { DashboardWithClassroom } from './DashboardWithClassroom' +import { FeatureBox } from './FeatureBox' + +// A mentor, signed in on codeclub.org. Everything below comes from the cast in +// meta.ts — Jo manages two clubs, so the dashboard has two cards and "which +// club am I setting up?" is answered by which card you press. +const CLUBS: School[] = schoolsForMentor(meta.cast?.piAccount ?? '') + +const DAYS = [ + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday', +] as const + +/** + * The class automatic setup would create, named from what codeclub.org already + * knows about the club's sessions. Derived, not hardcoded: change the cast and + * the club, the code and the class name all follow. + * + * Only one class, because that is all an automatic setup can honestly infer. + * Westlands really runs a Scratch group and a Python group — see notes. + */ +function autoClass(club: School): ClassGroup { + const day = DAYS.find((d) => club.schedule?.includes(d)) + return { + id: `auto-${club.id}`, + schoolId: club.id, + name: day ? `${day} club` : 'Club session', + kind: 'code-club', + studentIds: [], + } +} + +type Step = 'dashboard' | 'confirm' | 'creating' | 'created' | 'classroom' + +/** + * A section heading and the copy it introduces, held tight to each other. + * + * The card's own column gap is 16px, which is right between blocks but too + * loose between a heading and the sentence it belongs to. So a section is its + * own little column at 4px, and the 16px top margin — on top of the card's + * 16px — is what gives every section the same 32px above it. + */ +const SECTION: CSSProperties = { + display: 'flex', + flexDirection: 'column', + gap: 'var(--space-05)', + marginTop: 'var(--space-2)', +} + +export default function DashboardPrimaryAction() { + const [step, setStep] = useState('dashboard') + /** Clubs that have been through setup, so the button changes on return. */ + const [setUpClubIds, setSetUpClubIds] = useState([]) + const [activeClubId, setActiveClubId] = useState(CLUBS[0].id) + /** What a route we have not built would have done. */ + const [notice, setNotice] = useState() + + const club = CLUBS.find((c) => c.id === activeClubId) ?? CLUBS[0] + const classes = [autoClass(club)] + + // Fake latency, because "it set itself up" is a claim about how long a + // mentor waits, and a setup that returns instantly tests a different thing. + useEffect(() => { + if (step !== 'creating') return + const timer = setTimeout(() => { + setSetUpClubIds((ids) => (ids.includes(club.id) ? ids : [...ids, club.id])) + setStep('created') + }, 1800) + return () => clearTimeout(timer) + }, [step, club.id]) + + const noticeAlert = notice ? ( + setNotice(undefined)} /> + ) : null + + /** + * What setup makes, derived from the club. Shown before and after, so it + * stays tenseless — the confirm screen supplies "we'll create:" above it and + * the created screen supplies "What was set up". + * + * The values stay interpolated. Changing the cast has to move the club name, + * the code and the class name together, or the flow offers one club's code + * and then names a different club's session. + */ + const whatYouGet = ( +
    +
  • + A school called {club.name} +
  • +
  • + A club code {club.schoolCode} for creators to sign in +
  • +
  • + A class called {classes[0].name}, based on your session +
  • +
+ ) + + // The mentor is asked once, and asked nothing else. No form, no naming, no + // choosing whether the club is a school or a class — all of that is + // answerable from what Code Club already knows. + // + // THIS IS THE ONLY SCREEN THAT DIFFERS from the prototype this copies. Laid + // out like the Experience CS → Code Classroom interstitial: one narrow card + // centred on the page colour, everything inside it, and the two actions + // bottom right with the primary last. The three points about what Code + // Classroom is are green panels with an icon rather than bullets, because + // the bet is that the explanation is what gets skimmed. + // + // Inline styles rather than new classes: global.css is shared, and the repo + // rule is that a prototype changes nothing outside its own folder. + if (step === 'confirm') { + return ( + +
+
+ +
+

Set up Code Classroom for {club.name}?

+ +
+

What is Code Classroom?

+

+ Code Classroom is a free, safe environment for teaching and learning + computing. You can choose projects for your creators, create their accounts, + and see the work they save. +

+
+ + + Share projects with your club so creators know what to work on + + + Set up usernames and passwords without email addresses or parent sign-up + + + Creators can sign in again and continue where they left off + + +
+

What we'll set up

+

If you continue, we'll create:

+ {whatYouGet} +
+ +

+ Nothing will be shared with your club or made public. You can change these + names later. +

+ + {/* The reference card carries a diagram of the two products + between the list and the buttons. Left out for now — what it + should show has not been designed. */} + +
+
+
+
+
+
+
+ ) + } + + if (step === 'creating') { + return ( + +
+

Setting up Code Classroom

+ + +

This will take a few seconds. You do not need to do anything.

+
+
+
+ ) + } + + if (step === 'created') { + return ( + +
+

Your Code Classroom account has been created

+ + +

What was set up

+ {whatYouGet} +

+ You sign in with the same Raspberry Pi account you use for Code Club — there is no new + password to remember. +

+

+ Not set up: an account for each young person at your club. Nothing on codeclub.org + knows who they are, so that part cannot be done for you. +

+
+
+ ) + } + + // Where a mentor lands: the real Code Classroom page, in the empty state a + // mentor who has just been set up would actually find. Code Classroom has no + // educator home page to land on instead — you arrive at a class and move by + // breadcrumb — so this is the product as it is, not a proposal. + if (step === 'classroom') { + return ( + +
+ {noticeAlert} +
+
+ ) + } + + return ( + + {}} + onManageClub={() => {}} + onViewPublicProfile={() => {}} + onStartAClub={() => {}} + onFindAClub={() => {}} + isSetUp={(schoolId) => setUpClubIds.includes(schoolId)} + onCodeClassroom={(schoolId) => { + setActiveClubId(schoolId) + // Already set up? Straight in. Otherwise the mentor is asked first. + setStep(setUpClubIds.includes(schoolId) ? 'classroom' : 'confirm') + }} + /> + + ) +} From 97bd1db6d58822415381bd169d7d382ad00d5435 Mon Sep 17 00:00:00 2001 From: Sarah Tucker Date: Tue, 15 Sep 2026 15:07:07 +0100 Subject: [PATCH 2/2] Carry the card through to the end, and name the blocker on arrival MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes to where the flow lands. The created screen now uses the same centred card as the confirm screen, so arriving reads as the other side of the question rather than a different page. The four layout objects both screens share are pulled up next to SECTION rather than copied, so the two cannot drift apart. The class page gains an information alert between its title band and its content: the class has no members, nobody can sign in until the mentor creates their accounts, and an action opens three steps saying how. That blocker is the one thing setup cannot do — nothing on codeclub.org knows who the young people are — and a mentor who does not meet it here meets it in front of a room instead. Neither the alert nor the steps behind it are in the product, and the account-creation screen does not exist anywhere in this repo. The panel says so rather than implying a flow sits behind it; notes.md records both. EducatorClassPage renders its two bands as a fragment with no seam between them, so it is copied in as ClassPageWithBanner with one added prop. Nothing else about it is changed, and nothing shared is touched. Co-Authored-By: Claude Opus 5 --- .../ClassPageWithBanner.tsx | 153 +++++++++++++++++ .../card-action-restyled/notes.md | 21 ++- .../card-action-restyled/prototype.tsx | 155 +++++++++++++----- 3 files changed, 288 insertions(+), 41 deletions(-) create mode 100644 src/prototypes/onboarding-mentor/card-action-restyled/ClassPageWithBanner.tsx diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/ClassPageWithBanner.tsx b/src/prototypes/onboarding-mentor/card-action-restyled/ClassPageWithBanner.tsx new file mode 100644 index 0000000..634c44a --- /dev/null +++ b/src/prototypes/onboarding-mentor/card-action-restyled/ClassPageWithBanner.tsx @@ -0,0 +1,153 @@ +import type { ReactNode } from 'react' +import { Button, Card } from '../../../kit' +import type { ClassGroup, Project } from '../../../fixtures' + +// A COPY of screens/classroom/EducatorClassPage, changed here rather than +// there. +// +// The shared screen renders its two bands — the white title block and the +// off-white content below it — as a fragment, with nothing between them and no +// prop to put anything there. Putting the "no members yet" alert where it +// belongs means opening that seam, and opening it in the shared screen would +// change the page for every other prototype using it. So it is copied in, per +// the repo rule. +// +// What is different from the shared screen: +// +// - A `banner` slot between the two bands. +// +// That is the whole change. Everything else is the shared screen as it stands, +// including the real page's furniture: "Class members" is the primary action, +// projects sit in a bordered list of pale rows, and a project name is bold body +// text rather than a link. Keep it that way — if the shared screen gains +// something, this copy should gain it too. + +interface Props { + classGroup: ClassGroup + projects: Project[] + memberCount: number + /** The blurb under the class title. */ + description?: string + /** + * Rendered between the title band and the content, which is where a page- + * level message belongs — after a mentor has read what page they are on, and + * before the thing they would otherwise start doing. + */ + banner?: ReactNode + onAddProject: () => void + onOpenProject: (projectId: string) => void + onCopyLink: () => void + onClassMembers: () => void + /** Projects students cannot see yet. */ + hiddenProjectIds?: string[] + /** The per-row overflow menu. Renders whether or not you wire it. */ + onProjectMenu?: (projectId: string) => void + /** The gear beside "Copy link". Renders whether or not you wire it. */ + onSettings?: () => void +} + +export function ClassPageWithBanner({ + classGroup, + projects, + memberCount, + description, + banner, + onAddProject, + onOpenProject, + onCopyLink, + onClassMembers, + hiddenProjectIds = [], + onProjectMenu, + onSettings, +}: Props) { + return ( + <> +
+
+

{classGroup.name}

+ {description &&

{description}

} +
+ +
+ {/* Primary on the live page. Getting young people into the class is + the job a mentor comes here to do. */} +
+
+ + {/* Padded to the same gutter as both bands, so the alert lines up with + the title above it and the Projects card below it. */} + {banner &&
{banner}
} + +
+ +
+
+

Projects

+

+ Projects are shared with students and contain starter code created by a teacher. +

+
+
+ + {projects.length === 0 ? ( +

No projects yet

+ ) : ( +
    + {projects.map((project) => { + const hidden = hiddenProjectIds.includes(project.id) + return ( +
  • + + {hidden && ( + // Labelled rather than aria-hidden: the icon is the only + // thing on the row carrying this, so it has to be read. + + visibility_off + + )} + + +
  • + ) + })} +
+ )} +
+
+ + ) +} diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/notes.md b/src/prototypes/onboarding-mentor/card-action-restyled/notes.md index d04a1cd..f953df4 100644 --- a/src/prototypes/onboarding-mentor/card-action-restyled/notes.md +++ b/src/prototypes/onboarding-mentor/card-action-restyled/notes.md @@ -56,6 +56,15 @@ the route being copied; adding a step would test a different thing. - Automatic setup infers **one** class from the club's session time. Westlands really runs a Scratch group and a Python group — the same honest limit as the prototype this copies. +- **The "no members yet" alert is not in the product.** The class page itself + is the real, verified screen; the alert sitting between its two bands is this + prototype's addition, and so is the "Adding members" panel behind it. The + class page is copied into this folder as `ClassPageWithBanner` purely to open + a seam between the title band and the content — one added prop, nothing else + changed. +- **The steps in that panel are not a screen either.** Step 2, creating the + accounts, has no screen anywhere in this repo. The panel says so rather than + implying a flow exists behind it. ## What I'd want to watch in testing @@ -78,7 +87,17 @@ the route being copied; adding a step would test a different thing. "Code Classroom's word, not ours", which was the prototype apologising for the product. Without the aside the screen is a fairer test of whether the word actually lands, but it also means nobody is warned. This is the sharpest - edge on the screen. + edge on the screen, and the school page at the end says it again, in the + title, at full size. +- **Whether anyone opens "How do I add members?"** The alert names the blocker + on arrival; the action behind it is the test of whether naming it is enough. + If people read the alert and still press "Add project" first, the alert is + decoration. +- **Whether the alert reads as help or as failure.** "Your class has no members + yet" arrives seconds after a screen that said setup was done. It is either + the obvious next step or evidence that the one-press promise was oversold — + and which of those it is, is the most useful thing a session could tell us + about this whole route. ## What we learned diff --git a/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx b/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx index 81f8fdd..7cae99a 100644 --- a/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx +++ b/src/prototypes/onboarding-mentor/card-action-restyled/prototype.tsx @@ -1,7 +1,7 @@ import { useEffect, useState, type CSSProperties } from 'react' import { Alert, Button, Card, ProgressBar } from '../../../kit' import { schoolsForMentor, type ClassGroup, type School } from '../../../fixtures' -import { EducatorClassPage } from '../../../screens' +import { ClassPageWithBanner } from './ClassPageWithBanner' import { Surface } from '../../../surfaces' import { meta } from './meta' import { DashboardWithClassroom } from './DashboardWithClassroom' @@ -58,6 +58,27 @@ const SECTION: CSSProperties = { marginTop: 'var(--space-2)', } +/** + * The card layout both of this flow's own screens use: one narrow card + * centred on the page colour, everything inside it, actions bottom right. + * + * Shared between the confirm screen and the created screen so the two look + * like one route rather than two prototypes. Not in kit/ — a prototype adds to + * its own folder. + */ +const PAGE: CSSProperties = { + display: 'flex', + justifyContent: 'center', + padding: 'var(--space-4) var(--space-2)', +} +const COLUMN: CSSProperties = { width: '100%', maxWidth: 760 } +const CARD_STACK: CSSProperties = { + display: 'flex', + flexDirection: 'column', + gap: 'var(--space-2)', +} +const ACTIONS: CSSProperties = { justifyContent: 'flex-end', marginTop: 'var(--space-2)' } + export default function DashboardPrimaryAction() { const [step, setStep] = useState('dashboard') /** Clubs that have been through setup, so the button changes on return. */ @@ -65,6 +86,8 @@ export default function DashboardPrimaryAction() { const [activeClubId, setActiveClubId] = useState(CLUBS[0].id) /** What a route we have not built would have done. */ const [notice, setNotice] = useState() + /** Whether the mentor has asked how members get added. */ + const [showHowTo, setShowHowTo] = useState(false) const club = CLUBS.find((c) => c.id === activeClubId) ?? CLUBS[0] const classes = [autoClass(club)] @@ -123,16 +146,10 @@ export default function DashboardPrimaryAction() { if (step === 'confirm') { return ( -
-
+
+
-
+

Set up Code Classroom for {club.name}?

@@ -169,10 +186,7 @@ export default function DashboardPrimaryAction() { between the list and the buttons. Left out for now — what it should show has not been designed. */} -
+
+
+ +
) } - // Where a mentor lands: the real Code Classroom page, in the empty state a - // mentor who has just been set up would actually find. Code Classroom has no - // educator home page to land on instead — you arrive at a class and move by - // breadcrumb — so this is the product as it is, not a proposal. + // Where a mentor lands: the real Code Classroom class page, in the empty + // state a mentor who has just been set up would actually find. + // + // The alert above it is THIS PROTOTYPE'S ADDITION and is not in the product. + // Setup makes a school, a code and a class and then stops — the creators are + // the one thing it cannot do, because nothing on codeclub.org knows who they + // are. A mentor who does not realise that leaves with a class nobody can get + // into, and finds out in front of a room of young people. So the blocker is + // stated on arrival, and the alert offers the next step rather than just + // naming the problem. if (step === 'classroom') { return ( setStep('dashboard')} /> - + setShowHowTo(true) }, + ]} + > + Setting up made the class, but not the creators in it. Until you create their + accounts nobody can sign in — the club code on its own is not enough. + + + {showHowTo && ( + +

Adding members

+
    +
  1. + Open Class members at the top of this page. +
  2. +
  3. + Create a username and a password for each creator. No email addresses, + and nothing for a parent to sign up to. +
  4. +
  5. + Give them the club code {club.schoolCode} with the + username and password you made for them, and they can sign in. +
  6. +
+

+ Step 2 is not built in this prototype. What it actually takes to create a + set of accounts — one at a time, or in a batch, and who writes the + passwords down — is its own question, and this flow stops at the point + where it becomes one. +

+
+ )} +
+ } onAddProject={() => setNotice( 'Not built here — getting a Code Club project into Code Classroom is the importing lane’s question.', @@ -261,11 +334,13 @@ export default function DashboardPrimaryAction() { onOpenProject={() => {}} onCopyLink={() => setNotice( - 'Copy link shares the class. It skips the club code screen, but a young person still needs an account you made for them.', + 'Copy link shares the class. It skips the club code screen, but a creator still needs an account you made for them.', ) } onClassMembers={() => - setNotice('No members yet. You have not created any accounts.') + setNotice( + 'Not built here — creating the accounts is the step this flow stops at. See "How do I add members?" above.', + ) } />