-
Notifications
You must be signed in to change notification settings - Fork 634
2025 wrapped #8598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
2025 wrapped #8598
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds a 2025 "Year in Review" feature: backend aggregation endpoint, analytics reporter, a modal UI with intro/metric/share slides, client auto-open logic, a dedicated rewind page, header badges, and an API route that returns aggregated stats for teams. Changes
Sequence DiagramsequenceDiagram
participant User
participant Badge as RewindBadge
participant Client as RewindModalClient
participant Modal as RewindModal
participant API as /api/rewind
participant Backend as getYearInReview()
participant Analytics as reportRewindViewed()
Note over User,Badge: user opens Rewind (click or auto-open)
User->>Badge: click
Badge->>Client: request open
Client->>Modal: open (auto or manual)
Modal->>API: GET /api/rewind (fetchYearInReview)
API->>Backend: getYearInReview(authToken, teamIds)
Backend->>Backend: aggregate RPC, wallets, sponsored txs across teams
Backend-->>API: YearInReviewStats
API-->>Modal: JSON stats
Modal->>Analytics: reportRewindViewed(stats)
Analytics-->>Analytics: capture event
User->>Modal: navigate slides / share
Modal->>User: use Web Share API or clipboard
User->>Client: close
Client->>Client: persist "rewind-seen-2025" in localStorage
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8598 +/- ##
=======================================
Coverage 53.19% 53.19%
=======================================
Files 922 922
Lines 61480 61480
Branches 4032 4032
=======================================
Hits 32706 32706
Misses 28676 28676
Partials 98 98
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (13)
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (1)
40-40: Consider adding RewindBadge to mobile header for consistent UX.The
RewindBadgeis only added toAccountHeaderDesktopUIbut notAccountHeaderMobileUI. While mobile users can still access the Rewind feature via the tab navigation, adding the badge to mobile would provide a consistent experience across viewports.apps/dashboard/src/app/api/rewind/route.ts (1)
7-27: Add explicit return type annotation.Per coding guidelines, functions should have explicit return types for clarity. The GET handler should specify its return type.
🔎 Proposed fix
-export async function GET() { +export async function GET(): Promise<NextResponse> {apps/dashboard/src/@/analytics/report.ts (1)
706-722: Specify a person as the event owner, not a team handle.Per coding guidelines, the JSDoc should specify who owns the event using a GitHub username (e.g.,
@jnsdls,@MananTank).@thirdwebis a team handle rather than a specific person responsible for maintaining this event.🔎 Proposed fix
* ### Who is responsible for this event? - * @thirdweb + * @Yash094 */apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)
8-39: Add explicit return type annotation.Per coding guidelines, functions should have explicit return types. Consider adding
JSX.ElementorReact.ReactNodeas the return type.🔎 Proposed fix
-export default function RewindPage() { +export default function RewindPage(): JSX.Element {apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (2)
17-20: Hardcoded gradient colors deviate from design system.The gradient uses hardcoded colors (
from-blue-500 to-purple-500) rather than design tokens. While this may be intentional for a distinctive seasonal feature, consider whether these could be defined as CSS variables for easier theming/maintenance.
8-28: Add explicit return type annotation.Per coding guidelines, functions should have explicit return types for clarity.
🔎 Proposed fix
-export function RewindBadge({ className }: { className?: string }) { +export function RewindBadge({ className }: { className?: string }): JSX.Element {apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (2)
8-10: Unused variable and potential timing edge case.
_currentDay(line 10) is declared but never used. Additionally, callingnew Date()three times could theoretically yield inconsistent values if executed exactly at midnight, though this is unlikely in practice.Consider consolidating into a single Date instance:
🔎 Proposed fix
export function RewindModalClient() { const [open, setOpen] = useState(false); - const currentYear = new Date().getFullYear(); - const currentMonth = new Date().getMonth(); - const _currentDay = new Date().getDate(); + const now = new Date(); + const currentYear = now.getFullYear(); + const currentMonth = now.getMonth();
30-36: Consider wrapping localStorage calls in try-catch.
localStoragecan throw in private browsing mode or restricted contexts. While unlikely to cause issues for most users, wrapping in try-catch prevents silent failures.🔎 Proposed fix
const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); if (!newOpen) { // Mark as seen for this year - localStorage.setItem(`rewind-seen-${currentYear}`, "true"); + try { + localStorage.setItem(`rewind-seen-${displayYear}`, "true"); + } catch { + // Ignore localStorage errors (e.g., private browsing) + } } };apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (5)
19-24: Duplicate type definition.
YearInReviewStatsis already exported from@/api/rewind/get-year-in-review.ts(see external_snippet_1). Re-import to avoid drift and follow DRY.🔎 Proposed fix
+import type { YearInReviewStats } from "@/api/rewind/get-year-in-review"; import { reportRewindViewed } from "@/analytics/report"; import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"; import { cn } from "@/lib/utils"; import { ThirdwebMiniLogo } from "../../components/ThirdwebMiniLogo"; -type YearInReviewStats = { - totalRpcRequests: number; - totalWalletConnections: number; - totalMainnetSponsoredTransactions: number; - year: number; -};
90-91: Unused state variable_introPhase.
_introPhaseis set viasetIntroPhasebut never read. If it's not used for rendering or other logic, consider removing it.
124-136: Analytics event may fire on every modal re-open.When the user closes and reopens the modal within the same session,
opentoggles whiledataremains cached, causingreportRewindViewedto fire again. Consider tracking whether the event was already reported for this session.🔎 Proposed fix
+ const [hasReportedAnalytics, setHasReportedAnalytics] = useState(false); // Report analytics when data loads // eslint-disable-next-line no-restricted-syntax useEffect(() => { - if (data && open) { + if (data && open && !hasReportedAnalytics) { reportRewindViewed({ year: displayYear, totalRpcRequests: data.totalRpcRequests, totalWalletConnections: data.totalWalletConnections, totalMainnetSponsoredTransactions: data.totalMainnetSponsoredTransactions, }); + setHasReportedAnalytics(true); } - }, [data, open]); + }, [data, open, hasReportedAnalytics]);
215-235: UseXIconfrom lucide-react instead of inline SVG.The close button SVG is duplicated in two places and embeds raw SVG. Per coding guidelines, icons should be imported from
lucide-react. This also removes duplication.🔎 Proposed fix
Add to imports:
import { ChevronLeftIcon, ChevronRightIcon, SendIcon, Share2Icon, WalletIcon, + XIcon, ZapIcon, } from "lucide-react";Replace inline SVG (both occurrences):
<button type="button" onClick={() => onOpenChange(false)} className="text-muted-foreground hover:text-foreground transition-colors" aria-label="Close" > - <svg - className="h-5 w-5" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - aria-hidden="true" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M6 18L18 6M6 6l12 12" - /> - </svg> + <XIcon className="h-5 w-5" aria-hidden="true" /> </button>Also applies to: 253-273
150-167: Unhandled clipboard.writeText rejection.
navigator.clipboard.writeText()returns a Promise that can reject (e.g., permission denied). Both the catch fallback (line 162) and the else branch (line 165) don't handle this, potentially leaving the user without feedback.🔎 Proposed fix
const handleShare = () => { if (!data) return; const text = `I sent ${formatNumber(data.totalRpcRequests)} RPC requests, connected ${formatNumber(data.totalWalletConnections)} wallets, and sponsored ${formatNumber(data.totalMainnetSponsoredTransactions)} mainnet transactions on thirdweb this year! 🚀`; if (navigator.share) { navigator .share({ title: `My ${displayYear} thirdweb Rewind`, text, url: window.location.href, }) .catch(() => { - navigator.clipboard.writeText(text); + navigator.clipboard.writeText(text).catch(() => { + // Clipboard write failed silently + }); }); } else { - navigator.clipboard.writeText(text); + navigator.clipboard.writeText(text).catch(() => { + // Clipboard write failed silently + }); } };
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (11)
apps/dashboard/src/@/analytics/report.tsapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/api/rewind/route.ts
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/analytics/report.tsapps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsxapps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/app/(app)/account/rewind/RewindModal.tsxapps/dashboard/src/app/(app)/account/layout.tsxapps/dashboard/src/app/(app)/account/components/RewindBadge.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/src/**/@/analytics/report.ts
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/@/analytics/report.ts: Name analytics events with human-readable<subject> <verb>format (e.g. "contract deployed")
Name analytics event reporter functions asreport<Subject><Verb>in PascalCase
Include JSDoc comment explaining why the analytics event is needed and responsible person (@username) for maintenance
Files:
apps/dashboard/src/@/analytics/report.ts
apps/dashboard/**/@/analytics/report.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/@/analytics/report.{ts,tsx}: Create reporting helper functions namedreport<Subject><Verb>in PascalCase undersrc/@/analytics/report.ts
Add mandatory JSDoc to analytics reporting functions explaining why the event exists and who owns it (@username)
Accept a single typedpropertiesobject in analytics reporting functions and pass it unchanged toposthog.capture
Files:
apps/dashboard/src/@/analytics/report.ts
apps/{dashboard,playground}/src/@/analytics/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Only add analytics events that answer a clear product or business question. Check src/@/analytics/report.ts first to avoid duplicates
Files:
apps/dashboard/src/@/analytics/report.ts
apps/{dashboard,playground}/src/@/analytics/report.ts
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/src/@/analytics/report.ts: Use the naming convention: Event name as human-readable phrase in the form ' ' (e.g., 'contract deployed'). Reporting function: 'report' (PascalCase). All reporting helpers live in the shared report.ts file
Add a JSDoc header to analytics event reporters explaining Why the event exists and Who owns it (@username). Accept a single typed properties object and forward it unchanged to posthog.capture()
Files:
apps/dashboard/src/@/analytics/report.ts
apps/dashboard/**/page.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Use the
containerclass with amax-w-7xlcap for consistent page width
Files:
apps/dashboard/src/app/(app)/account/page.tsxapps/dashboard/src/app/(app)/account/rewind/page.tsx
apps/dashboard/**/api/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/api/**/*.{ts,tsx}: Co-locate data helpers under@/api/**and mark them with"server-only"import
Always callgetAuthToken()to get the JWT from cookies in server-side data fetching functions
Prefix server files withimport "server-only";so they never end up in the client bundle
Pass the JWT token in theAuthorization: Bearerheader in server-side fetches; never embed it in the URL
Return typed results (Project[],User[], etc.) from server-side data fetching functions; avoidany
Files:
apps/dashboard/src/app/api/rewind/route.tsapps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/**/layout.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/layout.{ts,tsx}: ReuseSidebarLayoutorFullWidthSidebarLayoutfrom@/components/blocks/SidebarLayoutfor all layouts
Export default async functions without'use client';in server components; they run on the Node edge
Files:
apps/dashboard/src/app/(app)/account/layout.tsx
🧬 Code graph analysis (9)
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (1)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (1)
RewindBadge(8-28)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
RewindModal(74-464)
apps/dashboard/src/app/(app)/account/page.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (1)
RewindModalClient(6-39)
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (1)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (1)
RewindBadge(8-28)
apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
RewindModal(74-464)
apps/dashboard/src/app/api/rewind/route.ts (3)
apps/dashboard/src/@/utils/redirects.ts (1)
loginRedirect(3-9)apps/dashboard/src/@/api/team/get-team.ts (1)
getTeams(58-73)apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
getYearInReview(19-59)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (3)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
YearInReviewStats(8-13)apps/dashboard/src/@/analytics/report.ts (1)
reportRewindViewed(715-722)apps/dashboard/src/app/(app)/components/ThirdwebMiniLogo.tsx (1)
ThirdwebMiniLogo(7-90)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (2)
packages/thirdweb/src/react/web/adapters/WindowAdapter.ts (1)
open(14-17)apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
RewindModal(74-464)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
apps/dashboard/src/@/api/analytics.ts (3)
getRpcUsageByType(563-568)getEOAAndInAppWalletConnections(262-270)getAggregateUserOpUsage(452-457)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/app/(app)/account/page.tsx (1)
9-9: LGTM!The
RewindModalClientimport and placement are appropriate. Rendering the client component at the end of the server component ensures the modal overlay doesn't interfere with the main content layout, and the component properly handles its own visibility state via localStorage.Also applies to: 53-54
apps/dashboard/src/app/(app)/account/layout.tsx (1)
81-84: LGTM!The Rewind tab is appropriately positioned for discoverability. The configuration follows the existing pattern for tab links.
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (1)
12-12: LGTM!The
RewindBadgeplacement mirrorsAccountHeaderDesktopUI, maintaining consistency across the application's header components. Same note asAccountHeaderUI: consider adding to mobile for consistent UX.Also applies to: 57-57
apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)
3-3: The import from@workspace/ui/components/buttonis consistent with the established pattern throughout theapps/dashboard/src/app/directory. While coding guidelines specify@/components/ui/*, the actual codebase standard used across dashboard app files is@workspace/ui/components/*. This file follows the prevailing import convention in the codebase.Likely an incorrect or invalid review comment.
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (3)
1-6: LGTM!Proper use of
"server-only"import and well-organized imports from@/api/analytics.
8-13: LGTM!Clean type definition with clear field names.
144-145: Verified:getAggregateUserOpUsagedoes filter out testnets automatically during aggregation (it skips chainIds withtestnet: true), so the "mainnet sponsored transactions" metric is accurate.
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
Outdated
Show resolved
Hide resolved
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (1)
15-28: IncludedisplayYearin the dependency array for completeness.While
displayYearis a constant and won't change, React's exhaustive-deps rule recommends including all referenced values in the dependency array for consistency and to avoid potential issues if the code evolves.🔎 Proposed fix
useEffect(() => { const hasSeenRewind = localStorage.getItem(`rewind-seen-${displayYear}`); const shouldShowRewind = (currentMonth === 11 || currentMonth === 0) && !hasSeenRewind; if (shouldShowRewind) { // Small delay for better UX const timer = setTimeout(() => { setOpen(true); }, 1000); return () => clearTimeout(timer); } - }, [currentMonth]); + }, [currentMonth, displayYear]);
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/app/api/rewind/route.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsxapps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
apps/dashboard/**/api/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/api/**/*.{ts,tsx}: Co-locate data helpers under@/api/**and mark them with"server-only"import
Always callgetAuthToken()to get the JWT from cookies in server-side data fetching functions
Prefix server files withimport "server-only";so they never end up in the client bundle
Pass the JWT token in theAuthorization: Bearerheader in server-side fetches; never embed it in the URL
Return typed results (Project[],User[], etc.) from server-side data fetching functions; avoidany
Files:
apps/dashboard/src/@/api/rewind/get-year-in-review.tsapps/dashboard/src/app/api/rewind/route.ts
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (2)
packages/thirdweb/src/react/web/adapters/WindowAdapter.ts (1)
open(14-17)apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
RewindModal(74-464)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
apps/dashboard/src/@/api/analytics.ts (3)
getRpcUsageByType(563-568)getEOAAndInAppWalletConnections(262-270)getAggregateUserOpUsage(452-457)
apps/dashboard/src/app/api/rewind/route.ts (2)
apps/dashboard/src/@/api/team/get-team.ts (1)
getTeams(58-73)apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
getYearInReview(19-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: Build Packages
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
1-182: LGTM!The implementation is well-structured with:
- Proper
"server-only"import to prevent client bundling- Comprehensive error handling with per-team try-catch blocks that prevent single team failures from affecting others
- Consistent patterns across all three aggregation helpers
- Type-safe return values with the exported
YearInReviewStatstype- Appropriate fallback behavior (returning 0) when data is unavailable
The previous issues regarding per-team error handling have been properly addressed.
| export async function GET(request: Request) { | ||
| const authToken = await getAuthToken(); | ||
| if (!authToken) { | ||
| return NextResponse.redirect(new URL("/account/rewind", request.url)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API routes should return HTTP status codes, not redirects.
Line 10 redirects unauthenticated requests to /account/rewind, but:
- This is a JSON API endpoint, and clients expect JSON responses (with appropriate status codes like 401), not HTML redirects.
- Redirecting to
/account/rewindwill likely fail since that page also requires authentication, creating confusion. - API consumers (e.g., React Query in
RewindModal) cannot follow redirects as intended.
🔎 Proposed fix
export async function GET(request: Request) {
const authToken = await getAuthToken();
if (!authToken) {
- return NextResponse.redirect(new URL("/account/rewind", request.url));
+ return NextResponse.json(
+ { error: "Unauthorized" },
+ { status: 401 }
+ );
}🤖 Prompt for AI Agents
In apps/dashboard/src/app/api/rewind/route.ts around lines 7 to 11, replace the
redirect for unauthenticated requests with a proper JSON response and HTTP
status code: detect missing authToken and return a 401 Unauthorized JSON
response (e.g., a small JSON body like { error: "Unauthorized" }) instead of
NextResponse.redirect, so API clients receive a machine-readable error and
correct status code.
PR-Codex overview
This PR introduces a new "Rewind" feature to the account section, allowing users to view their yearly statistics. It includes a modal for displaying these stats, analytics tracking, and UI components for better user engagement.
Detailed summary
Rewindinlayout.tsx.RewindModalClientto manage modal display logic.RewindBadgecomponent for UI integration.rewind viewedevents.getYearInReviewAPI for fetching yearly stats.RewindModalfor displaying yearly statistics.RewindPagewith a button to trigger modal.RewindBadgeinto existing headers and UI components.Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.