Skip to content

B2C Study Plan Freemium Gate

The Study/Lesson Plan sidebar entry is the marquee Pro-gated artifact for B2C users. This doc owns the entry point and the freemium gate around it: free users click it and hit PaywallModal; Pro users click it and land on /study-plan. The entry label is persona-aware ("Study Plan" for learner/parent, "Lesson Plan" for trainer) via artifactKeyFor(signup_intent). The Study Plan page itself is documented in b2c-personalized-learner-journey.md.

How it works

The behavior is a 2x2 of persona (label) × plan (action). Plan gates the action; persona only chooses the label.

Study/Lesson Plan sidebar entry  (nav item with planUpsell: true, B2C only)
  ├── persona (signup_intent) → LABEL only, via artifactKeyFor()
  │      learner → "Study Plan"   parent → "Study Plan"   trainer → "Lesson Plan"
  └── plan → ACTION
         free →  lock icon, click → PaywallModal (upgrade)
         pro  →  normal NavLink → /study-plan

Invariants:

  • Plan gates the action; persona never does. A free trainer and a free learner both hit the paywall; only the label differs.
  • The Study Plan page re-derives the same label independently via artifactKeyFor(user.signup_intent), so the page title matches the nav entry. A null/unknown persona falls back to "Study Plan".
  • /study-plan is reachable only by B2C users (RoleGuard b2c_user). Free users are steered to the paywall at the nav before they can navigate there; a free user who deep-links still hits the role guard, and plan-level gating is primarily enforced at the nav.

DashboardLayout computes the Pro condition for the planUpsell entry: for Pro it rewrites the entry href to ROUTES.studyPlan and renders a plain NavLink; for free it keeps the lock rendering and wires onPlanUpsellClick to setPaywallOpen(true).

Reference

Route Component Purpose
/study-plan (ROUTES.studyPlan) StudyPlanPage Pro-only Study/Lesson Plan (the gated artifact)
i18n key Value
b2c.pricing.artifact.studyPlan "Study Plan" (learner/parent label + page title)
b2c.pricing.artifact.lessonPlan "Lesson Plan" (trainer label + page title)

Where it lives

  • apps/web/src/pages/b2c/StudyPlan/index.tsx: StudyPlanPage, title via t(artifactKeyFor(signup_intent)).
  • apps/web/src/pages/b2c/constants.ts: artifactKeyFor + ARTIFACT_KEY_BY_INTENT.
  • apps/web/src/components/layouts/DashboardLayout.tsx: Pro condition, href rewrite, onPlanUpsellClick for free.
  • apps/web/src/components/layouts/dashboard/NavItem.tsx: NavLink for Pro, lock + paywall button for free.
  • apps/web/src/constants/navigation.ts: planUpsell nav item; apps/web/src/constants/routes.ts has studyPlan: '/study-plan'.
  • apps/web/src/routes/ProtectedRoutes/StudentRoutes.tsx: route under RoleGuard b2c_user.
  • apps/web/src/pages/b2c/components/PaywallModal.tsx: the upgrade prompt free users see.

Related: b2c-two-tier-pricing.md (the Free/Pro model), b2c-persona-vocabulary.md (the learner/trainer/parent → Study/Lesson Plan naming).