Commit 419c18b
Release v1.0.1 (#333)
* 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>1 parent b0713f3 commit 419c18b
57 files changed
Lines changed: 4701 additions & 281 deletions
File tree
- frontend
- app
- [locale]/shop
- cart
- checkout/success
- api
- questions/[category]
- shop
- admin/orders/[id]/refund
- checkout
- internal
- monobank/janitor
- orders/restock-stale
- webhooks/monobank
- components
- header
- home
- db
- lib
- cache
- env
- logging
- psp
- security
- services/orders
- shop
- tests
- helpers
- q&a
- shop
- messages
- studio
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
579 | 579 | | |
580 | 580 | | |
581 | 581 | | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
58 | 79 | | |
59 | 80 | | |
60 | 81 | | |
61 | 82 | | |
62 | 83 | | |
63 | 84 | | |
64 | 85 | | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
65 | 94 | | |
66 | 95 | | |
67 | 96 | | |
68 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
69 | 112 | | |
70 | 113 | | |
71 | 114 | | |
| |||
78 | 121 | | |
79 | 122 | | |
80 | 123 | | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
81 | 141 | | |
82 | 142 | | |
83 | 143 | | |
| |||
92 | 152 | | |
93 | 153 | | |
94 | 154 | | |
| 155 | + | |
95 | 156 | | |
96 | 157 | | |
97 | 158 | | |
| |||
109 | 170 | | |
110 | 171 | | |
111 | 172 | | |
112 | | - | |
| 173 | + | |
113 | 174 | | |
114 | 175 | | |
115 | 176 | | |
116 | 177 | | |
117 | 178 | | |
118 | | - | |
| 179 | + | |
119 | 180 | | |
120 | 181 | | |
121 | 182 | | |
| |||
125 | 186 | | |
126 | 187 | | |
127 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
128 | 193 | | |
129 | 194 | | |
130 | 195 | | |
| |||
137 | 202 | | |
138 | 203 | | |
139 | 204 | | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
140 | 213 | | |
141 | 214 | | |
142 | 215 | | |
| |||
149 | 222 | | |
150 | 223 | | |
151 | 224 | | |
152 | | - | |
| 225 | + | |
153 | 226 | | |
154 | 227 | | |
155 | 228 | | |
| |||
385 | 458 | | |
386 | 459 | | |
387 | 460 | | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
388 | 519 | | |
389 | 520 | | |
390 | 521 | | |
391 | 522 | | |
392 | | - | |
| 523 | + | |
393 | 524 | | |
394 | 525 | | |
395 | 526 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
7 | 9 | | |
8 | 10 | | |
9 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
10 | 36 | | |
11 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
12 | 43 | | |
0 commit comments