Skip to content

Conversation

@ariefgp
Copy link
Collaborator

@ariefgp ariefgp commented Dec 31, 2025

Summary

This PR enhances the client dashboard with 6 new analytics chart components, improves code maintainability through shared styles, adds accessibility features, and fixes UI bugs in existing charts.


New Features

1. Period Comparison Card

  • Shows weekly performance comparison (this week vs last week)
  • Displays votes, comments, submissions, and views with percentage change indicators
  • Visual trend indicators (up/down arrows) for quick insights

2. Category Performance Chart

  • Horizontal bar chart showing top categories by average engagement
  • Helps users understand which categories perform best
  • Displays item count and engagement metrics per category

3. Approval Rate Trend Chart

  • Area chart showing 6-month approval rate history
  • Tracks total submissions vs approved submissions over time
  • Helps users monitor their approval success rate

4. Submission Calendar Heatmap

  • GitHub-style activity heatmap for the last 90 days
  • Visual representation of submission consistency
  • Intensity colors indicate activity level per day

5. Engagement Distribution Chart

  • Horizontal bar chart showing top items by total engagement
  • Displays percentage of total engagement per item
  • Helps users identify their most engaging content

6. Engagement Rate Chart

  • Line chart showing engagement rate over time
  • Includes average reference line for comparison
  • Tracks votes and comments per submission ratio

Refactoring Changes

1. Created Shared Styles File

Problem: Each dashboard chart component had duplicated style constants (card styles, title styles, tooltip styles, colors), violating the DRY principle and making theme updates difficult.

Impact: Centralized style management, easier theme updates, reduced code duplication across 6 components.

What we did:

  • Created new file: components/dashboard/styles.ts
  • Extracted common constants: CARD_BASE_STYLES, TITLE_STYLES, SUBTITLE_STYLES, VALUE_STYLES, TOOLTIP_STYLES, CHART_COLORS, SEMANTIC_COLORS
  • Updated all 6 new chart components to import from shared styles

Deleted: Local style constant definitions in each component (replaced with imports from styles.ts)

2. Added Accessibility Attributes

Problem: Chart components lacked proper accessibility attributes, making them difficult to navigate for screen reader users.

Impact: Improved accessibility compliance, better screen reader support, proper semantic HTML structure.

What we did:

  • Changed container elements from <div> to <section> with aria-labelledby attribute
  • Added id attributes to heading elements for accessibility linking
  • Applied to all 6 new chart components

3. Replaced Hardcoded Text with Translations

Problem: Some text like "vs" and "Avg:" were hardcoded in English, breaking internationalization support.

Impact: Full i18n support for all dashboard text, consistent translation across 14 supported languages.

What we did:

  • Added COMMON.VS and COMMON.AVG translations to all 14 locale files
  • Updated period-comparison.tsx to use tCommon("VS") instead of hardcoded "vs"
  • Updated engagement-rate-chart.tsx to use tCommon("AVG") instead of hardcoded "Avg:"

4. Fixed Locale-Aware Date Formatting

Problem: submission-calendar.tsx used hardcoded "en-US" locale for date formatting, ignoring user's locale preference.

Impact: Dates now display in user's preferred locale format.

What we did:

  • Added useLocale() hook from next-intl
  • Updated formatDate function to accept locale parameter
  • Passed current locale to date formatting

Bug Fixes

1. Fixed Pie Chart Label Overlap for 0% Values

Problem: In StatusBreakdown and EngagementChart pie charts, labels for 0% values (e.g., "Rejected", "Shares") would render as "Rejected0%" or "Shares0%", overlapping with adjacent labels.

Impact: Clean pie chart display without overlapping text when some categories have zero values.

What we did:

  • Updated status-breakdown.tsx label function to return empty string for 0% values
  • Updated engagement-chart.tsx label function to return empty string for 0% values

2. Fixed Submission Calendar Layout

Problem: Submission calendar was constrained to 50% width in a 2-column grid, causing excessive whitespace on the right side.

Impact: Better visual balance and use of available space.

What we did:

  • Moved SubmissionCalendar to its own full-width row in dashboard-content.tsx
  • Updated heatmap container to center content with increased gap spacing
  • EngagementDistribution now has its own full-width row as well

Backend Changes

Repository Layer Updates

File: lib/repositories/client-dashboard.repository.ts

  • Added 5 new data types: PeriodComparisonData, CategoryPerformanceData, ApprovalTrendData, SubmissionCalendarData, EngagementDistributionData
  • Added export interfaces for type sharing with frontend components
  • Implemented 5 new calculation methods for chart data
  • Increased data fetch limits (top items: 5 to 10, daily views: 7 to 14 days) to support new charts

Translation Updates

Added new translation keys for all 6 chart components across 14 locale files:

  • ar.json (Arabic)
  • de.json (German)
  • en.json (English)
  • es.json (Spanish)
  • fr.json (French)
  • id.json (Indonesian)
  • it.json (Italian)
  • ja.json (Japanese)
  • ko.json (Korean)
  • nl.json (Dutch)
  • pl.json (Polish)
  • pt.json (Portuguese)
  • ru.json (Russian)
  • zh.json (Chinese)

Files Changed

New Files (7):

  • components/dashboard/styles.ts
  • components/dashboard/period-comparison.tsx
  • components/dashboard/category-performance.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/engagement-rate-chart.tsx

Modified Files (21):

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/engagement-chart.tsx
  • components/dashboard/status-breakdown.tsx
  • components/dashboard/index.ts
  • hooks/use-dashboard-stats.ts
  • hooks/mock-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • messages/ar.json
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/nl.json
  • messages/pl.json
  • messages/pt.json
  • messages/ru.json
  • messages/zh.json

Summary by cubic

Enhances the client dashboard with six new analytics charts and improves design, accessibility, and i18n. Also adds backend data support and fixes chart label and layout issues.

  • New Features

    • Added charts: Period Comparison, Category Performance, Approval Trend, Submission Calendar, Engagement Distribution, Engagement Rate.
    • Repository updates: new data types and calculations; increased limits (top items 10, daily views 14).
  • Refactors

    • Centralized shared styles for dashboard charts (cards, titles, tooltips, colors).
    • Improved accessibility with semantic sections and aria-labelledby.
    • Replaced hardcoded text with translations (COMMON.VS, COMMON.AVG) across 14 locales; locale-aware dates in the Submission Calendar.
    • Bug fixes: hide 0% pie labels; moved calendar and engagement distribution to full-width rows.

Written for commit 7aa7b95. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added a suite of dashboard analytics widgets and updated dashboard layout: Period Comparison, Category Performance, Approval Trend, Submission Calendar, Engagement Distribution, and Engagement Rate Chart.
  • Bug Fixes

    • Chart labels updated to hide zero-value slices for clearer visuals.
  • Internationalization

    • Added comprehensive dashboard translations across multiple languages (13 locales).

✏️ Tip: You can customize this high-level summary in your review settings.

  - Add PeriodComparison: weekly performance comparison (this week vs last week)
  - Add CategoryPerformance: horizontal bar chart of top categories by avg engagement
  - Add ApprovalTrend: area chart showing 6-month approval rate trend
  - Add SubmissionCalendar: GitHub-style heatmap for last 90 days activity
  - Add EngagementDistribution: horizontal bar chart of top items by engagement
  - Add EngagementRateChart: line chart showing engagement rate over time
… accessibility

  Changes:

  - New file: components/dashboard/styles.ts
    - Centralized design system constants (CARD_BASE_STYLES, TITLE_STYLES, etc.)
    - Added TOOLTIP_STYLES, CHART_COLORS, SEMANTIC_COLORS
  - Modified: components/dashboard/period-comparison.tsx
    - Import shared styles from styles.ts (DRY principle)
    - Use SEMANTIC_COLORS instead of hardcoded color values
    - Replace hardcoded "vs" with translation tCommon("VS")
    - Add accessibility attributes (aria-label, aria-labelledby, role)
    - Change container to <section> with proper landmarks
  - Modified: 14 locale files (ar, de, en, es, fr, id, it, ja, ko, nl, pl, pt, ru, zh)
    - Add client.dashboard.COMMON.VS translation
    - Add client.dashboard.COMMON.AVG translation
    - Replaced local style constants with imports from ./styles
    - Changed container from <div> to <section> with aria-labelledby
    - Added id to heading for accessibility linking
… and add accessibility

    - Replaced local style constants with imports from ./styles
    - Added useLocale() and passed locale to formatDate() for proper i18n
    - Changed container from <div> to <section> with aria-labelledby
    - Added id to heading for accessibility linking
…ility

    - Replaced local style constants with imports from ./styles
    - Changed container from <div> to <section> with aria-labelledby
    - Added id to heading for accessibility linking
… add accessibility

    - Replaced local style constants with imports from ./styles
    - Replaced hardcoded "Avg:" with tCommon("AVG") translation
    - Changed container from <div> to <section> with aria-labelledby
    - Added id to heading for accessibility linking
@ariefgp ariefgp self-assigned this Dec 31, 2025
@vercel
Copy link

vercel bot commented Dec 31, 2025

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

Project Deployment Review Updated (UTC)
ever-works-website-template Ready Ready Preview, Comment Dec 31, 2025 11:05pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a dashboard analytics feature: six new client React components, shared dashboard styles and exports, extended repository computations and types for new chart data, removal of a mock fixture, and comprehensive i18n dashboard strings across many locales.

Changes

Cohort / File(s) Summary
New Dashboard Components
components/dashboard/approval-trend.tsx, components/dashboard/category-performance.tsx, components/dashboard/engagement-distribution.tsx, components/dashboard/engagement-rate-chart.tsx, components/dashboard/period-comparison.tsx, components/dashboard/submission-calendar.tsx
Six new client-side React components. Each accepts data + isLoading, renders loading skeleton, empty-state messages (i18n), and responsive Recharts visualizations or heatmap/grid with shared style constants and accessibility attributes.
Dashboard Infrastructure
components/dashboard/styles.ts, components/dashboard/index.ts
New shared style constants (card/text/metric/tooltips), CHART_COLORS and SEMANTIC_COLORS exported as const; index re-exports the six new components to public API.
Dashboard Layout Integration
components/dashboard/dashboard-content.tsx
Injects the new dashboard sections into existing dashboard layout; passes isLoading/data derived from stats with safe defaults and keeps refresh/error handling.
Chart label tweaks
components/dashboard/engagement-chart.tsx, components/dashboard/status-breakdown.tsx
Label renderers now suppress labels for 0% slices (return empty string) to avoid showing zero-value labels.
Repository data layer
lib/repositories/client-dashboard.repository.ts
Adds new interfaces and Export variants for five chart data shapes; extends DashboardStats to include new fields; implements calculations for periodComparison, categoryPerformance, approvalTrend (6 months), submissionCalendar (90 days), engagementDistribution (top 10); increases top items to 10 and daily horizon to 14 days; provides empty-data helpers.
Hooks & mocks
hooks/use-dashboard-stats.ts, hooks/mock-dashboard-stats.ts, hooks/index.ts
use-dashboard-stats re-exports new types and extends UserStats with new chart fields. The mock fixture file was removed and its export removed from hooks index.
Localization
messages/en.json, messages/ar.json, messages/de.json, messages/es.json, messages/fr.json, messages/id.json, messages/it.json, messages/ja.json, messages/ko.json, messages/nl.json, messages/pl.json, messages/pt.json, messages/ru.json, messages/zh.json
Adds a comprehensive dashboard translation namespace (consistent nested keys: STATS, PERIOD_COMPARISON, CATEGORY_PERFORMANCE, APPROVAL_TREND, ENGAGEMENT_RATE, SUBMISSION_CALENDAR, ENGAGEMENT_DISTRIBUTION, COMMON, CHARTS) across many locales.

Sequence Diagram(s)

(Skipped — changes are multiple new components and data calculations but do not introduce a single new cross-component runtime control flow that meets the diagram criteria.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • evereq

Poem

🐇 Tiny paws tap keys at dawn,

Charts unfurl where numbers yawn,
Six new views in colors bright,
Translations sing from left to right,
Hop — the dashboard blooms tonight! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: enhancing the dashboard with new analytics charts and design improvements, which is reflected throughout the file summaries.
✨ 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 feat/enhance-dashboard-analytics-charts

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.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 28 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="components/dashboard/approval-trend.tsx">

<violation number="1" location="components/dashboard/approval-trend.tsx:89">
P2: Hardcoded SVG gradient ID can cause collisions if this component is rendered multiple times. Use React&#39;s `useId()` hook to generate a unique ID, consistent with how `stats-card.tsx` handles this.</violation>
</file>

<file name="components/dashboard/category-performance.tsx">

<violation number="1" location="components/dashboard/category-performance.tsx:106">
P2: The `labelFormatter` lookup may return the wrong category if two categories share the same 15-character prefix. Since `chartData` is in scope and contains both `displayCategory` and original `category`, match by exact `displayCategory` instead.</violation>
</file>

<file name="components/dashboard/status-breakdown.tsx">

<violation number="1" location="components/dashboard/status-breakdown.tsx:51">
P2: The condition checks for exact zero but the display rounds to 0%. Values like 0.004 (0.4%) would pass the check but still render as &#39;0%&#39; after rounding, potentially causing the same label overlap issue. Consider checking if the rounded percentage equals 0 instead.</violation>
</file>

<file name="components/dashboard/period-comparison.tsx">

<violation number="1" location="components/dashboard/period-comparison.tsx:125">
P2: ARIA role mismatch: `role=&quot;list&quot;` requires children with `role=&quot;listitem&quot;`, but `MetricCard` uses `role=&quot;group&quot;`. Remove `role=&quot;list&quot;` since the `MetricCard` components already have proper `role=&quot;group&quot;` with `aria-label` attributes for accessibility.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (16)
messages/pt.json (1)

2839-2930: Client dashboard (pt) translations look correct and aligned with new components

The new client.dashboard block is syntactically valid, preserves all interpolation placeholders, and the Portuguese wording is consistent with the rest of the locale. Only minor nit: if layout allows, you might consider expanding abbreviations like "Engaj. Médio" / "Méd." to full words for clarity.

messages/nl.json (1)

2839-2930: Client dashboard (nl) translations are consistent and implementation-ready

The added client.dashboard namespace matches the expected key structure, keeps all placeholders intact, and the Dutch phrasing fits the existing tone. Optionally, you could expand abbreviations like "Gem. Betrokk." / "Gem." if the chart layout has room for slightly longer labels.

messages/fr.json (1)

2939-3029: Client dashboard FR translations look correct; consider clarifying abbreviations.

The new client.submissions.dashboard block is structurally aligned with the EN locale (same keys, same placeholders) and should work fine with the new dashboard components.

One optional polish point:

  • "AVG_ENGAGEMENT": "Engag. Moy." and "AVG": "Moy." use fairly terse abbreviations that may be unclear out of context. If UI space allows, consider expanding slightly for readability, e.g.:
Optional wording tweak
-       "AVG_ENGAGEMENT": "Engag. Moy.",
+       "AVG_ENGAGEMENT": "Engagement moy.",
...
-               "AVG": "Moy."
+               "AVG": "Moyenne"

Purely stylistic; functionally this block is good to ship.

components/dashboard/engagement-chart.tsx (1)

20-35: Consider reusing shared dashboard style tokens to avoid duplication

You now have CARD_BASE_STYLES, TITLE_STYLES, and TOOLTIP_STYLES in components/dashboard/styles.ts; this component is duplicating those values inline. Reusing the shared tokens will keep the engagement chart visually consistent with the new dashboard widgets and make future style changes easier.

Proposed refactor using shared styles
-import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts';
+import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts';
+import { CARD_BASE_STYLES, TITLE_STYLES, TOOLTIP_STYLES } from './styles';
@@
-    return (
-      <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700 p-6">
+    return (
+      <div className={CARD_BASE_STYLES}>
@@
-    <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700 p-6">
-      <h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
+    <div className={CARD_BASE_STYLES}>
+      <h3 className={`${TITLE_STYLES} mb-4`}>
@@
-          <Tooltip 
-            contentStyle={{
-              backgroundColor: '#1F2937',
-              border: '1px solid #374151',
-              borderRadius: '8px',
-              color: '#F9FAFB'
-            }}
-          />
+          <Tooltip contentStyle={TOOLTIP_STYLES} />

Also applies to: 53-60

messages/ru.json (1)

2840-2930: Client dashboard RU translations look consistent; minor optional copy tweak

The new client.dashboard block is structurally coherent (all expected subsections and keys are present) and the {name} placeholder in WELCOME_BACK is correctly preserved. As an optional polish, consider localizing "COMMON.VS": "vs" to a Russian equivalent (for example, "против") if you want to avoid English fragments in the Russian UI; everything else looks good to ship.

messages/es.json (1)

2862-2952: ES dashboard translations aligned with analytics surface; only tiny optional wording nit

The new client.dashboard subtree for Spanish cleanly matches the expected structure (STATS, PERIOD_COMPARISON, CATEGORY_PERFORMANCE, APPROVAL_TREND, ENGAGEMENT_RATE, SUBMISSION_CALENDAR, ENGAGEMENT_DISTRIBUTION, COMMON, CHARTS) and preserves the {name} placeholder correctly in WELCOME_BACK. If you prefer fully localized copy, you might replace "COMMON.VS": "vs" with a Spanish alternative (e.g., "frente a"), but that’s purely optional—current texts are coherent and usable.

components/dashboard/status-breakdown.tsx (1)

50-53: Label guard correctly hides 0% slices; consider a tiny readability refactor

The updated label callback safely skips labels for zero-percent slices and avoids percent being undefined by using percent ?? 0, which matches the intent to hide 0% segments. For readability you could compute a local const percentage = (percent ?? 0) * 100; and reuse it in both the zero check and the formatted string, but behavior is already correct.

components/dashboard/dashboard-content.tsx (1)

18-23: New analytics widgets are wired correctly into the dashboard layout

The newly imported analytics components are integrated cleanly:

  • Each widget receives the appropriate slice from stats (periodComparison, categoryPerformance, approvalTrend, submissionCalendar, engagementDistribution, engagementOverview, totalSubmissions) and an isLoading={!stats} flag that matches their expected props.
  • Fallbacks like || [] and || 0 ensure children never see undefined where they expect arrays/numbers, while their own isLoading / “no data” branches handle empty data gracefully.
  • Updating EngagementOverview to take isLoading keeps behavior consistent with other cards.

You might optionally introduce a local const isLoading = !stats; and reuse it for all these components to reduce repetition, but that’s purely a readability tweak.

Please run pnpm tsc --noEmit to confirm that useDashboardStats’s return type includes all the new fields (periodComparison, categoryPerformance, approvalTrend, submissionCalendar, engagementDistribution, updated engagementOverview, etc.) referenced here.

Also applies to: 108-115, 130-134, 136-145, 164-187

components/dashboard/period-comparison.tsx (1)

125-125: Consider removing or fixing the role="list" attribute.

The grid has role="list" but the MetricCard children use role="group" instead of role="listitem". This creates an accessibility mismatch. Either remove role="list" from the grid or add role="listitem" wrappers around each MetricCard.

🔎 Proposed fix
-            <div className="grid grid-cols-2 md:grid-cols-4 gap-4" role="list">
+            <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
components/dashboard/submission-calendar.tsx (2)

33-40: Consider reusing the utility function from utils/date.ts or documenting the difference.

There's a formatDate function in utils/date.ts with different options (month: 'long'). This local version uses month: 'short' which is appropriate for the compact calendar tooltip, but consider adding a comment to clarify this intentional difference.


69-89: Using -1 as a sentinel value for padding days works but is non-obvious.

The count: -1 sentinel is used to identify padding cells. Consider using a more explicit approach like a isPadding boolean flag or a union type for better readability.

components/dashboard/engagement-rate-chart.tsx (1)

23-27: Duplicate interface definition.

EngagementOverviewData is defined locally here but also exists in hooks/use-dashboard-stats.ts (lines 31-35). Consider importing from the hook file to maintain a single source of truth and ensure type consistency.

🔎 Proposed fix

Add the type to the re-exports in hooks/use-dashboard-stats.ts:

// In hooks/use-dashboard-stats.ts, add to exports:
export type { EngagementOverviewData };

Then import in this file:

+import type { EngagementOverviewData } from "@/hooks/use-dashboard-stats";
-interface EngagementOverviewData {
-    week: string;
-    votes: number;
-    comments: number;
-}
components/dashboard/engagement-distribution.tsx (1)

105-110: Improved but still imperfect tooltip label matching.

Using startsWith is better than exact substring comparison (as in category-performance.tsx), but could still match incorrectly if multiple items share the same 20-character prefix. Consider using the same Map-based approach suggested for category-performance for consistency.

hooks/use-dashboard-stats.ts (1)

93-95: Add Zod validation for the dashboard stats API response.

The response is cast to UserStats without runtime validation. Per coding guidelines, create a Zod schema in lib/validations/client-dashboard.ts to validate the API response shape. This would catch mismatches between the API and the expected UserStats type at runtime, especially important given the complex nested structure of the response.

lib/repositories/client-dashboard.repository.ts (2)

56-112: Consider eliminating duplicate Export type variants.

Lines 56-88 define internal chart data types, while lines 89-112 define structurally identical Export variants. This duplication increases maintenance burden without clear benefit. Note that EngagementDistributionData (line 81) is exported directly without a duplicate, creating an inconsistent pattern.

🔎 Proposed consolidation

Export the base types directly and remove the Export variants:

-interface PeriodComparisonData {
+export interface PeriodComparisonData {
     thisWeek: { votes: number; comments: number; submissions: number; views: number };
     lastWeek: { votes: number; comments: number; submissions: number; views: number };
     change: { votes: number; comments: number; submissions: number; views: number };
 }
 
-interface CategoryPerformanceData {
+export interface CategoryPerformanceData {
     category: string;
     itemCount: number;
     totalEngagement: number;
     avgEngagement: number;
 }
 
-interface ApprovalTrendData {
+export interface ApprovalTrendData {
     month: string;
     approved: number;
     total: number;
     rate: number;
 }
 
-interface SubmissionCalendarData {
+export interface SubmissionCalendarData {
     date: string;
     count: number;
 }

-export interface PeriodComparisonDataExport {
-    thisWeek: { votes: number; comments: number; submissions: number; views: number };
-    lastWeek: { votes: number; comments: number; submissions: number; views: number };
-    change: { votes: number; comments: number; submissions: number; views: number };
-}
-
-export interface CategoryPerformanceDataExport {
-    category: string;
-    itemCount: number;
-    totalEngagement: number;
-    avgEngagement: number;
-}
-
-export interface ApprovalTrendDataExport {
-    month: string;
-    approved: number;
-    total: number;
-    rate: number;
-}
-
-export interface SubmissionCalendarDataExport {
-    date: string;
-    count: number;
-}

Then update consuming code to reference the base types instead of Export variants.


487-533: Consider extracting magic number for top categories limit.

The method correctly calculates category performance with multi-category item support. The top 5 limit (line 532) is reasonable but hardcoded.

🔎 Optional improvement

Extract to a constant at the top of the file for easier adjustment:

+const TOP_CATEGORIES_LIMIT = 5;
+
 // ... in calculateCategoryPerformance
 
         return result
             .sort((a, b) => b.avgEngagement - a.avgEngagement)
-            .slice(0, 5);
+            .slice(0, TOP_CATEGORIES_LIMIT);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4d9d8 and 32cfb95.

📒 Files selected for processing (28)
  • components/dashboard/approval-trend.tsx
  • components/dashboard/category-performance.tsx
  • components/dashboard/dashboard-content.tsx
  • components/dashboard/engagement-chart.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/index.ts
  • components/dashboard/period-comparison.tsx
  • components/dashboard/status-breakdown.tsx
  • components/dashboard/styles.ts
  • components/dashboard/submission-calendar.tsx
  • hooks/mock-dashboard-stats.ts
  • hooks/use-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • messages/ar.json
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/nl.json
  • messages/pl.json
  • messages/pt.json
  • messages/ru.json
  • messages/zh.json
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Node.js >= 20.19.0

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • hooks/use-dashboard-stats.ts
  • hooks/mock-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

components/**/*.{ts,tsx}: UI components should be placed in the components/** directory
Keep React components mostly presentational and lean, avoiding complex business logic

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Prefer TypeScript files over JavaScript

Run pnpm tsc --noEmit for TypeScript type-checking

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • hooks/use-dashboard-stats.ts
  • hooks/mock-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place UI and layout components in components/**

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer TypeScript for all code

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • hooks/use-dashboard-stats.ts
  • hooks/mock-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: Follow Prettier config with tabs, 4-space tabWidth, and 120-char printWidth
Prefer async/await over raw Promise chains in TypeScript/JavaScript code
Validate input with Zod where appropriate; follow existing schemas in lib/validations
Keep i18n-friendly: avoid hard-coded English strings in logic; use next-intl messages where relevant

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • hooks/use-dashboard-stats.ts
  • hooks/mock-dashboard-stats.ts
  • lib/repositories/client-dashboard.repository.ts
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/styles.ts
  • components/dashboard/index.ts
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
**/components/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/components/**/*.{jsx,tsx}: For forms, prefer react-hook-form + Zod; follow patterns in existing auth/profile forms
Place business logic in lib/services or lib/repositories, not in components; keep components mostly presentational and data-fetching

Files:

  • components/dashboard/dashboard-content.tsx
  • components/dashboard/status-breakdown.tsx
  • components/dashboard/engagement-rate-chart.tsx
  • components/dashboard/period-comparison.tsx
  • components/dashboard/submission-calendar.tsx
  • components/dashboard/engagement-distribution.tsx
  • components/dashboard/approval-trend.tsx
  • components/dashboard/category-performance.tsx
  • components/dashboard/engagement-chart.tsx
lib/repositories/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Data access and repositories should be placed in lib/repositories/** directory

Files:

  • lib/repositories/client-dashboard.repository.ts
lib/{services,repositories}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place shared business logic in lib/services/** and lib/repositories/**

Files:

  • lib/repositories/client-dashboard.repository.ts
🧬 Code graph analysis (5)
components/dashboard/dashboard-content.tsx (8)
components/dashboard/period-comparison.tsx (1)
  • PeriodComparison (79-165)
components/dashboard/index.ts (7)
  • PeriodComparison (10-10)
  • EngagementOverview (6-6)
  • CategoryPerformance (11-11)
  • ApprovalTrend (12-12)
  • SubmissionCalendar (13-13)
  • EngagementDistribution (14-14)
  • EngagementRateChart (15-15)
components/dashboard/engagement-overview.tsx (1)
  • EngagementOverview (16-72)
components/dashboard/category-performance.tsx (1)
  • CategoryPerformance (28-142)
components/dashboard/approval-trend.tsx (1)
  • ApprovalTrend (27-145)
components/dashboard/submission-calendar.tsx (1)
  • SubmissionCalendar (42-170)
components/dashboard/engagement-distribution.tsx (1)
  • EngagementDistribution (29-140)
components/dashboard/engagement-rate-chart.tsx (1)
  • EngagementRateChart (35-172)
hooks/use-dashboard-stats.ts (1)
lib/repositories/client-dashboard.repository.ts (5)
  • PeriodComparisonDataExport (89-93)
  • CategoryPerformanceDataExport (95-100)
  • ApprovalTrendDataExport (102-107)
  • SubmissionCalendarDataExport (109-112)
  • EngagementDistributionData (81-87)
components/dashboard/engagement-rate-chart.tsx (3)
components/dashboard/styles.ts (5)
  • CARD_BASE_STYLES (4-5)
  • TITLE_STYLES (7-7)
  • SUBTITLE_STYLES (9-9)
  • VALUE_STYLES (11-11)
  • TOOLTIP_STYLES (21-26)
components/ui/responsive-container.tsx (1)
  • ResponsiveContainer (14-51)
lib/editor/components/primitive/tooltip/tooltip.tsx (1)
  • Tooltip (132-153)
components/dashboard/submission-calendar.tsx (4)
hooks/use-dashboard-stats.ts (1)
  • SubmissionCalendarDataExport (15-15)
utils/date.ts (1)
  • formatDate (1-7)
components/dashboard/index.ts (1)
  • SubmissionCalendar (13-13)
components/dashboard/styles.ts (4)
  • CARD_BASE_STYLES (4-5)
  • TITLE_STYLES (7-7)
  • SUBTITLE_STYLES (9-9)
  • VALUE_STYLES (11-11)
components/dashboard/approval-trend.tsx (5)
hooks/use-dashboard-stats.ts (1)
  • ApprovalTrendDataExport (14-14)
components/dashboard/index.ts (1)
  • ApprovalTrend (12-12)
components/dashboard/styles.ts (5)
  • CARD_BASE_STYLES (4-5)
  • TITLE_STYLES (7-7)
  • SUBTITLE_STYLES (9-9)
  • VALUE_STYLES (11-11)
  • TOOLTIP_STYLES (21-26)
components/ui/responsive-container.tsx (1)
  • ResponsiveContainer (14-51)
lib/editor/components/primitive/tooltip/tooltip.tsx (1)
  • Tooltip (132-153)
⏰ 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). (5)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Greptile Review
  • GitHub Check: Lint and Build
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (33)
messages/it.json (1)

2839-2930: LGTM! Dashboard translations properly structured.

The Italian dashboard translations are well-organized with:

  • Valid JSON syntax and proper nesting
  • Consistent key naming conventions
  • Correct placeholder usage ({name}, {count}, etc.)
  • Complete coverage of all dashboard sections (STATS, PERIOD_COMPARISON, CATEGORY_PERFORMANCE, APPROVAL_TREND, ENGAGEMENT_RATE, SUBMISSION_CALENDAR, ENGAGEMENT_DISTRIBUTION, COMMON, CHARTS)

The structure aligns well with the new dashboard analytics components described in the PR objectives.

messages/zh.json (1)

2871-2962: LGTM! Chinese dashboard translations mirror Italian file perfectly.

The Chinese dashboard translations maintain excellent consistency with the Italian locale file:

  • Identical key structure and nesting
  • Matching placeholder usage
  • Valid JSON syntax throughout
  • Complete coverage of all dashboard sections
  • Proper formatting and organization

The consistency between locale files will ensure the dashboard components render correctly across all supported languages.

messages/de.json (1)

2872-2963: Client dashboard de-translations look structurally and semantically aligned

The new client.dashboard block mirrors the expected key structure (STATS, PERIOD_COMPARISON, CATEGORY_PERFORMANCE, APPROVAL_TREND, ENGAGEMENT_RATE, SUBMISSION_CALENDAR, ENGAGEMENT_DISTRIBUTION, COMMON, CHARTS), uses the correct {name} placeholder, and the German phrasing is consistent and clear for a dashboard context. No JSON or i18n placeholder issues spotted.

messages/id.json (1)

2840-2930: Client dashboard id-translations are consistent and correctly structured

The added client.dashboard namespace matches the other locales’ key shape, keeps the {name} placeholder intact, and provides natural Indonesian labels and descriptions for all charts and empty states. No issues with JSON validity or obvious i18n mismatches.

messages/en.json (1)

2955-3045: New client dashboard EN strings are consistent and ready to use.

The added client.submissions.dashboard namespace cleanly matches the described widgets (stats, weekly comparison, category performance, approval trend, engagement charts), with:

  • Key structure parallel to other locales and internally consistent.
  • Correct use of the {name} placeholder in WELCOME_BACK.
  • Reusable COMMON.VS and COMMON.AVG labels, which will help avoid hardcoded “vs” / “Avg” in chart components.
  • Clear, user-friendly copy for loading and no‑data states.

No issues from an i18n or structural perspective.

messages/ja.json (1)

2839-2930: Client dashboard ja translations look structurally sound

The new client.dashboard block is well‑structured (correct nesting, commas, and ICU placeholder {name}) and aligns with the described dashboard analytics widgets. No issues from a code/i18n‑keys perspective.

components/dashboard/styles.ts (1)

1-51: Shared dashboard style tokens are clean and reusable

Centralizing card, text, metric, tooltip, and color constants here is straightforward and consistent. The exports are well‑named, immutable, and ready to be reused across dashboard components.

components/dashboard/engagement-chart.tsx (1)

41-44: Zero‑percent slice labels now handled safely

The updated label callback correctly skips labels for 0% slices and defends against missing name/percent values. This should clean up the chart without affecting non‑zero segments.

messages/ar.json (1)

2860-2950: Arabic client dashboard block is consistent and correctly structured

The new client.dashboard keys are complete, structurally valid, and consistent with the other locales (including correct {name} placeholder usage). No code‑level issues spotted.

messages/pl.json (1)

2839-2930: Client dashboard PL translations align with new components

The new client.dashboard block (plus EDIT_SUBMISSION_DESC) looks structurally consistent with the component usages: all expected keys (STATS, PERIOD_COMPARISON, CATEGORY_PERFORMANCE, APPROVAL_TREND, ENGAGEMENT_RATE, SUBMISSION_CALENDAR, ENGAGEMENT_DISTRIBUTION, COMMON, CHARTS) are present, naming matches the code, and placeholders (e.g. {name}) are well-formed. JSON syntax also looks correct.

messages/ko.json (1)

2839-2930: Client dashboard KO translations are complete and consistent

The added client.dashboard namespace (and EDIT_SUBMISSION_DESC) cleanly mirrors the expected structure from the dashboard components: all section and field keys are present, COMMON.VS/AVG exist for shared labels, and the JSON remains valid. This should keep the new analytics widgets fully localized in Korean.

components/dashboard/index.ts (1)

10-15: Barrel exports for new dashboard widgets look correct

The additional exports for PeriodComparison, CategoryPerformance, ApprovalTrend, SubmissionCalendar, EngagementDistribution, and EngagementRateChart correctly point at their component modules and align with how they’re imported elsewhere.

components/dashboard/period-comparison.tsx (3)

32-53: LGTM!

The ChangeIndicator component is well-implemented with clear conditional logic for positive/negative/neutral states and appropriate color classes for both light and dark modes.


55-77: LGTM!

The MetricCard component is clean and accessible with proper role="group" and aria-label attributes. Good use of aria-hidden="true" on the decorative color dot.


79-165: Well-structured component with good separation of concerns.

The component follows best practices: proper loading/empty states, i18n compliance, shared styles usage, and accessibility with aria-labelledby. The use of <section> for the data-present state is appropriate.

components/dashboard/submission-calendar.tsx (2)

24-31: LGTM!

The intensity class function correctly maps count ratios to appropriate color classes with both light and dark mode support.


42-170: Well-implemented calendar heatmap with good UX.

The component handles loading, empty states, and data rendering well. Good use of useMemo for performance optimization and locale-aware date formatting. The legend at the bottom provides helpful context.

hooks/mock-dashboard-stats.ts (1)

64-97: Mock data structure aligns well with the new UserStats interface.

The new mock data fields (periodComparison, categoryPerformance, approvalTrend, submissionCalendar, engagementDistribution) correctly match the type definitions and provide reasonable test values.

hooks/use-dashboard-stats.ts (2)

2-17: Good pattern for re-exporting types.

Re-exporting the data types from the repository layer provides a clean API for component consumers and maintains proper module boundaries.


70-75: Type extension aligns with repository exports.

The new fields in UserStats correctly reference the exported types from the repository layer.

components/dashboard/approval-trend.tsx (3)

55-59: Data aggregation logic is correct.

The calculations for latestRate, firstRate, rateChange, totalSubmissions, and totalApproved correctly handle edge cases with optional chaining and default values.


87-106: Well-defined gradient for the area chart.

The gradient approvalGradient provides a nice visual effect with proper opacity transitions.


27-145: Clean implementation following established patterns.

The component properly handles loading, empty, and data states. Good use of shared styles, i18n, and accessibility attributes. The chart configuration is appropriate for displaying trend data.

components/dashboard/engagement-rate-chart.tsx (2)

43-54: Verify the rate calculation semantics.

The rate formula ((week.votes + week.comments) / totalSubmissions) * 100 divides weekly engagement by total submissions (a constant across all weeks). This produces a "percentage of total submissions that received engagement this week" rather than a typical engagement rate. Ensure this matches the intended metric, or consider documenting this in the UI/tooltip.


35-172: Component structure and patterns are consistent with other dashboard components.

Good implementation with proper loading/empty states, accessibility, and i18n. The ReferenceLine for average is a nice addition for context.

components/dashboard/category-performance.tsx (1)

28-142: Well-structured component with good accessibility and i18n support.

The component follows established patterns for loading/empty states, uses shared styles consistently, and provides a compact legend for the top categories.

components/dashboard/engagement-distribution.tsx (2)

122-137: Nice progress bar visualization for the top item.

The summary section with progress bar provides good context for the #1 item's share of total engagement.


29-140: Component follows established dashboard patterns.

Good implementation with consistent loading/empty states, accessibility, i18n, and shared styles. The visual summary at the bottom adds value.

lib/repositories/client-dashboard.repository.ts (5)

214-218: LGTM! Clear justification for increased data limits.

The increased limits for topItemsEngagement (5→10) and dailyViewsData (7→14) are well-documented with inline comments explaining their purpose for the new engagement distribution and period comparison charts.


538-580: LGTM! Approval trend calculation is correct.

The method properly handles:

  • 6-month initialization with zeros
  • Approved vs total counting by month
  • Zero-division protection in rate calculation (line 575)

Note: This uses the same local date logic as calculatePeriodComparison. If timezone handling is addressed there, apply the same approach here for consistency.


585-616: LGTM! Submission calendar logic is sound.

The 90-day heatmap calculation correctly:

  • Initializes all days with zeros
  • Uses ISO date format (YYYY-MM-DD) consistently
  • Sorts chronologically for proper display

621-658: LGTM! Engagement distribution calculation is accurate.

The method correctly:

  • Combines multiple engagement signals (votes, comments, views)
  • Handles missing items gracefully (line 644)
  • Calculates percentage share with zero-division protection
  • Returns top 10 items sorted by engagement

708-745: LGTM! Empty state helpers are consistent.

The helper methods getEmptyApprovalTrend and getEmptySubmissionCalendar correctly mirror the structure of their calculation counterparts, ensuring proper initialization when no data exists.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 31, 2025

Greptile Summary

  • Enhanced client dashboard with 6 new analytics chart components (Period Comparison, Category Performance, Approval Trend, Submission Calendar, Engagement Distribution, and Engagement Rate) to provide comprehensive performance insights
  • Improved code maintainability by creating centralized components/dashboard/styles.ts for shared chart styling constants and enhanced accessibility with semantic HTML and ARIA attributes
  • Fixed UI bugs in existing pie charts by hiding 0% value labels and improved layout by moving calendar components to full-width rows for better visual balance

Important Files Changed

Filename Overview
lib/repositories/client-dashboard.repository.ts Added 5 new data types and calculation methods for analytics charts; increased data fetch limits for enhanced dashboard functionality
components/dashboard/engagement-distribution.tsx New horizontal bar chart component with potential tooltip matching issue using string manipulation for truncated titles
components/dashboard/dashboard-content.tsx Restructured layout to accommodate 6 new analytics charts with improved responsive grid organization and full-width components

Confidence score: 4/5

  • This PR is well-structured with comprehensive analytics enhancements but requires attention to potential edge cases in chart tooltip logic
  • Score reflects excellent internationalization coverage across 14 locales, proper accessibility implementation, and solid architectural patterns, with minor concerns about string matching logic in tooltip handlers that could fail with similar prefixes
  • Pay close attention to engagement-distribution.tsx tooltip logic and verify the string matching approach works correctly with edge cases

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

28 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@ariefgp ariefgp marked this pull request as draft December 31, 2025 02:42
@ariefgp ariefgp marked this pull request as ready for review December 31, 2025 23:03
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
components/dashboard/category-performance.tsx (1)

103-108: Past tooltip matching issue has been resolved.

The labelFormatter now correctly uses exact displayCategory matching instead of substring comparison, eliminating the risk of returning the wrong category when multiple categories share the same 15-character prefix. This matches the fix described in commit 964ef9b.

🧹 Nitpick comments (2)
components/dashboard/category-performance.tsx (2)

133-133: Avoid programmatic case conversion on translated strings.

Applying .toLowerCase() to t("ITEMS") is not i18n-friendly. Case conversion rules vary by locale (e.g., Turkish Iı, German noun capitalization), and some languages lack case distinctions. Per coding guidelines, translators should control text presentation.

Recommendation: Add a separate translation key (e.g., ITEMS_LOWERCASE) or remove the transformation and let translators provide the appropriate case in each locale.

Alternative approaches

Option 1: Separate translation key

- {item.itemCount} {t("ITEMS").toLowerCase()}
+ {item.itemCount} {t("ITEMS_LOWER")}

Option 2: Let translator control case in the original key
Update all locale files to provide lowercase "items" if that's the desired presentation, then remove .toLowerCase().


84-84: Consider dark-mode adaptive axis colors.

The XAxis and YAxis use fixed stroke="#6B7280" (gray-500), which doesn't adapt to dark mode unlike other UI elements in the component. While fixed axis colors are common in charts for consistency, you may want to use a CSS variable or conditional color for better dark-mode integration.

Also applies to: 91-91

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32cfb95 and 7aa7b95.

📒 Files selected for processing (5)
  • components/dashboard/approval-trend.tsx
  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
  • hooks/index.ts
  • hooks/mock-dashboard-stats.ts
💤 Files with no reviewable changes (2)
  • hooks/index.ts
  • hooks/mock-dashboard-stats.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/dashboard/approval-trend.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Node.js >= 20.19.0

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

components/**/*.{ts,tsx}: UI components should be placed in the components/** directory
Keep React components mostly presentational and lean, avoiding complex business logic

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Prefer TypeScript files over JavaScript

Run pnpm tsc --noEmit for TypeScript type-checking

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Place UI and layout components in components/**

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer TypeScript for all code

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: Follow Prettier config with tabs, 4-space tabWidth, and 120-char printWidth
Prefer async/await over raw Promise chains in TypeScript/JavaScript code
Validate input with Zod where appropriate; follow existing schemas in lib/validations
Keep i18n-friendly: avoid hard-coded English strings in logic; use next-intl messages where relevant

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
**/components/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/components/**/*.{jsx,tsx}: For forms, prefer react-hook-form + Zod; follow patterns in existing auth/profile forms
Place business logic in lib/services or lib/repositories, not in components; keep components mostly presentational and data-fetching

Files:

  • components/dashboard/category-performance.tsx
  • components/dashboard/period-comparison.tsx
🧬 Code graph analysis (2)
components/dashboard/category-performance.tsx (3)
hooks/use-dashboard-stats.ts (1)
  • CategoryPerformanceDataExport (13-13)
components/dashboard/index.ts (1)
  • CategoryPerformance (11-11)
components/dashboard/styles.ts (5)
  • CARD_BASE_STYLES (4-5)
  • TITLE_STYLES (7-7)
  • SUBTITLE_STYLES (9-9)
  • TOOLTIP_STYLES (21-26)
  • CHART_COLORS (28-39)
components/dashboard/period-comparison.tsx (4)
hooks/use-dashboard-stats.ts (1)
  • PeriodComparisonDataExport (12-12)
env-config.ts (1)
  • value (28-39)
components/dashboard/styles.ts (8)
  • METRIC_CARD_STYLES (13-13)
  • METRIC_LABEL_STYLES (15-15)
  • METRIC_VALUE_STYLES (17-17)
  • METRIC_COMPARE_STYLES (19-19)
  • CARD_BASE_STYLES (4-5)
  • TITLE_STYLES (7-7)
  • SUBTITLE_STYLES (9-9)
  • SEMANTIC_COLORS (42-51)
components/dashboard/index.ts (1)
  • PeriodComparison (10-10)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Lint and Build
🔇 Additional comments (1)
components/dashboard/period-comparison.tsx (1)

1-165: LGTM! Well-structured component with excellent accessibility.

This component is well-implemented with:

  • Proper semantic HTML (<section>, <h3>) and ARIA attributes (aria-labelledby, role="group")
  • Complete internationalization using next-intl
  • Three well-defined states (loading, no-data, data-present)
  • Appropriate use of centralized styles and semantic colors
  • Clear component composition with focused sub-components
  • Locale-aware number formatting via toLocaleString()

The past review concern about role="list" has been correctly resolved.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 29 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="components/dashboard/submission-calendar.tsx">

<violation number="1" location="components/dashboard/submission-calendar.tsx:54">
P2: Using `toISOString().split(&quot;T&quot;)[0]` can cause timezone issues where the displayed date differs from the user&#39;s local date. For users in timezones ahead of UTC, &#39;today&#39; may show as yesterday during early morning hours. Use local date formatting instead to ensure consistency with user expectations.</violation>
</file>

<file name="components/dashboard/engagement-distribution.tsx">

<violation number="1" location="components/dashboard/engagement-distribution.tsx:105">
P2: The `labelFormatter` uses `startsWith` to reverse-lookup the original title, which can match the wrong item when multiple titles share the same 20-character prefix. Unlike `category-performance.tsx` which uses exact equality matching against `chartData`, this searches `data` with a partial match.

Consider matching by exact `displayTitle` against `chartData`:</violation>
</file>

<file name="components/dashboard/category-performance.tsx">

<violation number="1" location="components/dashboard/category-performance.tsx:133">
P2: Using `.toLowerCase()` on translated text breaks i18n for some languages (Turkish, German). Consider using ICU message format for proper pluralization: `{count, plural, one {# item} other {# items}}`.</violation>
</file>

<file name="components/dashboard/approval-trend.tsx">

<violation number="1" location="components/dashboard/approval-trend.tsx:99">
P2: Hardcoded color `#10B981` should use `SEMANTIC_COLORS.success` from the shared styles file to maintain consistency with the PR&#39;s goal of centralizing styles. This color appears in 4 places in this file. Consider importing and using the centralized constant for easier theme updates.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@evereq evereq merged commit db69615 into develop Jan 1, 2026
11 checks passed
@evereq evereq deleted the feat/enhance-dashboard-analytics-charts branch January 1, 2026 10:37
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.

3 participants