Skip to content

(SP: 2) [Frontend] Quiz UX improvements: violations counter, breadcrumbs, status badges#320

Merged
ViktorSvertoka merged 18 commits intodevelopfrom
sl/feat/quiz
Feb 13, 2026
Merged

(SP: 2) [Frontend] Quiz UX improvements: violations counter, breadcrumbs, status badges#320
ViktorSvertoka merged 18 commits intodevelopfrom
sl/feat/quiz

Conversation

@LesiaUKR
Copy link
Collaborator

@LesiaUKR LesiaUKR commented Feb 13, 2026

Closes #312
Closes #321

Summary

  • Added violations counter UI with disqualification threshold
  • Fixed points mismatch between leaderboard and dashboard
  • Consistent status badges and mobile UX improvements
  • Added breadcrumbs to quiz review page for navigation context
  • Fixed "Recommendation" tautology in quiz question feedback (uk locale)
  • Import ordering and ESLint compliance fixes

Test plan

  • Quiz review page shows breadcrumb: Dashboard > Quiz Title
  • Breadcrumb Dashboard link navigates correctly across all locales
  • Violations counter displays correctly during quiz
  • Points match between dashboard and leaderboard
  • Status badges (mastered/needs review/study) render consistently
  • Mobile layout renders correctly
  • Dark mode colors verified

Summary by CodeRabbit

Release Notes

  • New Features

    • Added quiz results section to dashboard with status badges (mastered, needs review, study)
    • Added new interactive hero sections with flip-card Q&A and animated code snippets
    • Enhanced quiz review page with breadcrumb navigation
    • Added violations counter for quiz integrity tracking
    • Improved mobile touch interactions for term reordering and modal dragging
  • Improvements

    • Updated avatar rendering in profile cards with generated avatars
    • Enhanced quiz card display with dynamic status indicators
    • Improved layout responsiveness on mobile devices
    • Updated translations across multiple languages
  • Bug Fixes

    • Fixed violations threshold for quiz disqualification

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)
- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)
- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features
- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)
Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts
Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator
@vercel
Copy link
Contributor

vercel bot commented Feb 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devlovers-net Ready Ready Preview, Comment Feb 13, 2026 5:24pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive redesign of the home page with interactive hero sections (WelcomeHeroSection and FeaturesHeroSection) including animated components (FloatingCode, InteractiveConstellation, FlipCardQA), adds dashboard quiz results visualization with caching, implements a Monobank payment janitor service with internal API route and multiple reconciliation jobs, extends database schema with janitor claim tracking, expands i18n across three languages, and enhances various UI components with touch interactions and improved styling.

Changes

Cohort / File(s) Summary
Home Page Redesign
frontend/app/[locale]/page.tsx, frontend/components/home/WelcomeHeroSection.tsx, frontend/components/home/FeaturesHeroSection.tsx, frontend/components/home/WelcomeHeroBackground.tsx, frontend/components/home/FloatingCode.tsx, frontend/components/home/InteractiveConstellation.tsx, frontend/components/home/FlipCardQA.tsx, frontend/components/home/InteractiveCTAButton.tsx
Replaced HeroSection with new WelcomeHeroSection and FeaturesHeroSection components. Added interactive, animated components: FloatingCode (typing animations), InteractiveConstellation (particle canvas), and FlipCardQA (3D flip cards). Updated InteractiveCTAButton with motion-driven hover effects. Removed CodeCard, HeroCodeCards, and original HeroSection.
Dashboard Quiz Results
frontend/app/[locale]/dashboard/page.tsx, frontend/components/dashboard/QuizResultRow.tsx, frontend/components/dashboard/QuizResultsSection.tsx
Added QuizResultsSection to dashboard displaying user's quiz attempts with responsive layout, status badges, and mobile-friendly grid. Updated QuizResultRow with improved points rendering (plus/em-dash), mobile layout adjustments, and chevron visibility logic. Extended user profile data (id, image fields).
Profile & Avatar Updates
frontend/components/dashboard/ProfileCard.tsx
Extended ProfileCardProps with id and image fields. Replaced initials-based avatar with UserAvatar component using either provided image or generated Dicebear URL with seed-based consistency.
Quiz UI Enhancements
frontend/app/[locale]/quiz/[slug]/page.tsx, frontend/components/quiz/QuizCard.tsx, frontend/components/quiz/QuizContainer.tsx, frontend/components/quiz/QuizQuestion.tsx, frontend/components/quiz/QuizResult.tsx, frontend/components/quiz/ViolationsCounter.tsx
Added dynamic status badges to QuizCard (mastered/needsReview/study based on progress). Integrated ViolationsCounter into quiz header as sticky element. Added auto-scroll to Next button on result reveal. Increased violations threshold for banner/disqualification from >=3 to >=4. Improved categoryStyle guard logic.
Q&A Touch Interactions
frontend/components/q&a/AIWordHelper.tsx, frontend/components/q&a/AccordionList.tsx, frontend/components/q&a/FloatingExplainButton.tsx, frontend/components/q&a/SelectableText.tsx, frontend/components/dashboard/ExplainedTermsCard.tsx
Added comprehensive touch-drag support to AIWordHelper and ExplainedTermsCard for mobile reordering. Added FloatingExplainButton placement prop (above/below) with viewport-aware positioning. Improved SelectableText mobile positioning logic. Enhanced visual feedback during touch drag interactions.
Quiz Caching & Data
frontend/db/queries/quiz.ts, frontend/lib/quiz/quiz-answers-redis.ts
Refactored cached attempt review to include userId in key generation and retrieval. Updated getUserLastAttemptPerQuiz to compute pointsEarned from point_transactions via derived subquery instead of qa.pointsEarned. Reduced public exports to QuizAnswer, QuizQuestion, QuizQuestionWithAnswers. Added 48-hour TTL Redis caching for AttemptReview.
Monobank Janitor Service
frontend/app/api/shop/internal/monobank/janitor/route.ts, frontend/lib/services/orders/monobank-janitor.ts, frontend/lib/services/orders/monobank-events-claim.ts, frontend/lib/services/orders/monobank-webhook.ts
Introduced new internal API POST route with strict authentication, rate-limiting via database gates, and per-job execution branches (job1–job4). Implemented four janitor jobs: Job1 processes creating/active attempts, Job2 claims stale attempts with cancellation/restock, Job3 processes stored events in canonical order, Job4 generates needs-review reporting. Added claimNextMonobankEvent and applyStoredMonobankEvent workflows with restock finalization.
Shop Database Schema
frontend/db/schema/shop.ts, frontend/drizzle/0013_monobank_janitor_claim_attempts.sql, frontend/drizzle/meta/_journal.json
Added janitorClaimedUntil and janitorClaimedBy columns to payment_attempts table. Created payment_attempts_janitor_claim_idx index on (provider, status, janitorClaimedUntil, updatedAt). Updated migration journal with new entry.
Leaderboard & Header
frontend/components/leaderboard/LeaderboardClient.tsx, frontend/components/header/MainSwitcher.tsx
Replaced gradient utility classes with linear gradient variants using CSS variables. Added isLeaderboardPath helper to MainSwitcher layout decision, applying mx-auto layout when on leaderboard alongside other key paths.
Styling & Fonts
frontend/app/globals.css, frontend/app/layout.tsx, frontend/components/about/HeroSection.tsx
Added three new 3D transform utilities (.perspective-1000, .preserve-3d, .backface-hidden). Replaced next/font/google Geist imports with direct geist package imports. Updated LinkedIn followers default from 1.3k+ to 1.5k+.
i18n Translations
frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Expanded homepage translations with welcomeDescription, featuresHeading, featureBadges, featuresCta, and comprehensive flipCard UI/questions. Updated QA recommendation label to "Tip". Added quiz card statuses (mastered, needsReview, study). Extended dashboard with quizResults and quizReview blocks. Added antiCheat counter translations. Translations added for all three language files.
Monobank Janitor Tests
frontend/lib/tests/shop/monobank-events-claim.test.ts, frontend/lib/tests/shop/monobank-janitor-job1.test.ts, frontend/lib/tests/shop/monobank-janitor-job2.test.ts, frontend/lib/tests/shop/monobank-janitor-job3.test.ts, frontend/lib/tests/shop/monobank-janitor-job4-needs-review.test.ts, frontend/lib/tests/shop/monobank-janitor-route-g1.test.ts
Comprehensive test suites covering event claiming, all four janitor jobs (with success/failure paths, dry-run validation), rate-limiting, authentication, payload validation, and per-job response formatting. Tests validate state changes across orders, paymentAttempts, and monobankEvents tables.
Dependencies & Misc
frontend/package.json, frontend/instrumentation-client.ts, frontend/lib/about/stats.ts, frontend/components/ui/particle-canvas.tsx
Added @swc/helpers and geist dependencies. Exported onRouterTransitionStart from instrumentation-client. Changed LinkedIn follower default to 1500. Fixed EOL formatting in particle-canvas.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Browser Client
    participant Route as Janitor API Route
    participant DB as Database
    participant Job as Janitor Job Handler
    participant PSP as Payment Provider
    participant Webhook as Webhook Service

    Client->>Route: POST /api/shop/internal/monobank/janitor<br/>{job, dryRun, limit, secret}
    activate Route
    Route->>Route: Validate origin & auth secret
    Route->>Route: Parse & validate payload schema
    Route->>DB: acquireJobSlot (rate-limiting gate)
    alt Rate Limited
        DB-->>Route: Returns 429 with Retry-After
        Route-->>Client: 429 with retryAfterSeconds
    else Acquired
        DB-->>Route: Returns slot acquired
        alt Job1
            Route->>Job: runMonobankJanitorJob1(dryRun, limit)
            Job->>DB: Fetch creating/active attempts
            Job->>PSP: Check invoice status
            Job->>Webhook: Apply webhook events
            Webhook->>DB: Update order & attempt status
            Job-->>Route: {processed, applied, noop, failed}
        else Job3
            Route->>Job: runMonobankJanitorJob3(dryRun, limit)
            Job->>DB: Fetch stored events (canonical order)
            Job->>Webhook: Apply stored events
            Webhook->>DB: Update order/attempt, release lease
            Job-->>Route: {processed, applied, noop, failed}
        end
        Route-->>Client: 200 with job results {success, processed, applied, noop, failed, report}
    end
    deactivate Route
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

Possibly related PRs

Suggested labels

refactor, bug, backend

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐰 Whiskers twitching with delight,
A janitor hops through the night,
Quiz results shimmer, heroes soar,
Touch drags dance on mobile's floor,
Three tongues sing in harmony bright,
DevLovers blooms—what a sight!

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.98% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main user-facing improvements: violations counter, breadcrumbs, and status badges. It directly reflects the primary changes across multiple components and is specific enough for history scanning.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into develop

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sl/feat/quiz

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@LesiaUKR LesiaUKR changed the base branch from main to develop February 13, 2026 17:22
@ViktorSvertoka ViktorSvertoka merged commit dcd8c0f into develop Feb 13, 2026
8 checks passed
@ViktorSvertoka ViktorSvertoka deleted the sl/feat/quiz branch February 13, 2026 17:32
@LesiaUKR LesiaUKR restored the sl/feat/quiz branch February 13, 2026 21:54
ViktorSvertoka added a commit that referenced this pull request Feb 14, 2026
* feat(mobile): improve dashboard, leaderboard & AI helper UX for touch devices

  - Add touch drag support for AI helper modal and explained terms reorder
  - Position explain button below selected word on mobile
  - Show delete/restore buttons always visible on mobile (no hover)
  - Add user avatar to dashboard profile card (same as leaderboard)
  - Fix leaderboard page layout
  - Fix Tailwind v4 canonical class warnings

* Added touchcancel listener

* (SP: 2) [Frontend] Quiz results dashboard, review cache fix, UX improvements (#317)

* (SP: 3) [Backend] add internal janitor (jobs 1-4), claim/lease + runbook (G0-G6) (#318)

* (SP: 2) [Frontend] Redesign Home Hero & Add Features Section (#319)

* refactor(home): rename hero sections and add complete i18n support

- Rename LegacyHeroSection → WelcomeHeroSection
- Rename HeroSection → FeaturesHeroSection
- Add welcomeDescription translation key to eliminate duplication
- Translate all hardcoded text (headings, badges, CTAs)
- Improve Ukrainian/Polish translations for better readability
- Remove unused legacy components and images

* feat(about): update LinkedIn follower count to reflect current stat (1.5k+)

* refactor(home): implement i18n for FlipCardQA & fix memory leaks

* fix(home): resolve rotateY conflict & scope keyboard events in FlipCardQA

* fix(home): resolve all issues

* chore(home): cleanup comments, remove dead code & fix trailing spaces

* (SP: 2) [Frontend] Quiz UX improvements: violations counter, breadcrumbs, status badges (#320)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* Header UX polish, quiz highlight fix, Blog button styling, shop i18n product    descriptions (#322)

* Header UX: reorder languages, swap controls, fix quiz highlight, style Blog button

* shop i18n product descriptions

* (SP: 1) [Frontend] Q&A: Next.js tab states + faster loader start (#324)

* fix(qa): align Next.js tab states and speed up loader startup

* feat(home,qa): improve home snap flow and add configurable Q&A page size

* fix(i18n,qa,seed): address review issues for locale handling and pagination state

* (SP: 1) [Frontend] Align quiz result messages with status badges, fix locale switch on result page (#325)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* fix(quiz): align result messages with status badges, persist result on locale switch

* chore(release): v1.0.0

---------

Co-authored-by: tetiana zorii <tanyusha.zoriy@gmail.com>
Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com>
Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com>
Co-authored-by: Yevhenii Datsenko <134847096+yevheniidatsenko@users.noreply.github.com>
Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com>
ViktorSvertoka added a commit that referenced this pull request Feb 14, 2026
* feat(mobile): improve dashboard, leaderboard & AI helper UX for touch devices

  - Add touch drag support for AI helper modal and explained terms reorder
  - Position explain button below selected word on mobile
  - Show delete/restore buttons always visible on mobile (no hover)
  - Add user avatar to dashboard profile card (same as leaderboard)
  - Fix leaderboard page layout
  - Fix Tailwind v4 canonical class warnings

* Added touchcancel listener

* (SP: 2) [Frontend] Quiz results dashboard, review cache fix, UX improvements (#317)

* (SP: 3) [Backend] add internal janitor (jobs 1-4), claim/lease + runbook (G0-G6) (#318)

* (SP: 2) [Frontend] Redesign Home Hero & Add Features Section (#319)

* refactor(home): rename hero sections and add complete i18n support

- Rename LegacyHeroSection → WelcomeHeroSection
- Rename HeroSection → FeaturesHeroSection
- Add welcomeDescription translation key to eliminate duplication
- Translate all hardcoded text (headings, badges, CTAs)
- Improve Ukrainian/Polish translations for better readability
- Remove unused legacy components and images

* feat(about): update LinkedIn follower count to reflect current stat (1.5k+)

* refactor(home): implement i18n for FlipCardQA & fix memory leaks

* fix(home): resolve rotateY conflict & scope keyboard events in FlipCardQA

* fix(home): resolve all issues

* chore(home): cleanup comments, remove dead code & fix trailing spaces

* (SP: 2) [Frontend] Quiz UX improvements: violations counter, breadcrumbs, status badges (#320)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* Header UX polish, quiz highlight fix, Blog button styling, shop i18n product    descriptions (#322)

* Header UX: reorder languages, swap controls, fix quiz highlight, style Blog button

* shop i18n product descriptions

* (SP: 1) [Frontend] Q&A: Next.js tab states + faster loader start (#324)

* fix(qa): align Next.js tab states and speed up loader startup

* feat(home,qa): improve home snap flow and add configurable Q&A page size

* fix(i18n,qa,seed): address review issues for locale handling and pagination state

* (SP: 1) [Frontend] Align quiz result messages with status badges, fix locale switch on result page (#325)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* fix(quiz): align result messages with status badges, persist result on locale switch

* chore(release): v1.0.0

* feat(jpg): add images for shop

---------

Co-authored-by: tetiana zorii <tanyusha.zoriy@gmail.com>
Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com>
Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com>
Co-authored-by: Yevhenii Datsenko <134847096+yevheniidatsenko@users.noreply.github.com>
Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com>
ViktorSvertoka added a commit that referenced this pull request Feb 15, 2026
* feat(mobile): improve dashboard, leaderboard & AI helper UX for touch devices

  - Add touch drag support for AI helper modal and explained terms reorder
  - Position explain button below selected word on mobile
  - Show delete/restore buttons always visible on mobile (no hover)
  - Add user avatar to dashboard profile card (same as leaderboard)
  - Fix leaderboard page layout
  - Fix Tailwind v4 canonical class warnings

* Added touchcancel listener

* (SP: 2) [Frontend] Quiz results dashboard, review cache fix, UX improvements (#317)

* (SP: 3) [Backend] add internal janitor (jobs 1-4), claim/lease + runbook (G0-G6) (#318)

* (SP: 2) [Frontend] Redesign Home Hero & Add Features Section (#319)

* refactor(home): rename hero sections and add complete i18n support

- Rename LegacyHeroSection → WelcomeHeroSection
- Rename HeroSection → FeaturesHeroSection
- Add welcomeDescription translation key to eliminate duplication
- Translate all hardcoded text (headings, badges, CTAs)
- Improve Ukrainian/Polish translations for better readability
- Remove unused legacy components and images

* feat(about): update LinkedIn follower count to reflect current stat (1.5k+)

* refactor(home): implement i18n for FlipCardQA & fix memory leaks

* fix(home): resolve rotateY conflict & scope keyboard events in FlipCardQA

* fix(home): resolve all issues

* chore(home): cleanup comments, remove dead code & fix trailing spaces

* (SP: 2) [Frontend] Quiz UX improvements: violations counter, breadcrumbs, status badges (#320)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* Header UX polish, quiz highlight fix, Blog button styling, shop i18n product    descriptions (#322)

* Header UX: reorder languages, swap controls, fix quiz highlight, style Blog button

* shop i18n product descriptions

* (SP: 1) [Frontend] Q&A: Next.js tab states + faster loader start (#324)

* fix(qa): align Next.js tab states and speed up loader startup

* feat(home,qa): improve home snap flow and add configurable Q&A page size

* fix(i18n,qa,seed): address review issues for locale handling and pagination state

* (SP: 1) [Frontend] Align quiz result messages with status badges, fix locale switch on result page (#325)

* feat(quiz): add guest warning before start and bot protection

Guest warning: show login/signup/continue buttons for unauthenticated
users on quiz rules screen before starting.

Bot protection: multi-attempt verification via Redis - each question
can only be verified once per user per attempt. Keys use dynamic TTL
matching quiz time limit and are cleared on retake.

Additional fixes:
- Footer flash on quiz navigation (added loading.tsx, eliminated redirect)
- Renamed QaLoader to Loader for reuse across pages
- React compiler purity errors (crypto.getRandomValues in handlers)
- Start button disabled after retake (isStarting not reset)

* refactor(quiz): PR review feedback

- Extract shared resolveRequestIdentifier() helper to eliminate
  duplicated auth/IP resolution logic in route.ts and actions/quiz.ts
- Return null instead of 'unknown' when identifier unresolvable,
  skip verification tracking for unidentifiable users
- Cap Redis TTL with MAX_TTL (3600s) to prevent client-supplied
  timeLimitSeconds from persisting keys indefinitely
- Add locale prefix to returnTo paths in guest warning links
- Replace nested Button inside Link with styled Link to fix
  invalid HTML (interactive element nesting)

* fix(quiz): fall through to IP when auth cookie is expired/invalid

* feat(quiz): add quiz results dashboard and review page

- Add quiz history section to dashboard with last attempt per quiz
- Add review page showing incorrect questions with explanations
- Add collapsible cards with expand/collapse all toggle
- Add "Review Mistakes" button on quiz result screen
- Add category icons to quiz page and review page headers
- Add BookOpen icon to explanation block in QuizQuestion
- Update guest message to mention error review benefit
- Add i18n translations (en/uk/pl) for all new features

* fix(quiz): scroll to next button on answer reveal, scope review cache by userId

* fix(quiz): restore type imports and userId cache key after merge conflict

* fix: restore type imports, sync @swc/helpers, fix indentation after merge

* feat(quiz): add violations counter UI, fix disqualification threshold

- Add ViolationsCounter component with color escalation (green/yellow/red)
- Sticky top bar keeps counter visible on scroll (mobile/tablet)
- Add i18n counter keys for en/uk/pl with ICU plural forms
- Fix threshold bug: violations warning now triggers at 4+ (was 3+)
  to match actual integrity score calculation (100 - violations * 10 < 70)

* fix(quiz): fix points mismatch between leaderboard and dashboard

Dashboard showed raw pointsEarned from last quiz_attempt, while
leaderboard summed improvement deltas from point_transactions.
Additionally, orphaned transactions from re-seeded quizzes inflated
leaderboard totals (12 rows, 83 ghost points cleaned up in DB).

- Dashboard query now joins point_transactions to show actual awarded
  points per quiz instead of raw attempt score
- Leaderboard query filters out orphaned transactions where the
  source attempt no longer exists in quiz_attempts

* OBfix(quiz): fix points mismatch, consistent status badges, mobile UX

Dashboard showed raw pointsEarned from last attempt while leaderboard
summed improvement deltas from point_transactions. Orphaned transactions
from re-seeded quizzes inflated leaderboard totals (cleaned up in DB).

- Dashboard query joins point_transactions for actual awarded points
- Leaderboard query filters orphaned transactions (source_id not in quiz_attempts)
- Quiz cards use 3-level badges (Mastered/Review/Study) matching dashboard
- Mobile quiz results show dash for zero points, added chevron indicator

* fix(quiz): add breadcrumbs to review page, fix recommendation tautology

* fix(quiz): align result messages with status badges, persist result on locale switch

* chore(release): v1.0.0

* feat(jpg): add images for shop

* (SP: 3) [Shop][Monobank] Janitor map + internal janitor endpoint stub + status UX + security/obs + J test gate (#328)

* (SP: 3) [Backend] add internal janitor (jobs 1-4), claim/lease + runbook (G0-G6)

* (SP: 3) [Backend] add provider selector, fix payments gating, i18n checkout errors

* Add shop category images to public

* (SP: 3) [Shop][Monobank] I1 structured logging: codes + logging safety checks

* (SP: 3) [Shop][Monobank] Fail-closed non-browser origin posture for webhook + janitor (ORIGIN_BLOCKED)

* (SP: 3) [Shop][Monobank] [Shop][Monobank] J gate: add orders status ownership test and pass all pre-prod invariants

* (SP: 3) [Shop][Monobank]  review fixes (tests, logging, success UI)

* (SP: 1) [Shop][Monobank] Tighten webhook log-code typing; harden DB tests; minor security/log/UI cleanups

* (SP: 1) [Shop][Monobank] harden Monobank webhook (origin/PII-safe logs) and remove duplicate sha256 hashing

* (SP:2) [Frontend] Fix duplicated Q&A items after content updates (#330)

* fix(qa): prevent duplicate questions and improve cache invalidation

* fix(qa): keep pagination totals consistent after deduplication

* (SP: 1) [Frontend] Integrate online users counter popup and fix header (#331)

* feat(home): add online users counter + fix header breakpoint

* deleted scrollY in OnlineCounterPopup

* fixed fetch in OnlineCounterPopup

* Bug/fix qa (#332)

* fix(qa): prevent duplicate questions and improve cache invalidation

* fix(qa): keep pagination totals consistent after deduplication

* fix(qa): paginate by unique questions and bump cache namespace

* chore(release): v1.0.1

---------

Co-authored-by: tetiana zorii <tanyusha.zoriy@gmail.com>
Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com>
Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com>
Co-authored-by: Yevhenii Datsenko <134847096+yevheniidatsenko@users.noreply.github.com>
Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com>
Co-authored-by: Yuliia Nazymko <122815071+YNazymko12@users.noreply.github.com>
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.

2 participants