Skip to content

feat(tracker): add Active Days analytics and contribution insights#671

Open
arpit2006 wants to merge 1 commit into
GitMetricsLab:mainfrom
arpit2006:feat/active-analytics
Open

feat(tracker): add Active Days analytics and contribution insights#671
arpit2006 wants to merge 1 commit into
GitMetricsLab:mainfrom
arpit2006:feat/active-analytics

Conversation

@arpit2006
Copy link
Copy Markdown
Contributor

@arpit2006 arpit2006 commented Jun 1, 2026

Related Issue


Description

Implemented Total Active Days Analytics in the GitHub Tracker dashboard.

Changes Made

  • Added a new Active Days tab alongside Issues and Pull Requests.
  • Calculated the total number of unique days with contribution activity.
  • Included both Issues and Pull Requests when determining active days.
  • Added an analytics summary card displaying the total active days count.
  • Integrated active days with existing filters (repository, state, and date range).
  • Ensured the metric updates dynamically whenever filtered data changes.
  • Added proper empty-state handling when no activity data is available.
  • Maintained responsive design across desktop and mobile devices.

This enhancement provides contributors with a better understanding of their contribution consistency and engagement over time.


How Has This Been Tested?

  • Verified active day calculations using sample issue and pull request data.
  • Tested updates when applying repository filters.
  • Tested updates when applying state filters.
  • Tested updates when applying date range filters.
  • Verified correct behavior with empty datasets.
  • Checked responsiveness on different screen sizes.
  • Confirmed there are no TypeScript or build errors.

Screenshots (if applicable)

d2 d1
  1. Active Days analytics card.
  2. Active Days tab with contribution data.
  3. Filtered results updating the active day count.

Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Active Days" analytics tab with date-based activity tracking and pagination controls
    • Dashboard now displays total contribution metrics
  • Improvements

    • Redesigned contribution mix section with standardized card layout
    • Enhanced pie chart visualization and presentation
  • Tests

    • Added test coverage for active days calculation

@netlify
Copy link
Copy Markdown

netlify Bot commented Jun 1, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 9e8aa8b
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a1d85aa47eb4b0008d46439
😎 Deploy Preview https://deploy-preview-671--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements the "Total Active Days" analytics feature for the GitHub Tracker. It adds a getTotalActiveDays utility that counts unique contribution dates, refactors Dashboard chart rendering with a shared card layout helper, and integrates an "Active Days" tab into the Tracker page with date-aggregated activity and pagination.

Changes

Total Active Days Analytics Feature

Layer / File(s) Summary
getTotalActiveDays utility and test coverage
src/components/Dashboard.tsx, src/components/__test__/Dashboard.test.tsx
Exports getTotalActiveDays helper that deduplicates and counts unique created_at dates from combined issues and PR datasets. Adds comprehensive Vitest test cases validating correct active day counting and zero-handling for empty inputs.
Dashboard card rendering refactoring
src/components/Dashboard.tsx
Introduces renderChartCard helper to standardize Paper/Box layout across analytics cards. Refactors "Contribution Mix" pie and "Top Repositories" bar charts to use the shared renderer, adjusts chart configuration and empty-state messaging for repository data scenarios.
Tracker Active Days feature integration
src/pages/Tracker/Tracker.tsx
Adds Active Days tab to Tracker page with state management for pagination and fetch gating. Computes unique activity dates from filtered issues and PRs, aggregates activity counts per date, and conditionally renders an analytics snapshot card and paginated activity table. Updates tab switching to reset pagination state and hides state filter on Active Days view.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GitMetricsLab/github_tracker#591: Modifies Dashboard.tsx chart refactoring and "no data" handling directly related to the chart rendering changes in this PR.
  • GitMetricsLab/github_tracker#517: Modifies Tracker.tsx fetch state flow and tab behavior that may interact with the Active Days tab integration and hasFetchedData gating.
  • GitMetricsLab/github_tracker#255: Modifies Dashboard.tsx analytics rendering and Tracker.tsx integration with chart/card logic that this PR builds upon.

Suggested labels

type:feature, level:advanced, quality:clean

Poem

🐰 A rabbit hops through dates so bright,
Counting days of contribution light,
Active streaks and analytics glow,
Dashboard cards in a steady row,
Metrics hop toward insight's embrace!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(tracker): add Active Days analytics and contribution insights' clearly and accurately describes the main changes in the changeset.
Description check ✅ Passed The PR description comprehensively covers all required template sections with detailed change documentation, testing coverage, and supporting screenshots.
Linked Issues check ✅ Passed The PR fully implements all acceptance criteria from issue #669: calculates unique active days [Dashboard.tsx], displays the metric in a dedicated analytics card [Tracker.tsx], updates dynamically with filters [Tracker.tsx], supports date ranges [Tracker.tsx], maintains responsive design, and handles empty datasets gracefully.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing Total Active Days Analytics as required by issue #669; no unrelated modifications detected in the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
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.

🧹 Nitpick comments (2)
src/components/__test__/Dashboard.test.tsx (1)

6-17: 💤 Low value

Prefer type-safe mocks over as never[] casts.

The test data is missing required GitHubItem properties. Instead of using as never[] which suppresses all type checking, create complete mock objects or use a factory helper.

♻️ Suggested improvement
+const createMockItem = (created_at: string): Parameters<typeof getTotalActiveDays>[0][number] => ({
+  id: 1,
+  title: 'test',
+  state: 'open',
+  created_at,
+  repository_url: 'https://api.github.com/repos/test/repo',
+  html_url: 'https://github.com/test/repo/issues/1',
+});
+
 describe('getTotalActiveDays', () => {
   it('counts unique YYYY-MM-DD values across issues and pull requests', () => {
     const issues = [
-      { created_at: '2026-05-01T12:00:00Z' },
-      { created_at: '2026-05-01T18:30:00Z' },
-      { created_at: '2026-05-02T09:15:00Z' },
+      createMockItem('2026-05-01T12:00:00Z'),
+      createMockItem('2026-05-01T18:30:00Z'),
+      createMockItem('2026-05-02T09:15:00Z'),
     ];
 
     const prs = [
-      { created_at: '2026-05-02T20:45:00Z' },
-      { created_at: '2026-05-03T08:00:00Z' },
+      createMockItem('2026-05-02T20:45:00Z'),
+      createMockItem('2026-05-03T08:00:00Z'),
     ];
 
-    expect(getTotalActiveDays(issues as never[], prs as never[])).toBe(3);
+    expect(getTotalActiveDays(issues, prs)).toBe(3);
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/__test__/Dashboard.test.tsx` around lines 6 - 17, The test is
casting incomplete test data to never[] which bypasses type safety; replace
those casts by creating properly typed mock GitHubItem objects (or a small
factory helper) that include the required properties used by getTotalActiveDays
(e.g., created_at plus any other fields present on the GitHubItem type), and use
those mocks instead of issues as never[] and prs as never[] when calling
getTotalActiveDays so the compiler enforces correctness.
src/pages/Tracker/Tracker.tsx (1)

173-191: ⚡ Quick win

Optimize activeDaysData computation to single-pass O(N).

The current implementation iterates the combined array multiple times: once to build the Set, then once per unique date to count activities. With many items this becomes O(N*D). A single-pass approach using a Map is more efficient.

Additionally, this duplicates the date extraction logic from the exported getTotalActiveDays utility in Dashboard.tsx.

♻️ Single-pass implementation
-  const activeDaysData = Array.from(
-    new Set(
-      [...filteredIssues, ...filteredPrs]
-        .map((item) => item.created_at?.slice(0, 10))
-        .filter((date): date is string => Boolean(date))
-    )
-  )
-    .map((date) => ({
-      date,
-      count: [...filteredIssues, ...filteredPrs].filter(
-        (item) => item.created_at?.slice(0, 10) === date
-      ).length,
-    }))
-    .sort((a, b) => b.date.localeCompare(a.date));
+  const activeDaysData = (() => {
+    const countsByDate = new Map<string, number>();
+    [...filteredIssues, ...filteredPrs].forEach((item) => {
+      const date = item.created_at?.slice(0, 10);
+      if (date) {
+        countsByDate.set(date, (countsByDate.get(date) ?? 0) + 1);
+      }
+    });
+    return Array.from(countsByDate, ([date, count]) => ({ date, count }))
+      .sort((a, b) => b.date.localeCompare(a.date));
+  })();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 173 - 191, activeDaysData is
built with multiple passes over [...filteredIssues, ...filteredPrs], causing
O(N*D) behavior and duplicating logic from Dashboard.tsx; replace it with a
single-pass date counting using a Map (iterate once over the combined array,
extract created_at?.slice(0,10) and increment counts in the Map), then convert
the Map entries to the [{date, count}] array, sort by date descending, set
totalActiveDays = map.size, and compute activeDaysPageData via the same slice
logic using activeDaysPage and ACTIVE_DAYS_ROWS_PER_PAGE; alternatively import
and call the exported getTotalActiveDays utility from Dashboard.tsx (if it
returns the needed structure) to avoid duplicating date-extraction logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/__test__/Dashboard.test.tsx`:
- Around line 6-17: The test is casting incomplete test data to never[] which
bypasses type safety; replace those casts by creating properly typed mock
GitHubItem objects (or a small factory helper) that include the required
properties used by getTotalActiveDays (e.g., created_at plus any other fields
present on the GitHubItem type), and use those mocks instead of issues as
never[] and prs as never[] when calling getTotalActiveDays so the compiler
enforces correctness.

In `@src/pages/Tracker/Tracker.tsx`:
- Around line 173-191: activeDaysData is built with multiple passes over
[...filteredIssues, ...filteredPrs], causing O(N*D) behavior and duplicating
logic from Dashboard.tsx; replace it with a single-pass date counting using a
Map (iterate once over the combined array, extract created_at?.slice(0,10) and
increment counts in the Map), then convert the Map entries to the [{date,
count}] array, sort by date descending, set totalActiveDays = map.size, and
compute activeDaysPageData via the same slice logic using activeDaysPage and
ACTIVE_DAYS_ROWS_PER_PAGE; alternatively import and call the exported
getTotalActiveDays utility from Dashboard.tsx (if it returns the needed
structure) to avoid duplicating date-extraction logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26eb192f-6fa1-40d4-a71a-ed2b5cb81190

📥 Commits

Reviewing files that changed from the base of the PR and between 53f820b and 9e8aa8b.

📒 Files selected for processing (3)
  • src/components/Dashboard.tsx
  • src/components/__test__/Dashboard.test.tsx
  • src/pages/Tracker/Tracker.tsx

@arpit2006
Copy link
Copy Markdown
Contributor Author

@mehul-m-prajapati , Requesting Review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Add Total Active Days Analytics

1 participant