diff --git a/src/pages/Tracker/Tracker.tsx b/src/pages/Tracker/Tracker.tsx index 576f39bf..202a93cb 100644 --- a/src/pages/Tracker/Tracker.tsx +++ b/src/pages/Tracker/Tracker.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react" +import React, { useState, useEffect, useMemo } from "react" import { IssueOpenedIcon, IssueClosedIcon, @@ -28,11 +28,17 @@ import { MenuItem, FormControl, InputLabel, + Chip, + Card, + CardContent, + Typography, + Grid, + Divider, } from "@mui/material"; import { useTheme } from "@mui/material/styles"; import { useGitHubAuth } from "../../hooks/useGitHubAuth"; import { useGitHubData } from "../../hooks/useGitHubData"; -import { KeyIcon } from "lucide-react"; +import { KeyIcon, Search, Filter } from "lucide-react"; const ROWS_PER_PAGE = 10; @@ -79,17 +85,33 @@ const Home: React.FC = () => { const [startDate, setStartDate] = useState(""); const [endDate, setEndDate] = useState(""); - // Fetch data when username, tab, or page changes + // Fetch data when username, filters, tab, or page changes useEffect(() => { if (username) { - fetchData(username, page + 1, ROWS_PER_PAGE); + const filters = { + search: searchTitle, + repo: selectedRepo, + startDate: startDate, + endDate: endDate, + state: tab === 0 ? issueFilter : prFilter, + }; + const activeTab = tab === 0 ? 'issue' : 'pr'; + fetchData(username, page + 1, ROWS_PER_PAGE, activeTab, filters); } - }, [tab, page]); + }, [username, tab, page, issueFilter, prFilter, searchTitle, selectedRepo, startDate, endDate, fetchData]); const handleSubmit = (e: React.FormEvent): void => { e.preventDefault(); setPage(0); - fetchData(username, 1, ROWS_PER_PAGE); + const filters = { + search: searchTitle, + repo: selectedRepo, + startDate: startDate, + endDate: endDate, + state: tab === 0 ? issueFilter : prFilter, + }; + const activeTab = tab === 0 ? 'issue' : 'pr'; + fetchData(username, 1, ROWS_PER_PAGE, activeTab, filters); }; const handlePageChange = (_: unknown, newPage: number) => { @@ -158,121 +180,219 @@ const Home: React.FC = () => { }; - // Current data and filtered data according to tab and filters + // Memoized filtered data to avoid recomputing on every render const currentRawData = tab === 0 ? issues : prs; - const currentFilteredData = filterData(currentRawData, tab === 0 ? issueFilter : prFilter); + const currentFilteredData = useMemo(() => { + return filterData(currentRawData, tab === 0 ? issueFilter : prFilter); + }, [currentRawData, tab, issueFilter, prFilter, searchTitle, selectedRepo, startDate, endDate]); const totalCount = tab === 0 ? totalIssues : totalPrs; + // Helper function to get status badge color + const getStatusColor = (item: GitHubItem): "success" | "error" | "warning" | "info" | "default" => { + if (item.pull_request) { + if (item.pull_request.merged_at) return "success"; + return item.state === "closed" ? "error" : "info"; + } + return item.state === "closed" ? "error" : "warning"; + }; + + // Helper function to get status label + const getStatusLabel = (item: GitHubItem): string => { + if (item.pull_request?.merged_at) return "Merged"; + return item.state.charAt(0).toUpperCase() + item.state.slice(1); + }; + return ( - - {/* Auth Form */} - -
- - setUsername(e.target.value)} - required - sx={{ flex: 1, minWidth: 150 }} - /> - setToken(e.target.value)} - type="password" - required - sx={{ flex: 1, minWidth: 150 }} - helperText={ - - + {/* Header Section */} + + + GitHub Activity Tracker + + + Track and analyze your GitHub issues and pull requests + + + + {/* Authentication Card */} + + + + + + GitHub Authentication + + + + + + setUsername(e.target.value)} + required + placeholder="Enter your GitHub username" + variant="outlined" + size="medium" + /> + + + setToken(e.target.value)} + type="password" + placeholder="Paste your token here" + variant="outlined" + size="medium" + helperText={ + - - Generate new token - - - - • + + + Generate token + + + • + + + Learn more + + } + /> + + + + + + + + + + {/* Error Alert */} + {(authError || dataError) && ( + + {authError || dataError} + + )} - - Learn more - - - } - /> - + {/* Filters Section */} + + + + + + Filters + - -
- - {/* Filters */} - - setSearchTitle(e.target.value)} - sx={{ minWidth: 200 }} - /> - setSelectedRepo(e.target.value)} - sx={{ minWidth: 200 }} - /> - setStartDate(e.target.value)} - InputLabelProps={{ shrink: true }} - sx={{ minWidth: 150 }} - /> - setEndDate(e.target.value)} - InputLabelProps={{ shrink: true }} - sx={{ minWidth: 150 }} - /> - + + + setSearchTitle(e.target.value)} + placeholder="Search by title..." + variant="outlined" + size="small" + InputProps={{ + startAdornment: , + }} + /> + + + setSelectedRepo(e.target.value)} + placeholder="Filter by repo..." + variant="outlined" + size="small" + /> + + + setStartDate(e.target.value)} + InputLabelProps={{ shrink: true }} + variant="outlined" + size="small" + /> + + + setEndDate(e.target.value)} + InputLabelProps={{ shrink: true }} + variant="outlined" + size="small" + /> + + + + {/* Tabs + State Filter */} { gap: 2, }} > - { - setTab(v); - setPage(0); + - - - - - State + { + setTab(v); + setPage(0); + }} + sx={{ + "& .MuiTabs-indicator": { + height: 3, + }, + }} + > + + + + + + Filter by State