From 67be97a830c901c724815a9dfb3c144bae8ad3d0 Mon Sep 17 00:00:00 2001 From: Jeet Vasoya Date: Mon, 25 May 2026 22:04:06 +0530 Subject: [PATCH 1/2] task done Requested Features Added: Developer Activity Reminder & Motivation System --- ACTIVITY_REMINDER_FEATURE.md | 167 +++++++++++ src/components/ActivityReminder.tsx | 410 ++++++++++++++++++++++++++++ src/hooks/useGitHubActivity.ts | 120 ++++++++ src/pages/Tracker/Tracker.tsx | 9 + src/utils/activityReminders.ts | 191 +++++++++++++ 5 files changed, 897 insertions(+) create mode 100644 ACTIVITY_REMINDER_FEATURE.md create mode 100644 src/components/ActivityReminder.tsx create mode 100644 src/hooks/useGitHubActivity.ts create mode 100644 src/utils/activityReminders.ts diff --git a/ACTIVITY_REMINDER_FEATURE.md b/ACTIVITY_REMINDER_FEATURE.md new file mode 100644 index 00000000..5bc7988e --- /dev/null +++ b/ACTIVITY_REMINDER_FEATURE.md @@ -0,0 +1,167 @@ +# Daily Activity Reminder System - Feature Documentation + +## Overview + +The Daily Activity Reminder System is a new enhancement to the GitHub Tracker dashboard that motivates users to maintain consistent contribution streaks. It provides real-time insights into your GitHub activity, tracks contribution streaks, and displays motivational reminders to encourage daily contributions. + +## Features + +### 1. **Daily Activity Status** + - **Real-time Activity Tracking**: Monitors commits, pull requests, issues, and other GitHub activities throughout the day + - **Activity Count**: Shows how many contributions you've made today + - **Last Activity Date**: Displays when your last contribution was + +### 2. **Contribution Streak** + - **Streak Counter**: Tracks consecutive days with GitHub contributions + - **Visual Indicator**: 🔥 Flame emoji indicates active streaks + - **Risk Detection**: Alerts you when your streak is at risk (if you haven't contributed today) + - **Motivational Messages**: + - 1-day streak: 🎯 Keep it going! + - 7-day streak: 🔥 You're on a roll! + - 30-day streak: 🚀 Amazing consistency! + - 100+ days: 👑 Legendary contributor! + +### 3. **Productivity Score** + - **Dynamic Calculation**: Based on daily activity metrics + - **Weighted System**: + - 25% each for commits, PRs, merges, and issues + - Bonus points for consecutive streaks (7, 30, 100+ days) + - **Visual Progress Bar**: Shows score with color coding: + - Red: 0-50% (Needs improvement) + - Orange: 50-75% (Good) + - Green: 75-100% (Excellent) + +### 4. **Motivational Reminders** + - **Inactivity Alerts**: Reminds you when you haven't contributed today + - **Activity-Specific Messages**: + - 📌 "Time to make your first contribution today" + - 🚀 "You haven't committed today" + - 💻 "No pull requests opened today" + - 📝 "Consider creating or working on an issue" + - **Positive Reinforcement**: Congratulatory messages when you're active + +### 5. **Activity Breakdown** + - **Visual Status Indicators**: Quick checklist of today's contributions: + - Commits + - Pull Requests Opened + - Pull Requests Merged + - Issues Created + - **Color-Coded**: Green checkmarks for completed activities, gray for pending + +## How It Works + +### Data Collection +The system analyzes GitHub activity data from the last 30 days by default and identifies: +- **Commits**: Estimated from PR creation activity +- **Pull Requests**: Tracked separately as opened and merged +- **Issues**: Issues created or interacted with +- **Daily Activity**: All contributions made within a 24-hour period + +### Streak Calculation +- Streaks are calculated by checking for consecutive days with at least one contribution +- A streak requires activity every day to maintain continuity +- If you miss a day, your streak resets + +### Display Logic +The Activity Reminder appears on the Tracker page when: +1. You've successfully fetched GitHub data (entered username and token) +2. Data has been loaded (not in loading state) +3. You have at least some GitHub activity (issues or PRs) + +## Using the Feature + +### Step 1: Access the Tracker +Navigate to the **Tracker** page in the GitHub Tracker application. + +### Step 2: Authenticate +1. Enter your GitHub username +2. Enter your Personal Access Token (PAT) +3. Click "Fetch Data" + +### Step 3: View Your Activity +Once data is loaded, the Daily Activity Status section appears above the data table with: +- Today's contribution count +- Current streak +- Productivity score +- Motivational reminders +- Activity breakdown + +### Step 4: Respond to Reminders +Use the motivational reminders as guidance to: +- Plan your contributions for the day +- Maintain your contribution streak +- Reach productivity goals + +## Token Requirements + +To use this feature, you need a Personal Access Token with the following permissions: +- `public_repo` (access to public repositories) +- `repo` (access to private repositories - if tracking private repos) + +**Note**: The feature works with or without a token, but with a token you get higher API rate limits. + +## Technical Details + +### Components +- **`useGitHubActivity` Hook**: Analyzes activity data and returns activity status +- **`ActivityReminder` Component**: Displays the reminder UI with all statistics +- **`activityReminders` Utilities**: Helper functions for generating messages and calculations + +### API Integration +The feature leverages the existing GitHub API integration through: +- `useGitHubData` hook for fetching issues and PRs +- `useGitHubAuth` hook for authentication +- Octokit client for GitHub API requests + +### Data Processing +- Activity timestamps are extracted from GitHub API responses +- Daily activity is compared against the current date (00:00-23:59) +- Streak calculation traverses activity history backward in time +- Scores are calculated based on weighted activity metrics + +## Limitations + +1. **Commit Detection**: Direct commit data requires the `/repos/{owner}/{repo}/commits` endpoint, which is not currently used. Commits are estimated from PR activity. +2. **Historical Data**: Only analyzes the last 30 days of issues and PRs due to GitHub API pagination limits. +3. **Rate Limiting**: GitHub API has rate limits (60 requests/hour for unauthenticated, 5000/hour with token). +4. **Timezone**: Activity is determined based on UTC timezone (when GitHub timestamps are recorded). + +## Future Enhancements + +Potential improvements for future versions: +- [ ] Weekly productivity heatmap +- [ ] Monthly contribution statistics +- [ ] Achievement badges (First commit, 100-day streak, etc.) +- [ ] Custom notification preferences +- [ ] Email/browser notifications for streak reminders +- [ ] Integration with GitHub contributions graph +- [ ] Detailed contribution analytics +- [ ] Goal setting and tracking + +## Troubleshooting + +### Activity Reminder not showing +- Ensure you've entered your GitHub username and token +- Click "Fetch Data" to load your GitHub activity +- Check that you have at least one issue or PR in your GitHub history + +### Streak not updating +- Wait for the page to fully load data +- The streak is calculated based on your GitHub activity timestamps +- Ensure your GitHub activity has timestamps from recent days + +### Incorrect productivity score +- Scores are recalculated based on daily activity (commits, PRs, issues) +- The score includes bonus points for longer streaks +- Refresh the page to recalculate with latest data + +## Contact & Feedback + +If you encounter issues or have suggestions for improvements, please: +1. Check the existing GitHub issues +2. Create a new issue with detailed information +3. Include screenshots if relevant + +--- + +**Happy contributing! Keep your streak alive!** 🔥 diff --git a/src/components/ActivityReminder.tsx b/src/components/ActivityReminder.tsx new file mode 100644 index 00000000..e517b3ca --- /dev/null +++ b/src/components/ActivityReminder.tsx @@ -0,0 +1,410 @@ +import React, { useMemo } from 'react'; +import { + Box, + Card, + CardContent, + Typography, + Grid, + Chip, + LinearProgress, + Alert, + useTheme, +} from '@mui/material'; +import { + CheckCircleIcon, + FlameIcon, + AlertCircleIcon, + TrendingUpIcon, +} from 'lucide-react'; +import { ActivityStatus } from '../hooks/useGitHubActivity'; +import { + generateReminders, + generateStreakData, + getActivitySummary, + getActivityColor, + calculateProductivityScore, +} from '../utils/activityReminders'; + +interface ActivityReminderProps { + activity: ActivityStatus; + username: string; +} + +const ActivityReminder: React.FC = ({ + activity, + username, +}) => { + const theme = useTheme(); + const reminders = useMemo(() => generateReminders(activity), [activity]); + const streakData = useMemo(() => generateStreakData(activity), [activity]); + const activitySummary = useMemo( + () => getActivitySummary(activity), + [activity] + ); + const activityColor = useMemo(() => getActivityColor(activity), [activity]); + const productivityScore = useMemo( + () => calculateProductivityScore(activity), + [activity] + ); + + const getSeverityColor = (severity: string) => { + switch (severity) { + case 'success': + return 'success'; + case 'error': + return 'error'; + case 'warning': + return 'warning'; + default: + return 'info'; + } + }; + + const getStreakColor = () => { + if (streakData.isStreakAtRisk) return 'error'; + if (streakData.currentStreak >= 30) return 'success'; + if (streakData.currentStreak >= 7) return 'warning'; + return 'default'; + }; + + return ( + + + + Daily Activity Status + + + + {/* Main Activity Card */} + + + + + {activity.isInactiveToday ? ( + + ) : ( + + )} + + + Today's Activity + + + {activity.todayActivityCount === 0 + ? 'No contributions' + : `${activity.todayActivityCount} contribution${activity.todayActivityCount !== 1 ? 's' : ''}`} + + + + + + {activitySummary} + + + {activity.lastActivityDate && ( + + Last activity: {activity.lastActivityDate} + + )} + + + + + {/* Streak & Productivity Card */} + + + + + + + + Contribution Streak + + + {streakData.currentStreak} day{streakData.currentStreak !== 1 ? 's' : ''} + + + + + + + {streakData.streakMessage} + + + {/* Productivity Score */} + + + + Productivity Score + + + {productivityScore}% + + + = 75 + ? theme.palette.success.main + : productivityScore >= 50 + ? theme.palette.warning.main + : theme.palette.error.main, + }, + }} + /> + + + + + + {/* Reminders Section */} + {reminders.length > 0 && ( + + + Activity Reminders + + + {reminders.map((reminder, index) => ( + {reminder.icon}} + > + + {reminder.message} + + + ))} + + + )} + + {/* Activity Breakdown */} + + + + + Activity Breakdown + + + + + + Commits + + + + + + + + PRs Opened + + + + + + + + PRs Merged + + + + + + + + Issues + + + + + + + + + + + ); +}; + +export default ActivityReminder; diff --git a/src/hooks/useGitHubActivity.ts b/src/hooks/useGitHubActivity.ts new file mode 100644 index 00000000..2fd8ddc9 --- /dev/null +++ b/src/hooks/useGitHubActivity.ts @@ -0,0 +1,120 @@ +import { useMemo } from 'react'; + +export interface ActivityStatus { + hasCommittedToday: boolean; + hasOpenedPRToday: boolean; + hasMergedPRToday: boolean; + hasCreatedIssueToday: boolean; + hasInteractedWithIssueToday: boolean; + isInactiveToday: boolean; + contributionStreak: number; + todayActivityCount: number; + lastActivityDate: string | null; +} + +interface GitHubItem { + id: number; + title: string; + state: string; + created_at: string; + pull_request?: { + merged_at: string | null; + }; + repository_url: string; + html_url: string; +} + +export const useGitHubActivity = ( + issues: GitHubItem[] = [], + prs: GitHubItem[] = [] +): ActivityStatus => { + return useMemo(() => { + const today = new Date(); + today.setHours(0, 0, 0, 0); + + // Check today's activity + const todaysIssues = issues.filter((issue) => { + const createdDate = new Date(issue.created_at); + createdDate.setHours(0, 0, 0, 0); + return createdDate.getTime() === today.getTime(); + }); + + const todaysPRs = prs.filter((pr) => { + const createdDate = new Date(pr.created_at); + createdDate.setHours(0, 0, 0, 0); + return createdDate.getTime() === today.getTime(); + }); + + // Separate PR types for today + const todaysOpenPRs = todaysPRs.filter((pr) => pr.state === 'open'); + const todaysMergedPRs = todaysPRs.filter( + (pr) => pr.pull_request?.merged_at + ); + + // Calculate activity flags + const hasOpenedPRToday = todaysOpenPRs.length > 0; + const hasMergedPRToday = todaysMergedPRs.length > 0; + const hasCreatedIssueToday = todaysIssues.length > 0; + const hasInteractedWithIssueToday = todaysIssues.length > 0; + + // For commits, we estimate based on PR and issue creation activity + // (actual commits require different API endpoint) + const hasCommittedToday = hasOpenedPRToday || hasMergedPRToday; + + const todayActivityCount = todaysIssues.length + todaysPRs.length; + const isInactiveToday = todayActivityCount === 0; + + // Calculate contribution streak (consecutive days with activity) + const allActivity = [...issues, ...prs].sort( + (a, b) => + new Date(b.created_at).getTime() - new Date(a.created_at).getTime() + ); + + let contributionStreak = 0; + if (allActivity.length > 0) { + let currentDate = new Date(); + currentDate.setHours(0, 0, 0, 0); + + // Check if there's activity today + const hasActivityToday = allActivity.some((item) => { + const itemDate = new Date(item.created_at); + itemDate.setHours(0, 0, 0, 0); + return itemDate.getTime() === currentDate.getTime(); + }); + + if (hasActivityToday) { + contributionStreak = 1; + currentDate.setDate(currentDate.getDate() - 1); + + // Count consecutive days backwards + for (const item of allActivity) { + const itemDate = new Date(item.created_at); + itemDate.setHours(0, 0, 0, 0); + + if (itemDate.getTime() === currentDate.getTime()) { + contributionStreak++; + currentDate.setDate(currentDate.getDate() - 1); + } + } + } + } + + // Get last activity date + const lastActivityDate = + allActivity.length > 0 + ? new Date(allActivity[0].created_at).toLocaleDateString() + : null; + + return { + hasCommittedToday, + hasOpenedPRToday, + hasMergedPRToday, + hasCreatedIssueToday, + hasInteractedWithIssueToday, + isInactiveToday, + contributionStreak, + todayActivityCount, + lastActivityDate, + }; + }, [issues, prs]); +}; diff --git a/src/pages/Tracker/Tracker.tsx b/src/pages/Tracker/Tracker.tsx index 576f39bf..4204e0c5 100644 --- a/src/pages/Tracker/Tracker.tsx +++ b/src/pages/Tracker/Tracker.tsx @@ -32,6 +32,8 @@ import { import { useTheme } from "@mui/material/styles"; import { useGitHubAuth } from "../../hooks/useGitHubAuth"; import { useGitHubData } from "../../hooks/useGitHubData"; +import { useGitHubActivity } from "../../hooks/useGitHubActivity"; +import ActivityReminder from "../../components/ActivityReminder"; import { KeyIcon } from "lucide-react"; const ROWS_PER_PAGE = 10; @@ -69,6 +71,8 @@ const Home: React.FC = () => { fetchData, } = useGitHubData(getOctokit); + const activity = useGitHubActivity(issues, prs); + const [tab, setTab] = useState(0); const [page, setPage] = useState(0); @@ -330,6 +334,11 @@ const Home: React.FC = () => { )} + {/* Activity Reminder - Show when data is loaded and user is authenticated */} + {username && !loading && (issues.length > 0 || prs.length > 0) && ( + + )} + {loading ? ( diff --git a/src/utils/activityReminders.ts b/src/utils/activityReminders.ts new file mode 100644 index 00000000..0a957fbd --- /dev/null +++ b/src/utils/activityReminders.ts @@ -0,0 +1,191 @@ +import { ActivityStatus } from '../hooks/useGitHubActivity'; + +export interface ReminderMessage { + icon: string; + message: string; + severity: 'info' | 'warning' | 'error' | 'success'; + type: string; +} + +export interface StreakData { + currentStreak: number; + isStreakAtRisk: boolean; + streakMessage: string; +} + +/** + * Generate motivational reminder messages based on activity status + */ +export const generateReminders = ( + activity: ActivityStatus +): ReminderMessage[] => { + const reminders: ReminderMessage[] = []; + + if (activity.isInactiveToday) { + // No activity today + reminders.push({ + icon: '📌', + message: 'Time to make your first contribution today', + severity: 'warning', + type: 'inactivity', + }); + } else { + // Has activity - provide positive reinforcement + reminders.push({ + icon: '🔥', + message: `Great start! You've contributed ${activity.todayActivityCount} time(s) today`, + severity: 'success', + type: 'achievement', + }); + } + + // Specific activity reminders + if (!activity.hasCommittedToday && !activity.isInactiveToday) { + reminders.push({ + icon: '🚀', + message: "You haven't committed today", + severity: 'info', + type: 'commit', + }); + } + + if (!activity.hasOpenedPRToday && !activity.isInactiveToday) { + reminders.push({ + icon: '💻', + message: 'No pull requests opened today', + severity: 'info', + type: 'pr', + }); + } + + if (!activity.hasCreatedIssueToday && activity.isInactiveToday) { + reminders.push({ + icon: '📝', + message: 'Consider creating or working on an issue', + severity: 'info', + type: 'issue', + }); + } + + return reminders; +}; + +/** + * Generate streak data and motivational message + */ +export const generateStreakData = ( + activity: ActivityStatus +): StreakData => { + const currentStreak = activity.contributionStreak; + const isStreakAtRisk = activity.isInactiveToday && currentStreak > 0; + + let streakMessage = ''; + + if (currentStreak === 0) { + streakMessage = 'Start your contribution streak today!'; + } else if (currentStreak === 1) { + streakMessage = '🎯 You have a 1-day streak! Keep it going!'; + } else if (currentStreak < 7) { + streakMessage = `🔥 ${currentStreak}-day streak! You're on a roll!`; + } else if (currentStreak < 30) { + streakMessage = `🚀 ${currentStreak}-day streak! Amazing consistency!`; + } else if (currentStreak < 100) { + streakMessage = `💪 ${currentStreak}-day streak! You're a contribution machine!`; + } else { + streakMessage = `👑 ${currentStreak}-day streak! Legendary contributor!`; + } + + if (isStreakAtRisk) { + streakMessage += ' ⚠️ Your streak is at risk!'; + } + + return { + currentStreak, + isStreakAtRisk, + streakMessage, + }; +}; + +/** + * Get activity summary text + */ +export const getActivitySummary = (activity: ActivityStatus): string => { + if (activity.isInactiveToday) { + return 'No contributions today'; + } + + const parts: string[] = []; + + if (activity.hasCommittedToday) { + parts.push('Commits made'); + } + if (activity.hasOpenedPRToday) { + parts.push('PRs opened'); + } + if (activity.hasMergedPRToday) { + parts.push('PRs merged'); + } + if (activity.hasCreatedIssueToday) { + parts.push('Issues created'); + } + + if (parts.length === 0) { + return 'Some contributions today'; + } + + return parts.join(' • '); +}; + +/** + * Get color based on activity level + */ +export const getActivityColor = ( + activity: ActivityStatus +): 'error' | 'warning' | 'success' | 'info' => { + if (activity.isInactiveToday) { + return 'error'; + } + + if (activity.todayActivityCount === 1) { + return 'warning'; + } + + if (activity.todayActivityCount >= 2) { + return 'success'; + } + + return 'info'; +}; + +/** + * Calculate productivity score based on activity + */ +export const calculateProductivityScore = ( + activity: ActivityStatus +): number => { + let score = 0; + + if (activity.hasCommittedToday) score += 25; + if (activity.hasOpenedPRToday) score += 25; + if (activity.hasMergedPRToday) score += 25; + if (activity.hasCreatedIssueToday) score += 25; + + // Bonus for consistency + if (activity.contributionStreak >= 7) score += 10; + if (activity.contributionStreak >= 30) score += 20; + if (activity.contributionStreak >= 100) score += 30; + + return Math.min(score, 100); +}; + +/** + * Get motivation level based on streak + */ +export const getMotivationLevel = ( + streak: number +): 'low' | 'medium' | 'high' | 'legendary' => { + if (streak === 0) return 'low'; + if (streak < 7) return 'medium'; + if (streak < 30) return 'high'; + return 'legendary'; +}; From 2d2b9af9ee0d636c511356a6e573f487d9ff61d1 Mon Sep 17 00:00:00 2001 From: Jeet Vasoya Date: Mon, 25 May 2026 22:42:47 +0530 Subject: [PATCH 2/2] final commit --- ACTIVITY_REMINDER_FEATURE.md | 14 ++++++++++--- src/components/ActivityReminder.tsx | 2 -- src/hooks/useGitHubActivity.ts | 31 +++++++++++++++++++---------- src/pages/Tracker/Tracker.tsx | 23 +++++++++++++++------ src/utils/dateUtils.ts | 21 +++++++++++++++++++ 5 files changed, 69 insertions(+), 22 deletions(-) create mode 100644 src/utils/dateUtils.ts diff --git a/ACTIVITY_REMINDER_FEATURE.md b/ACTIVITY_REMINDER_FEATURE.md index 5bc7988e..9e384feb 100644 --- a/ACTIVITY_REMINDER_FEATURE.md +++ b/ACTIVITY_REMINDER_FEATURE.md @@ -94,18 +94,26 @@ Use the motivational reminders as guidance to: ## Token Requirements -To use this feature, you need a Personal Access Token with the following permissions: +**Authentication with a Personal Access Token (PAT) is required** to view and use the ActivityReminder UI. The component is only displayed when you have successfully authenticated with both a GitHub username and a valid PAT. + +Your PAT should have the following permissions: - `public_repo` (access to public repositories) - `repo` (access to private repositories - if tracking private repos) -**Note**: The feature works with or without a token, but with a token you get higher API rate limits. +Without valid authentication, the Daily Activity Status reminder widget will not be accessible. ## Technical Details ### Components - **`useGitHubActivity` Hook**: Analyzes activity data and returns activity status - **`ActivityReminder` Component**: Displays the reminder UI with all statistics -- **`activityReminders` Utilities**: Helper functions for generating messages and calculations +- **Utility Functions** (`activityReminders.ts`): + - `generateReminders()` - Creates motivational alert messages + - `generateStreakData()` - Calculates streak and generates streak messages + - `getActivitySummary()` - Generates text summary of daily activities + - `getActivityColor()` - Returns color coding based on activity level + - `calculateProductivityScore()` - Computes dynamic productivity score (0-100%) + - `getMotivationLevel()` - Determines motivation tier based on streak ### API Integration The feature leverages the existing GitHub API integration through: diff --git a/src/components/ActivityReminder.tsx b/src/components/ActivityReminder.tsx index e517b3ca..f536221b 100644 --- a/src/components/ActivityReminder.tsx +++ b/src/components/ActivityReminder.tsx @@ -27,12 +27,10 @@ import { interface ActivityReminderProps { activity: ActivityStatus; - username: string; } const ActivityReminder: React.FC = ({ activity, - username, }) => { const theme = useTheme(); const reminders = useMemo(() => generateReminders(activity), [activity]); diff --git a/src/hooks/useGitHubActivity.ts b/src/hooks/useGitHubActivity.ts index 2fd8ddc9..20c55c7e 100644 --- a/src/hooks/useGitHubActivity.ts +++ b/src/hooks/useGitHubActivity.ts @@ -47,9 +47,15 @@ export const useGitHubActivity = ( // Separate PR types for today const todaysOpenPRs = todaysPRs.filter((pr) => pr.state === 'open'); - const todaysMergedPRs = todaysPRs.filter( - (pr) => pr.pull_request?.merged_at - ); + + // Compute merged PRs from all PRs by checking merged_at date (not created_at) + // This captures PRs created earlier but merged today + const todaysMergedPRs = prs.filter((pr) => { + if (!pr.pull_request?.merged_at) return false; + const mergedDate = new Date(pr.pull_request.merged_at); + mergedDate.setHours(0, 0, 0, 0); + return mergedDate.getTime() === today.getTime(); + }); // Calculate activity flags const hasOpenedPRToday = todaysOpenPRs.length > 0; @@ -82,19 +88,22 @@ export const useGitHubActivity = ( return itemDate.getTime() === currentDate.getTime(); }); + // Initialize streak based on activity today + // If active today, start at 1 and move to yesterday for iteration + // If inactive today, start at 0 and keep currentDate at today if (hasActivityToday) { contributionStreak = 1; currentDate.setDate(currentDate.getDate() - 1); + } - // Count consecutive days backwards - for (const item of allActivity) { - const itemDate = new Date(item.created_at); - itemDate.setHours(0, 0, 0, 0); + // Count consecutive days backwards (regardless of activity today) + for (const item of allActivity) { + const itemDate = new Date(item.created_at); + itemDate.setHours(0, 0, 0, 0); - if (itemDate.getTime() === currentDate.getTime()) { - contributionStreak++; - currentDate.setDate(currentDate.getDate() - 1); - } + if (itemDate.getTime() === currentDate.getTime()) { + contributionStreak++; + currentDate.setDate(currentDate.getDate() - 1); } } } diff --git a/src/pages/Tracker/Tracker.tsx b/src/pages/Tracker/Tracker.tsx index 4204e0c5..dbeecd06 100644 --- a/src/pages/Tracker/Tracker.tsx +++ b/src/pages/Tracker/Tracker.tsx @@ -34,6 +34,7 @@ import { useGitHubAuth } from "../../hooks/useGitHubAuth"; import { useGitHubData } from "../../hooks/useGitHubData"; import { useGitHubActivity } from "../../hooks/useGitHubActivity"; import ActivityReminder from "../../components/ActivityReminder"; +import { get30DayWindow } from "../../utils/dateUtils"; import { KeyIcon } from "lucide-react"; const ROWS_PER_PAGE = 10; @@ -86,14 +87,24 @@ const Home: React.FC = () => { // Fetch data when username, tab, or page changes useEffect(() => { if (username) { - fetchData(username, page + 1, ROWS_PER_PAGE); + const { startDate, endDate } = get30DayWindow(); + const apiFilters = { + startDate: startDate, + endDate: endDate, + }; + fetchData(username, page + 1, ROWS_PER_PAGE, 'both', apiFilters); } - }, [tab, page]); + }, [tab, page, username]); const handleSubmit = (e: React.FormEvent): void => { e.preventDefault(); setPage(0); - fetchData(username, 1, ROWS_PER_PAGE); + const { startDate, endDate } = get30DayWindow(); + const apiFilters = { + startDate: startDate, + endDate: endDate, + }; + fetchData(username, 1, ROWS_PER_PAGE, 'both', apiFilters); }; const handlePageChange = (_: unknown, newPage: number) => { @@ -334,9 +345,9 @@ const Home: React.FC = () => { )} - {/* Activity Reminder - Show when data is loaded and user is authenticated */} - {username && !loading && (issues.length > 0 || prs.length > 0) && ( - + {/* Activity Reminder - Show when user is authenticated and data is loaded */} + {username && !loading && ( + )} {loading ? ( diff --git a/src/utils/dateUtils.ts b/src/utils/dateUtils.ts new file mode 100644 index 00000000..9541c7cb --- /dev/null +++ b/src/utils/dateUtils.ts @@ -0,0 +1,21 @@ +/** + * Get the date range for the last 30 days + * Returns dates in YYYY-MM-DD format suitable for GitHub API queries + */ +export const get30DayWindow = (): { startDate: string; endDate: string } => { + const today = new Date(); + const thirtyDaysAgo = new Date(today); + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); + + const formatDate = (date: Date): string => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + }; + + return { + startDate: formatDate(thirtyDaysAgo), + endDate: formatDate(today), + }; +};