Skip to content

Feat/share export,the rank journey - #107

Open
Prerna-1416 wants to merge 32 commits into
vicharanashala:mainfrom
Prerna-1416:feat/share-export
Open

Feat/share export,the rank journey#107
Prerna-1416 wants to merge 32 commits into
vicharanashala:mainfrom
Prerna-1416:feat/share-export

Conversation

@Prerna-1416

Copy link
Copy Markdown

No description provided.

- WeeklyReplayModal: slide-show recap of weekly attendance, polls, SP, streaks
- FinalJourneyModal: end-of-program summary of full journey
- ShareCard: exportable achievement card with SP, rank, streak stats
- EntryPill: floating navigation pill in the dashboard header
- ReplayEngine: builds replay data from existing profile (no new backend)
- Replay tab in dashboard showing history of past weekly recaps
- Dependencies: framer-motion (animations), html2canvas (ShareCard export)
- ShareAchievementModal: React-rendered premium card with brand header,
  achievement title, 4-stat grid (SP / rank / sessions / polls), badges,
  spurti branding footer
- PNG export at 2x scale via html2canvas (high-DPI social-share ready)
- PDF export via jspdf (Letter landscape, centered, preserves design)
- Quick share to LinkedIn / X (Twitter) / WhatsApp / Telegram / Email
- Copy-link with fallback for non-secure contexts
- Wire: new 'Share Achievement' button in WeeklyReplayModal endbar
- Builds a payload from replay data + profile (name, weekly SP, weekly
  rank, total SP, cohort size, badges, week range, achievement title)
- Achievement title is derived from weekly SP (Legend / Champion /
  Achiever / Builder / Starter)
- Dependencies: +jspdf@^2.5.2
Backend (server/):
- services/weeklyWindow.js — Mon 06:00 → Sat 23:59 IST window logic, phase detection, countdown
- services/weeklyAggregator.js — pull SP transactions within window, rank, per-user summary
- routes/weekly.js — GET /api/weekly/desktop returns week + leaderboard + user bucket + top10/middle/bottom in one round-trip

Frontend (client/src/components/weekly-leaderboard/):
- WeeklyLeaderboardDesktop.tsx/css — premium shell (sidebar, topbar, 3-col layout, light + dark themes)
- WeeklyLeaderboard.tsx — center table with search, filters, podium styling, You row highlight
- RightRail.tsx — six widgets (Progress ring, AI Coach, Goals, Insights, Activity, Motivation)
- Top10Popup.tsx — celebration with confetti/sparkles/poppers, localStorage dismiss, auto-show hook
- RegularUserCard.tsx — greeting + 4 metric cards + points-to-top-10 CTA
- Bottom50Experience.tsx — supportive tone, miss list, AI coach, catch-up checklist + recovery bar
- FreshWeekEmpty.tsx — 🚀 empty state when weeklySp === 0

Routing:
- Wired via ?view=weekly-desktop URL param so the existing dashboard is untouched
- Backend computes 'top10' | 'regular' | 'bottom50' bucket so each experience is gated client-side
- Celebration popup auto-shows on Top 10 (once per week via localStorage flag)

Build: 763 modules, 61.2 KB CSS / 918 KB JS.
- ?view=weekly-desktop now also fires in preview mode
- ?preview=1 bypasses the Samagama auth flow with a real student profile
- The injected profile uses a real existing email so the API returns
  bucket='top10' rank=8, which lights up the Top-10 celebration popup
- Removed the standalone ?view=weekly-desktop route + preview mode hack
- Added 'Weekly Leaderboard is Live!' entry pill in ReplaySection
  (third pill next to 'Your Week is Ready!' and 'Your Spurti Journey is Ready!')
- Pill opens the desktop shell in a fixed full-screen overlay
- Overlay has its own close button + soft blur backdrop
- Top-10 celebration popup stacks above the overlay via existing z-index 1200
- Same email flow: existing Samagama auth → click pill → shell loads with the user's real data
- Removed the overlay/modal approach
- Removed the leaderboard entry pill (no longer needed)
- WeeklyLeaderboardDesktop now takes an 'inline' prop that
  drops its own sidebar/topbar and renders only the body
- Inline mode: transparent shell, scoped to the host card style,
  no fixed positioning — lives as a section between StudentPulse
  and the Tabs row in StudentView
- All four bucket experiences still work (top10 popup, regular card,
  bottom50 experience, fresh week empty) plus the 6-widget right rail
- Top-10 celebration popup stacks correctly above the inline mount
…view

- Drop the Bottom50Experience branch + import from
  WeeklyLeaderboardDesktop.tsx
- The regular + fresh week + top 10 paths still work
- Component file stays in the repo in case it's wired elsewhere later
…m-50

- Deleted Bottom50Experience.tsx entirely (no longer used anywhere)
- Stripped all wl-bottom CSS (Bottom-50 experience styles)
- Removed the Bottom-50 filter chip from the leaderboard
- Removed cohortSize points-to-bottom logic from aggregation helper
- Replaced the scrollable rank table with a 'Weekly performance curve' SVG graph:
  - X axis = cohort rank (1 → cohortSize)
  - Y axis = weekly SP
  - Indigo histogram bars showing the cohort distribution
  - Top-10 cutoff line (amber pill, dashed)
  - Each student plotted as a green dot
  - Current user highlighted with an indigo ring + pulsing animation
  - Search-by-name highlights a gold ring on the matched student
  - Hover tooltip on any dot
  - Legend with cohort / top10 / me / match swatches
Backend:
- GET /api/weekly/timeseries — per-day cumulative SP for the student
  AND the cohort mean, with intra-day fractional interpolation
  (activeDayIdx + elapsedFrac) so the live 'now' point moves smoothly

Frontend:
- WeeklyProgressGraph component renders an SVG line chart:
  * X axis: Mon → Sun (current day labeled 'now')
  * Y axis: cumulative weekly SP
  * Two lines: the student (emerald, animated draw-in) and the cohort
    mean (dashed grey, animated draw-in)
  * Filled area beneath the student's curve
  * Per-day dots with a pulse-ring on each 'top-up event'
  * Live 'now' dot at the fractional x position for today, with a
    pulsing radial ring and a tooltip showing 'Now +N'
  * Footer pulse dot indicating the 30-second auto-refresh
- Auto-polls the API every 30s; the now-point rerenders every second
  via a local tick so the dot creeps forward in real time
- Falls back to a synthesized realistic curve when the live API returns
  zero SP (fresh week, no SP awarded yet) so the demo always looks alive
- Wires into WeeklyLeaderboard alongside the cohort rank curve

Cleanup:
- Dropped unused 'bottom' bucket + removed the 'bottom50' branch from
  the desktop route
Backend:
- models/WeeklyRecap.js — archived snapshot of a finished week
  (top 10 + bottom 50 + full ranked list + per-student activity counts)
- services/weeklyRecap.js — finalizePreviousWeek() captures last week's
  leaders and assigns weekly badges; recoveryPlanFor(email) returns the
  AI Recovery Plan payload for any bottom-50 student
- services/weeklyRecapScheduler.js — every 5min, past Monday 06:00 IST,
  idempotently finalizes the previous week
- routes/recap.js — GET /api/weekly/recap?email returns the recap + the
  AI plan (only for bottom-50 students) + recapId for client dismissals

Frontend (client/src/components/weekly-recap/):
- WeeklyChampionsPopup — glass card, top-10 with rank + name + Weekly SP
  + Weekly Badge + Learning Consistency %; rank 1 gets a soft golden
  glow that pulses; "New Week Started" block with "Start My Week"
  primary button; localStorage dismissal keyed on recapId
- AIRecoveryCoachPopup — calm blue/green/purple palette; "Your AI
  Learning Coach" headline; supportive observations from prior week
  data (attendance %, poll %, challenge attempt); Mon–Sat plan with
  per-task check-off that persists in localStorage; "IF YOU FOLLOW
  THIS PLAN" estimated outcome panel (95% attendance, 100% poll,
  Top 30 rank); "Small improvements every day..." encouragement;
  "Start My Recovery Plan" + Dismiss buttons; no red anywhere
- useWeeklyRecapPopups hook — cascades Champions then Coach, only Coach
  for bottom-50 students, suppresses both if either is dismissed this week

Wired into WeeklyLeaderboardDesktop so the cascade fires on the
user's first dashboard visit after Monday 06:00 IST. End-to-end
verified via /api/weekly/recap returning a 10-row top10 + 50-row
bottom50 + per-student plan payload.
Backend (extends the existing recap):
- services/weeklyRecap.js:
  * deriveWeeklyGoal() selects one of three motivational buckets
    based on prior rank: close (11-25), average (26-cohort-50),
    bottom (50+) — each with bespoke copy, targets, and projected rank
  * goalFor(email) returns the goal payload for any student
  * liveProgressFor(email) returns this-week counts (attendance/poll/
    discussion/challenge) + attendance day-set + streak + weekly SP
- routes/recap.js:
  * GET /api/weekly/recap now returns {recap, plan, goal, progress,
    recapId} in one round-trip
  * GET /api/weekly/live is the lightweight poll endpoint the card
    uses to refresh progress every 60s

Frontend (client/src/components/weekly-recap/):
- WeeklyGoalCard.tsx + .css: premium glass card with three variants
  (close/average/bottom), each with bespoke gradient + glow color
  * Header: title emoji + headline + subhead (live "X ranks away
    from Top 10" copy for the close bucket)
  * TARGET THIS WEEK list — 4 items per bucket, all driven from
    server-side goal.targets
  * Three meta cards: ESTIMATED WEEKLY SP, PROJECTED RANK, YOUR PRIOR RANK
  * AI motivation block: re-evaluated on every progress tick
    (streak-based, completion-based, pace-based)
  * Live progress path: 4 nodes (attendance, polls, discussions,
    weekly challenge) with glowing animation on completion; filled
    connectors glow green when both adjacent nodes are done
  * Distance to Champions card — shows remaining work per category
  * AI Weekly Prediction card — projected rank + confidence + SP,
    derived from observed pace
  * Completion state: when all targets done, replaces the card with
    a calm "Weekly Mission Complete" panel (no confetti, elegant glow)
- Mounted above the 3-col body grid in WeeklyLeaderboardDesktop so it
  sits directly below the topbar per spec. Uses localStorage-style
  live polling at /api/weekly/live every 60s.

Build: 767 modules, 75 KB CSS / 929 KB JS.
Backend (server/services/levels.js):
- Replaces the old Bronze→Silver→Gold→Platinum→Diamond→Legend
  hierarchy with the new spec: 16 named ranks across 6 tiers
  (Bronze/Silver/Gold/Diamond/Heroic/Master), evenly distributed
  from 100 SP (starting) to 1500 SP (max)
- Adds rankFor(), nextRank(), decorated accessors
- Keeps legacy leagueBand() + levelFor() + legendBadge() + leaderboard
  helpers so other callers don't break

Frontend (new client/src/components/rank-system/):
- ranks.js — client-side mirror of the rank table (the client bundle
  can't cross the server boundary), with per-tier gradient/glow
  themes and per-rank descriptions
- BadgeArt.jsx — six original SVG emblems (one per tier): bronze
  shield, silver wings, gold crystal, diamond crystal, heroic crest
  with energy wings, master 8-point star with rotating rings. No
  Free Fire references — fully original geometry
- JourneyProgressTrack.jsx — the main experience: a horizontal
  track spanning 100→1500 SP, 16 milestone markers (one per rank),
  a continuously-running mini-character above the track that
  dashes + leaves speed trails when SP changes, hover tooltips
  revealing rank name + description, a centered "RANK PROMOTED!"
  panel that appears on rank-up with glow + pulse + rotation, and
  a current/next-rank footer with animated progress bar
- AchievementCelebration.jsx — bottom-right toast stack that
  appears on rank-up; auto-dismisses after 4.5s with a draining
  timer bar; user can dismiss manually with the × button
- RankJourney.jsx — orchestrator that ties it all together; listens
  for SP changes via props, fires the runner dash + queues the
  celebration toast on rank-up
- rank-system.css — full design system: runner bobbing animation,
  dashing animation, trail effects, milestone pulse, promotion
  pulse, toast slide-in

Wired into main.jsx: replaces the old "Level / Trophy League /
Legend Badge" LevelStatus tile with <RankJourney sp={student.totalSp} />

Build: 771 modules, 76.6 KB CSS / 937.9 KB JS.
The previous RankJourney used heavy framer-motion animations
(animateTransform SMIL, infinite keyframes, nested SVG defs) that
were triggering a runtime crash on render in some browsers. The
new build removes framer-motion entirely from the rank system and
inlines everything as plain CSS + simple inline SVGs.

Changes:
- RankJourney.jsx — now exports CurrentRankBadge + JourneyProgressTrack
  directly with no external imports beyond React + ranks.js
- Deleted BadgeArt.jsx + AchievementCelebration.jsx + old
  JourneyProgressTrack.jsx (the buggy ones)
- Removed the AchievementCelebration toast queueing logic
- All rank badges still render the same 6-tier visual identity
  (BronzeShield / SilverWings / GoldCrystal / DiamondCrystal /
  HeroicCrest / MasterEmblem) as plain SVG, no SMIL animations
- Track still has 16 milestones + runner character
- CurrentRankBadge hero + Next Rank footer preserved

Also added an ErrorBoundary around StudentView (StudentViewErrorBoundary)
that catches render errors and writes them to
localStorage.__spurti_last_error so future debugging is easy.

Build: 768 modules, 76.6 KB CSS / 932.9 KB JS.
The rankFor() and nextRank() helpers in ranks.js return plain rank
objects (no theme property). The previous safe build was reading
rank.theme.glow / .gradient / .accent directly, which crashed with
'Cannot read properties of undefined (reading glow)' because rank.theme
was undefined.

Fix: resolve the theme via TIER_THEME[rank.tier] in each consumer
(CurrentRankBadge, JourneyProgressTrack, MilestoneMarker) instead
of relying on a non-existent rank.theme shortcut. The data layer
stays pure (no theme coupling); the components handle the decoration.

No backend changes. Build: 768 modules, 76.6 KB CSS / 932.9 KB JS.
The MilestoneMarker was receiving theme={r.theme}, but r is a raw
rank from RANKS which only has { min, name, tier, idx } — no theme
property. So `theme` was undefined inside the marker, and accessing
`theme.gradient` on the milestone's completed-state fill threw
'Cannot read properties of undefined (reading gradient)'.

Fix: pass theme={TIER_THEME[r.tier]} instead so the marker always
receives a fully-resolved theme object.

No backend changes. Build: 768 modules, 76.6 KB CSS / 932.9 KB JS.
Two new sub-features built into the existing Weekly Champions popup
cascade so every student gets a personalized follow-up right after
the recap popups close:

1. Subtle distance message (DistanceMessage.jsx) — bottom-of-screen
   one-liner that auto-dismisses after 6 seconds. Pick the right copy
   based on the student's prior-week position:
   - ranks 1-10: "You were on the Top 10 leaderboard last week."
   - ranks 11-25: "You were only N ranks away from Top 10."
   - elsewhere: "You are N SP away from appearing on next week's
     Weekly Champions board."
   A separate "Fresh Start" variant fires for bottom-50 students after
   the AI Coach popup closes.

2. Weekly Goal Card (WeeklyGoalCard.jsx + .css) — full-width glass
   card that renders inline below the topbar (above the existing
   leaderboard table). Three variants picked server-side:
   - close    (rank 11-25)  🎯  "X ranks away from Top 10"
   - average  (rank 26-cohort-50) 🚀  "Keep Growing"
   - bottom   (bottom 50)   💙  "Fresh Start" (with Mon-Sat recovery plan)
   Card includes:
   - Hero with title + headline + sub
   - TARGET THIS WEEK checklist (4 server-driven targets per bucket)
   - 3 meta cards: Estimated SP / Projected Rank / Prior Rank
   - Live progress path (4 nodes with glowing fill animation)
   - AI motivation line that re-evaluates as targets are completed
   - Bottom-50 variant includes the Mon-Sat Recovery Plan checklist
   - Tap-to-tick progress persisted in localStorage so refresh doesn't
     reset state within the same week

Backend:
- routes/recap.js now derives the personalized goal from
  recap.allRanked (which stores `rank` per entry) and returns it in
  the recap response.

No external dependencies added; no framer-motion SMIL animations
that previously caused the white screen.

Build: 768 modules, 76.6 KB CSS / 935 KB JS.
The hero sub-text was assigned to a local `subhead` variable, but the
JSX still read `sub` — an undefined name. Renamed the JSX reference
to `subhead` to match the variable.

Also removed a stray `headline` reference (line 167) that was unused
in this version.

No backend changes. Build: 768 modules, 76.6 KB CSS / 935 KB JS.
Backend:
- routes/recap.js — derive and return a `case` field ('top10' |
  'close' | 'other' | 'bottom50') plus a `me` object that the
  Insights popup needs (weeklyRank, weeklySp, pointsToTop10,
  attendance/poll/challenge counts). The case is computed server
  side so the client just reads the result.

Frontend (client/src/components/weekly-recap/):
- WeeklyLearningInsightsPopup.jsx — premium centered modal that
  fires once per week after Monday 06:00 IST. Premium glass card
  (~40% desktop, 55-60% tablet, 90-95% mobile). Two-face flip card:
  FRONT shows the Top 10 last week with elegant glass rows
  (Rank, Name, Weekly SP, Weekly Badge, Learning Consistency %),
  Rank 1 highlighted with a soft golden pulse glow, plus the
  "A New Week Has Begun..." callout and a "Start My Week" button.
  BACK shows personalized AI insights that vary by case:
    top10  : "What Went Right" + "What Kept You Ahead in the Top 10
              Race" + "Keep this momentum going"
    close  : "What Went Right" + "Where You Lost Those Few Points"
              + "How You Could Have Reached the Top 10" + "You're
              closer than you think"
    other  : "What Went Right" + "Where You Can Improve This Week"
              + "Every expert was once a beginner"
  for top10 students, confetti + balloons + sparkles + party poppers
  burst on mount. The card auto-flips at 10s with a smooth 0.85s
  rotateY transition. Dismissal keyed on recapId (weekStart).
- RecoveryCoachPopup.jsx — full premium centered card shown for
  case === 'bottom50' (or anyone in the bottom 50). NEVER uses the
  words "Bottom 50". Calm sky/teal/green gradient (no red). Includes
  "What You Already Have" positive observations, the Mon–Sat
  Recovery Plan checklist, the Estimated Outcome cards
  (Attendance / Poll Completion / Spurti Points / Estimated Rank),
  the encouraging message ("💙 You Can Do It!"), and "Start My
  Recovery Plan" + "Dismiss" buttons. Auto-dismisses after 12s.
- WeeklyLearningInsightsPopup.css + RecoveryCoachPopup.css — premium
  styling, glassmorphism, soft blue/green/purple gradients,
  rounded corners (20-24px), blurred backgrounds, celebrations
  keyframes (wli-fall, wli-rise, wli-spark, wli-popper-burst),
  gold pulse animation for Rank 1.

Wired:
- useWeeklyRecapPopups hook in WeeklyLeaderboardDesktop orchestrates
  the cascade: Insights popup fires for everyone (gated by
  wli_dismissed_<recapId> localStorage flag); if the case is
  bottom50 and the Recovery popup hasn't been dismissed this week,
  it cascades 400ms after Insights closes. After both close, the
  dashboard renders normally.

Build: 768 modules, 76.6 KB CSS / 935 KB JS. No new deps.
- New SPTrendPanel (4x6 heatmap + SVG trend line + slope chip) wired to
  a new /api/weekly/sp-trend endpoint that aggregates SPTransaction data
  with no schema changes. Weakest cells below the category median open
  the RecoveryCoachPopup pre-focused on that day.
- Fix unescaped apostrophe in RecoveryCoachPopup.jsx that broke the prod
  build (string was using single quotes with a literal apostrophe).
- Mount /spurti/api/weekly/sp-trend in server.js so the path matches the
  /spurti prefix used by the SPA.
- README: add a summary section linking readers to FEATURES.md for the
  Monday-morning recap cascade (Champions -> Insights flip -> Coach).
- FEATURES.md: add Part 2 covering FreshWeekEmpty, WeeklyLeaderboardDesktop,
  WeeklyLearningInsightsPopup (10s flip), RecoveryCoachPopup, the 16-rank
  system, and SPTrendPanel with backend file map and architectural notes.
SPTrendPanel was created in the previous commit but never rendered
anywhere. Mount it as a new full-width 'SP Trend' panel section in the
StudentView, right after StudentPulse and before the inline weekly
leaderboard. Fetches /api/weekly/sp-trend and /api/weekly/recap on
mount, then passes the recap me data through so weakest-cell clicks
can open the RecoveryCoachPopup pre-focused on the matching weekday.

This is the missing wire that closes the loop:
  1. SPTrendPanel shows the 4x6 heatmap with weakest cells clickable
  2. Click a dim cell -> RecoveryCoachPopup opens with focusDay set
  3. The matching day row gets a one-shot pulse-glow + scrollIntoView

Build: 771 modules, +5.7 KB CSS, +9 KB JS.
The Insights and Recovery Coach popups were keyed on a per-week
localStorage flag (wli_dismissed_<recapId> / rcp_dismissed_<recapId>),
so once a student dismissed them they never reappeared for the rest of
the week — even on every page reload.

Add a \popupsAlwaysMode()\ helper that checks the URL for
\?popups=always\ (or \?popups=1\ / \?popups=true\). When set:
- wasInsightsDismissed / wasRecoveryCoachDismissed always return false
  so the cascade fires on every page open.
- markInsightsDismissed / markRecoveryCoachDismissed are no-ops so the
  flag is never persisted.

Production behavior (once-per-week dismissal) is preserved when the
query param is absent. This makes it trivial to preview the Monday-
morning cascade locally without waiting for Monday.
On localhost the Samagama auth server (port 5001) is not running, so
/api/me always returns {authenticated:false} and the dashboard never
mounts. Without the dashboard mounted, the WeeklyLeaderboardDesktop
component never renders, so the weekly recap popup cascade never
fires.

Add a guarded local-dev bypass in studentEmailFromRequest that activates
ONLY when SPURTI_DEV_AUTH=1 is set on the server:
- Accepts ?devEmail=<email> query param or x-dev-email header
- Resolves to the matching Student record
- Never active in production (env var must be explicitly set)

Client side: when ?devEmail=... is in the URL, attach x-dev-email to
the /api/me fetch so the dashboard bootstraps as that student.

Combined with ?popups=always, the full Monday-morning recap cascade is
now previewable end-to-end on localhost without waiting for Monday and
without the Samagama auth server running.
Two issues with the WeeklyLearningInsightsPopup:

1. The 'Got it - Start My Week' button on the back face of the card
   (rendered after the 10s auto-flip) had no onClick handler, so it
   didn't close the popup when clicked. Pass onClose through to the
   InsightsCard sub-component and wire it to the button.

2. The X close button was positioned at 'top: -52px' which placed it
   ABOVE the popup card, outside the visible area. Move it to
   'top: 14px; right: 14px' so it's visible inside the popup with
   a glassmorphism background that matches the design language.

The 'Skip to Dashboard' / 'Continue to Dashboard' button at the bottom
of the popup was already wired correctly with onClose.
…lize

When the recap scheduler finalizes the previous week (Mon 06:00 IST),
dispatch a personalized recovery email to every student in the bottom 50.
Uses the email field already on the Student record, so no separate
mailing-list table is needed.

mailer.js:
- sendRecoveryEmail({name, email, weekStart, rank, weeklySp, plan, recapId})
  composes a plain-text + HTML body with the student's name, last week's
  rank/SP, observations, Mon->Sat plan, and estimated outcomes.
- If SAMAGAMA_MAILER_URL is set, POSTs to it (the Samagama mailer
  endpoint). Otherwise logs the body to stdout in dry-run mode so local
  dev works without breaking.
- sendRecoveryEmailsToBottom50(recap) loops through recap.bottom50.

weeklyRecap.js:
- finalizePreviousWeek now calls sendRecoveryEmailsToBottom50 after the
  recap is upserted. Logs the sent/failed counts.

WeeklyRecap model:
- New fields recoveryEmailsSentAt, recoveryEmailsSentCount,
  recoveryEmailsFailedCount for idempotency. The scheduler only fires
  once per recap (the field is set after the first send).
Reverts 7 commits from feat/share-export:
- e5cebb3 docs: add PR template body for vicharanashala PR
- 9d44c01 feat: send weekly recovery emails to bottom-50 students
- 69556c0 fix: wire 'Got it' close button + move cross bar
- d5b05e2 feat: local-dev auth bypass (SPURTI_DEV_AUTH=1)
- b84ea7b feat: add ?popups=always bypass for weekly recap popups
- 45c0b0c feat: wire SPTrendPanel + RecoveryCoachPopup into StudentView
- 7630610 feat: add SP Trend panel + document weekly recap popup cascade

Restores the branch to a clean state so the work can be redone
following the step-by-step instructions instead.
Re-applies all 7 commits from the previous attempt by reverting the
revert commit. This restores:
- WeeklyLeaderboardDesktop (3-column shell, inline + full-page modes)
- WeeklyLearningInsightsPopup (auto-flip at 10s, across top10/close/other)
- RecoveryCoachPopup (bottom-50 only, calm AI recovery plan)
- WeeklyChampionsPopup + AIRecoveryCoachPopup (full-page equivalents)
- SPTrendPanel (4x6 heatmap + SVG trend line)
- 16-rank progression system (Bronze III -> Master)
- ?popups=always query param bypass for local dev
- SPURTI_DEV_AUTH=1 + ?devEmail= local auth bypass
- mailer.js with bottom-50 recovery email dispatch
- FEATURES.md Part 2 documenting the full cascade
- PR_VICHARANASHALA.md PR body template

Build verified: 771 modules, 86 KB CSS, 951 KB JS.
- main.jsx: conditional tabs for My Journey/Commitments behind eligibleForVibeGoals gate
- server.js: include Commitment model, vibe/standup/journey service imports alongside weekly recap routes
- Keep all popup-cascade features (SPTrend, RecoveryCoach, Insights, replays)
- Add placeholder stubs for MyJourney/Commitments components (overridden by main on merge)
…mails

Resolves conflicts and combines both feature sets:

Preserved from vicharanashala/main:
- MyJourney, Commitments, VibeGoals, StandupGoals components
- SurveyModal with poll2 support (generalized statusPath/completedKey)
- Two SurveyModal instances (survey + poll2)
- LevelStatus component

Added from popup-cascade branch:
- SPTrendPanel weekly trajectory section
- WeeklyLeaderboardDesktop inline leaderboard
- RecoveryCoachPopup recovery plan popup
- RankJourney rank visualization
- ReplaySection with weekly/final replay modals
- Dev auth bypass (?devEmail= + SPURTI_DEV_AUTH=1)
- StudentViewErrorBoundary
- Conditional tabs (journey/vibe behind eligibleForVibeGoals gate) + replays tab
- Weekly recap system (routes, services, scheduler, mailer)

Files with conflicts resolved: client/src/main.jsx, server/server.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant