Conversation
…istence + async label workflow (#364)
…tics cleanup (#367) * perf(vercel): cut runtime costs via notification, blog cache, and analytics changes * perf(blog): remove server searchParams usage to preserve ISR
… to client-side (#370) * refactor(frontend): remove locale layout dynamic auth and move header auth client-side * fix(frontend): prevent stale auth responses in useAuth and remove redundant dashboard dynamic layout
…abs (#372) * refactor(frontend): remove locale layout dynamic auth and move header auth client-side * fix(frontend): prevent stale auth responses in useAuth and remove redundant dashboard dynamic layout * feat(frontend): sync auth state across tabs via BroadcastChannel
…tars cache (#371) * perf(quiz-flow): move quiz progress to client-side fetch, enable ISR for quizzes page - Move user progress fetch from SSR to client-side API (/api/quiz/progress) - Remove force-dynamic and getCurrentUser() from quizzes page - Add revalidate=300 for ISR caching - Use window.history.replaceState for tab URL sync (avoid Next.js navigation) - Add forceMount to TabsContent to prevent layout shift on tab switch - Fix nested <main> — use <section> inside DynamicGridBackground - Cache GitHub stars count in sessionStorage to avoid refetch + re-animation * perf: replace useRef with useState lazy initializer in GitHubStarButton Fixes React 19 react-hooks/refs ESLint error — useRef.current cannot be read during render. Uses useState(getStoredStars) to capture the sessionStorage value once on mount instead. * fix: stop star icon trembling on hover in GitHubStarButton
…zes page (#373) * perf(quiz-flow): move quiz progress to client-side fetch, enable ISR for quizzes page - Move user progress fetch from SSR to client-side API (/api/quiz/progress) - Remove force-dynamic and getCurrentUser() from quizzes page - Add revalidate=300 for ISR caching - Use window.history.replaceState for tab URL sync (avoid Next.js navigation) - Add forceMount to TabsContent to prevent layout shift on tab switch - Fix nested <main> — use <section> inside DynamicGridBackground - Cache GitHub stars count in sessionStorage to avoid refetch + re-animation * perf: replace useRef with useState lazy initializer in GitHubStarButton Fixes React 19 react-hooks/refs ESLint error — useRef.current cannot be read during render. Uses useState(getStoredStars) to capture the sessionStorage value once on mount instead. * fix: stop star icon trembling on hover in GitHubStarButton * fix: eliminate quiz timer flash on language switch Remove Suspense boundary (loading.tsx) that unmounted QuizContainer during locale navigation. Synchronous session restore via useReducer lazy initializer and correct timer initialization via useState lazy initializer prevent any visible state reset on language switch * fix: replace quiz card layout shift with skeleton grid during progress load
…out polling + add sweep indexes (#375) * (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: 1) [Cart] adding route for user orders to cart page * (SP: 1) [Cart] fix after review cart mpage and adding index for orders * (SP: 1) [Cart] Fix cart orders summary auth rendering and return totalCount for orders badge * (SP: 1) [Cart] remove console.warn from CartPageClient to satisfy monobank logging safety invariant, namespace localStorage cart by user and reset on auth change * (SP: 1) [Cart] rehydrate per cartOwnerId (remove didHydrate coupling) * (SP: 2)[Backend] shop/shipping schema migrations foundation * (SP: 2)[Backend] shop/shipping public routes + np cache + sync * (SP: 2)[Backend] shop/shipping: shipping persistence + currency policy * (SP: 2)[Backend] shop/shipping: webhook apply + psp fields + enqueue shipping * (SP: 2)[Backend] shop/shipping: shipments worker + internal run + np mock * (SP: 2)[Backend] shop/shipping: admin+ui shipping actions * (SP: 2)[Backend] shop/shipping: retention + log sanitizer + metrics * (SP: 1)[Backend] stabilize Monobank janitor (job1/job3) and fix failing apply-outcomes tests * (SP: 1) [db]: add shop shipping core migration * (SP: 1) [FIX] resolve merge artifacts in order details page * (SP: 1) [FIX] apply post-review fixes for shipping and admin flows * (SP: 1) [FIX] align cart shipping imports (localeToCountry + availability reason code) * (SP: 1) [FIX] hard-block checkout when shipping disabled + i18n reason mapping * (SP: 1) [FIX] harden webhook enqueue + shipping worker + NP catalog + cart fail-closed * (SP: 1) [FIX] Initialize shippingMethodsLoading to true to avoid premature checkout. * (SP: 1) [FIX] migration 17 * (SP: 1) [DB] migrarion to testind DB and adjusting tests * (SP: 1)[DB] slow down restock janitor + enforce prod interval floor * (SP: 1) [DB] add order status lite view (opt-in) + instrumentation * (SP: 1) [DB] replace checkout success router.refresh polling with backoff API polling * (SP: 1) [DB] throttle sessions activity heartbeat + use count(*) (PK invariant) * (SP: 1)[DB] enforce production min intervals for internal shipping jobs * (SP: 1) [DB] add minimal partial indexes for orders sweeps + rollout notes * (SP: 1) [DB] refactor sweep claim step to FOR UPDATE SKIP LOCKED batching * (SP: 1)[DB]: slow janitor schedule to every 30 minutes * (SP: 1)[DB] increase polling delays for MonobankRedirectStatus * (SP: 1)[FIX] harden webhooks + fix SSR hydration + janitor/np gates + sweeps refactor * (SP: 1)[FIX] harden shipping enqueue gating + apply NP interval floor
… notifications, consent, returns) (#378) * (SP:3)[SHOP] add canonical payment/shipping/admin audit tables + dedupe helper with flagged atomic dual-write * (SP: 2)[SHOP] add INTL quote flow (request/offer/accept/decline), payment-init gate, and quote expiry/timeout sweeps * (SP: 3)[SHOP] introduce outbox-driven notifications with projector + worker (phase 3) * (SP: 3)[SHOP] add minimal returns/RMA lifecycle with atomic audit + canonical events (phase 4) * (SP: 3)[SHOP] enforce guest status-token lite-only access and audit token usage (phase 5) * (SP: 3)[SHOP] centralize transition guards and enforce across admin/webhook/worker flows (phase 6) :wq n * (SP:3)[SHOP]: enforce DATABASE_URL_LOCAL preflight + deterministic vitest config * (SP:3)[SHOP]: require canonical events in prod (fail-fast) * (SP:3)[SHOP]: implement notifications transport with retries + DLQ * (SP:3)[SHOP]: persist checkout legal consent artifact * (SP:1)[SHOP] add migration 0025 for consent + events + audit + prices * (SP:1)[SHOP] emit shipping_events for shipment worker transitions * (SP:2)[SHOP] audit admin product mutations (deduped) * (SP:2)[SHOP] make Monobank webhook retryable on transient apply failures * (SP:3) [SHOP] enforce guest status-token scopes across order actions * (SP:1) [SHOP] make product_prices the only write authority * (SP:1) [SHOP] add Playwright e2e smoke suite (local DB only) * (SP:3) [SHOP] explicitly reject exchanges (EXCHANGES_NOT_SUPPORTED) * (SP: 3)[FIX] harden audit + workers/tests; fix transitions/restock + webhook perf * (SP: 3)[FIX] harden local-db test safety and tighten shop reliability guards * (SP: 3)[FIX] fail-closed admin audit, refine shipments-worker outcomes/metrics, tighten quote+tests * (SP: 1)[FIX] harden shipments-worker claiming/leases and make audit+quote/test paths resilient * (SP: 1)[FIX] harden quote request errors/logging and sanitize requestId; document best-effort delete audit
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughThis PR consists primarily of formatting, whitespace, and structural refactoring across the frontend codebase. Key functional changes include adding error-handling cleanup for order shipping snapshots, introducing shipping status transition helper functions, consolidating duplicate lite response logic, and enhancing the ActivityHeatmapCard with outside-click listeners. The majority of changes are cosmetic. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
frontend/lib/services/products/mutations/create.ts (1)
27-30: Formatting change looks good; consider improving type safety.The multi-line formatting improves readability. However, line 29 uses
(input as any)twice, which bypasses TypeScript's type checking. Consider properly typing theProductInputinterface to includeslug?andtitleproperties so you can access them without casting toany.♻️ Optional type-safe refactor
If
ProductInputproperly declares these properties, you can remove the casts:const slug = await normalizeSlug( executor, - (input as any).slug ?? (input as any).title + input.slug ?? input.title );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/lib/services/products/mutations/create.ts` around lines 27 - 30, The code uses (input as any) twice which loses TypeScript safety; define or update the ProductInput type to include slug?: string and title: string, change the function signature to accept input: ProductInput (where this code runs), and then replace the casts with a direct access normalizeSlug(executor, input.slug ?? input.title); ensure any other uses of input in this file conform to ProductInput so the unsafe casts can be removed.frontend/lib/services/orders/checkout.ts (1)
1094-1130: Avoid duplicated cleanup/logging in the nested shipping snapshot catch.The new inner
catchduplicates compensating delete and then rethrows into the outercatch, which repeats cleanup/logging again.♻️ Proposed simplification (single cleanup path)
if (preparedShipping.required && preparedShipping.snapshot) { - try { - await ensureOrderShippingSnapshot({ - orderId: created.id, - snapshot: preparedShipping.snapshot, - }); - } catch (e) { - // Neon HTTP: no interactive transactions. Do compensating cleanup. - logError( - `[createOrderWithItems] orderShipping snapshot insert failed orderId=${created.id}`, - e - ); - try { - await db.delete(orders).where(eq(orders.id, created.id)); - } catch (cleanupErr) { - logError( - `[createOrderWithItems] cleanup delete failed orderId=${created.id}`, - cleanupErr - ); - } - throw e; - } + await ensureOrderShippingSnapshot({ + orderId: created.id, + snapshot: preparedShipping.snapshot, + }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/lib/services/orders/checkout.ts` around lines 1094 - 1130, The inner catch inside createOrderWithItems around ensureOrderShippingSnapshot duplicates the compensating cleanup and logging that's already performed by the outer catch; remove the duplicated db.delete(orders).where(eq(orders.id, created.id)) and its cleanup log from the inner catch and instead either just log the specific shipping snapshot error via logError(`[createOrderWithItems] orderShipping snapshot insert failed orderId=${created.id}`, e) and rethrow the original error, or simply rethrow e so the outer catch performs the single cleanup path; keep ensureOrderShippingSnapshot, created.id, db.delete, orders and logError references intact.frontend/lib/tests/shop/intl-quote-domain-phase2.test.ts (1)
1-465: PR title "Hot fix" doesn't match cosmetic changes.This file contains only formatting changes with no functional modifications to the test logic, assertions, or behavior. The PR title "Hot fix" typically implies a critical bug fix, but no bugs are being addressed here.
Consider updating the PR title to accurately reflect the nature of these changes (e.g., "refactor: formatting improvements" or "chore: code formatting").
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/lib/tests/shop/intl-quote-domain-phase2.test.ts` around lines 1 - 465, The PR title "Hot fix" is misleading because the changes in intl-quote-domain-phase2.test.ts are purely cosmetic/formatting (no logic or assertions changed); update the pull request title and description to accurately reflect this (e.g., "chore: format intl quote domain tests" or "refactor: formatting only") and mention that tests under describe.sequential('intl quote domain (phase 2)') were only reformatted, so reviewers know no functional change was made.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/components/dashboard/ActivityHeatmapCard.tsx`:
- Line 213: The forEach callback is returning the result of monthRowMap.set(...)
which triggers the useIterableCallbackReturn lint error; change the arrow
callback to have a void/block body so it doesn't return a value — e.g., replace
monthsData.forEach((m, i) => monthRowMap.set(`${m.year}-${m.month}`, i)) with a
block-style callback that calls monthRowMap.set(`${m.year}-${m.month}`, i); (no
return) to silence the lint error.
---
Nitpick comments:
In `@frontend/lib/services/orders/checkout.ts`:
- Around line 1094-1130: The inner catch inside createOrderWithItems around
ensureOrderShippingSnapshot duplicates the compensating cleanup and logging
that's already performed by the outer catch; remove the duplicated
db.delete(orders).where(eq(orders.id, created.id)) and its cleanup log from the
inner catch and instead either just log the specific shipping snapshot error via
logError(`[createOrderWithItems] orderShipping snapshot insert failed
orderId=${created.id}`, e) and rethrow the original error, or simply rethrow e
so the outer catch performs the single cleanup path; keep
ensureOrderShippingSnapshot, created.id, db.delete, orders and logError
references intact.
In `@frontend/lib/services/products/mutations/create.ts`:
- Around line 27-30: The code uses (input as any) twice which loses TypeScript
safety; define or update the ProductInput type to include slug?: string and
title: string, change the function signature to accept input: ProductInput
(where this code runs), and then replace the casts with a direct access
normalizeSlug(executor, input.slug ?? input.title); ensure any other uses of
input in this file conform to ProductInput so the unsafe casts can be removed.
In `@frontend/lib/tests/shop/intl-quote-domain-phase2.test.ts`:
- Around line 1-465: The PR title "Hot fix" is misleading because the changes in
intl-quote-domain-phase2.test.ts are purely cosmetic/formatting (no logic or
assertions changed); update the pull request title and description to accurately
reflect this (e.g., "chore: format intl quote domain tests" or "refactor:
formatting only") and mention that tests under describe.sequential('intl quote
domain (phase 2)') were only reformatted, so reviewers know no functional change
was made.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (101)
frontend/actions/notifications.tsfrontend/actions/profile.tsfrontend/app/[locale]/admin/shop/orders/[id]/ShippingActions.tsxfrontend/app/[locale]/dashboard/page.tsxfrontend/app/[locale]/quizzes/page.tsxfrontend/app/api/quiz/progress/route.tsfrontend/app/api/shop/admin/orders/[id]/quote/offer/route.tsfrontend/app/api/shop/admin/orders/[id]/shipping/route.tsfrontend/app/api/shop/internal/shipping/shipments/run/route.tsfrontend/app/api/shop/orders/[id]/quote/accept/route.tsfrontend/app/api/shop/orders/[id]/quote/decline/route.tsfrontend/app/api/shop/orders/[id]/quote/request/route.tsfrontend/app/api/shop/orders/[id]/returns/route.tsfrontend/app/api/shop/orders/[id]/status/route.tsfrontend/app/api/shop/shipping/methods/route.tsfrontend/app/api/shop/shipping/np/cities/route.tsfrontend/app/api/shop/shipping/np/warehouses/route.tsfrontend/app/globals.cssfrontend/components/admin/quiz/QuestionEditor.tsxfrontend/components/auth/logoutButton.tsxfrontend/components/dashboard/AchievementsSection.tsxfrontend/components/dashboard/ActivityHeatmapCard.tsxfrontend/components/dashboard/ExplainedTermsCard.tsxfrontend/components/dashboard/ProfileCard.tsxfrontend/components/dashboard/QuizResultRow.tsxfrontend/components/dashboard/QuizResultsSection.tsxfrontend/components/dashboard/StatsCard.tsxfrontend/components/header/AppMobileMenu.tsxfrontend/components/header/UserNavDropdown.tsxfrontend/components/home/FloatingCode.tsxfrontend/components/home/InteractiveCTAButton.tsxfrontend/components/quiz/CountdownTimer.tsxfrontend/components/quiz/QuizContainer.tsxfrontend/components/quiz/QuizzesSection.tsxfrontend/components/shared/GitHubStarButton.tsxfrontend/components/shared/LanguageSwitcher.tsxfrontend/components/shop/header/CartButton.tsxfrontend/components/theme/ThemeToggle.tsxfrontend/db/queries/shop/admin-orders.tsfrontend/db/schema/notifications.tsfrontend/db/schema/shop.tsfrontend/drizzle/meta/0016_snapshot.jsonfrontend/drizzle/meta/0017_snapshot.jsonfrontend/drizzle/meta/0018_snapshot.jsonfrontend/drizzle/meta/0019_snapshot.jsonfrontend/drizzle/meta/0020_snapshot.jsonfrontend/drizzle/meta/0021_snapshot.jsonfrontend/drizzle/meta/0022_snapshot.jsonfrontend/drizzle/meta/0023_snapshot.jsonfrontend/drizzle/meta/0024_snapshot.jsonfrontend/drizzle/meta/0025_snapshot.jsonfrontend/drizzle/meta/0026_snapshot.jsonfrontend/drizzle/meta/_journal.jsonfrontend/hooks/useQuizSession.tsfrontend/lib/achievements.tsfrontend/lib/env/monobank.tsfrontend/lib/env/nova-poshta.tsfrontend/lib/env/shop-canonical-events.tsfrontend/lib/env/shop-intl.tsfrontend/lib/quiz/quiz-answers-redis.tsfrontend/lib/services/orders/checkout.tsfrontend/lib/services/orders/monobank-webhook.tsfrontend/lib/services/orders/restock.tsfrontend/lib/services/products/mutations/create.tsfrontend/lib/services/shop/notifications/outbox-worker.tsfrontend/lib/services/shop/notifications/projector.tsfrontend/lib/services/shop/notifications/templates.tsfrontend/lib/services/shop/quotes.tsfrontend/lib/services/shop/returns.tsfrontend/lib/services/shop/shipping/admin-actions.tsfrontend/lib/services/shop/shipping/shipments-worker.tsfrontend/lib/services/shop/transitions/order-state.tsfrontend/lib/services/shop/transitions/return-state.tsfrontend/lib/services/shop/transitions/shipping-state.tsfrontend/lib/tests/helpers/db-safety.tsfrontend/lib/tests/helpers/seed-product.tsfrontend/lib/tests/shop/admin-product-canonical-audit-phase5.test.tsfrontend/lib/tests/shop/admin-product-create-atomic-phasec.test.tsfrontend/lib/tests/shop/checkout-legal-consent-phase4.test.tsfrontend/lib/tests/shop/checkout-shipping-phase3.test.tsfrontend/lib/tests/shop/intl-quote-domain-phase2.test.tsfrontend/lib/tests/shop/monobank-webhook-apply-outcomes.test.tsfrontend/lib/tests/shop/monobank-webhook-retry-classifier.test.tsfrontend/lib/tests/shop/notifications-projector-phase3.test.tsfrontend/lib/tests/shop/notifications-worker-phase3.test.tsfrontend/lib/tests/shop/notifications-worker-transport-phase3.test.tsfrontend/lib/tests/shop/nova-poshta-client-network-failure.test.tsfrontend/lib/tests/shop/order-payment-init-intl-gate-phase2.test.tsfrontend/lib/tests/shop/order-payment-init-token-scope-phase7.test.tsfrontend/lib/tests/shop/order-status-token.test.tsfrontend/lib/tests/shop/orders-status-ownership.test.tsfrontend/lib/tests/shop/returns-route-phase4.test.tsfrontend/lib/tests/shop/shipping-internal-retention-route-phase7.test.tsfrontend/lib/tests/shop/shipping-np-cities-route-p2.test.tsfrontend/lib/tests/shop/shipping-np-warehouses-route-p2.test.tsfrontend/lib/tests/shop/shipping-shipments-worker-phase5.test.tsfrontend/lib/tests/shop/stripe-webhook-psp-fields.test.tsfrontend/lib/tests/shop/transition-matrix-phase6.test.tsfrontend/lib/user-stats.tsfrontend/lib/validation/shop.tsfrontend/tests/e2e/shop-minimal-phase9.spec.ts
💤 Files with no reviewable changes (4)
- frontend/components/quiz/CountdownTimer.tsx
- frontend/lib/env/shop-canonical-events.ts
- frontend/lib/tests/shop/monobank-webhook-retry-classifier.test.ts
- frontend/lib/services/shop/transitions/return-state.ts
|
|
||
| const monthRowMap = new Map<string, number>(); | ||
| monthsData.forEach((m, i) => monthRowMap.set(`${m.year}-${m.month}`, i)); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and read the relevant section
cd frontend/components/dashboard 2>/dev/null && wc -l ActivityHeatmapCard.tsxRepository: DevLoversTeam/devlovers.net
Length of output: 98
🏁 Script executed:
# Read the context around line 213
sed -n '210,220p' frontend/components/dashboard/ActivityHeatmapCard.tsxRepository: DevLoversTeam/devlovers.net
Length of output: 338
🏁 Script executed:
# Run the verification script provided in the review
rg -nP "forEach\(\([^)]*\)\s*=>\s*monthRowMap\.set\(" frontend/components/dashboard/ActivityHeatmapCard.tsxRepository: DevLoversTeam/devlovers.net
Length of output: 152
Fix forEach callback return at line 213 (lint violation).
The callback currently returns monthRowMap.set(...). forEach callbacks should return void here; the expression-body syntax causes useIterableCallbackReturn lint error.
🔧 Proposed fix
- monthsData.forEach((m, i) => monthRowMap.set(`${m.year}-${m.month}`, i));
+ monthsData.forEach((m, i) => {
+ monthRowMap.set(`${m.year}-${m.month}`, i);
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| monthsData.forEach((m, i) => monthRowMap.set(`${m.year}-${m.month}`, i)); | |
| monthsData.forEach((m, i) => { | |
| monthRowMap.set(`${m.year}-${m.month}`, i); | |
| }); |
🧰 Tools
🪛 Biome (2.4.4)
[error] 213-213: This callback passed to forEach() iterable method should not return a value.
(lint/suspicious/useIterableCallbackReturn)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@frontend/components/dashboard/ActivityHeatmapCard.tsx` at line 213, The
forEach callback is returning the result of monthRowMap.set(...) which triggers
the useIterableCallbackReturn lint error; change the arrow callback to have a
void/block body so it doesn't return a value — e.g., replace
monthsData.forEach((m, i) => monthRowMap.set(`${m.year}-${m.month}`, i)) with a
block-style callback that calls monthRowMap.set(`${m.year}-${m.month}`, i); (no
return) to silence the lint error.
Summary by CodeRabbit
Bug Fixes
New Features
Refactor