diff --git a/src/hooks/useGitHubData.ts b/src/hooks/useGitHubData.ts index d4d1161..e9b15d0 100644 --- a/src/hooks/useGitHubData.ts +++ b/src/hooks/useGitHubData.ts @@ -1,60 +1,63 @@ import { useState, useCallback } from 'react'; -export const useGitHubData = (octokit) => { +export const useGitHubData = (octokit: any) => { + const [issues, setIssues] = useState([]); const [prs, setPrs] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + const [totalIssues, setTotalIssues] = useState(0); + const [totalPrs, setTotalPrs] = useState(0); - const fetchAll = async (url, params) => { - let page = 1; - let results = []; - let hasMore = true; + const fetchPaginated = async (username: string, type: string, page = 1, per_page = 10) => { - while (hasMore) { - const response = await octokit.request(url, { ...params, page }); - results = results.concat(response.data.items); - hasMore = response.data.items.length === 100; - page++; - } + const q = `author:${username} is:${type}`; + const response = await octokit.request('GET /search/issues', { + q, + sort: 'created', + order: 'desc', + per_page, + page, + }); - return results; + return { + items: response.data.items, + total: response.data.total_count, + }; }; - const fetchData = useCallback(async (username) => { - if (!octokit || !username) return; - - setLoading(true); - setError(''); - - try { - const [issuesResponse, prsResponse] = await Promise.all([ - fetchAll('GET /search/issues', { - q: `author:${username} is:issue`, - sort: 'created', - order: 'desc', - per_page: 100, - }), - fetchAll('GET /search/issues', { - q: `author:${username} is:pr`, - sort: 'created', - order: 'desc', - per_page: 100, - }), - ]); - - setIssues(issuesResponse); - setPrs(prsResponse); - } catch (err) { - setError(err.message); - } finally { - setLoading(false); - } - }, [octokit]); + const fetchData = useCallback( + async (username: string, page = 1, perPage = 10) => { + + if (!octokit || !username) return; + + setLoading(true); + setError(''); + + try { + const [issueRes, prRes] = await Promise.all([ + fetchPaginated(username, 'issue', page, perPage), + fetchPaginated(username, 'pr', page, perPage), + ]); + + setIssues(issueRes.items); + setPrs(prRes.items); + setTotalIssues(issueRes.total); + setTotalPrs(prRes.total); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }, + [octokit] + ); return { issues, prs, + totalIssues, + totalPrs, loading, error, fetchData, diff --git a/src/hooks/usePagination.ts b/src/hooks/usePagination.ts deleted file mode 100644 index 4c9bd2d..0000000 --- a/src/hooks/usePagination.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useState } from 'react'; - -export const usePagination = (rowsPerPage = 10) => { - const [page, setPage] = useState(0); - const [itemsPerPage] = useState(rowsPerPage); - - const handleChangePage = (event, newPage) => { - setPage(newPage); - }; - - const paginateData = (data) => { - return data.slice(page * itemsPerPage, page * itemsPerPage + itemsPerPage); - }; - - return { - page, - itemsPerPage, - handleChangePage, - paginateData, - }; -}; \ No newline at end of file diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx index 7645397..34cb8cd 100644 --- a/src/pages/Home/Home.tsx +++ b/src/pages/Home/Home.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Container, Box, @@ -25,7 +25,6 @@ import { import { useTheme } from "@mui/material/styles"; import { useGitHubAuth } from "../../hooks/useGitHubAuth"; import { useGitHubData } from "../../hooks/useGitHubData"; -import { usePagination } from "../../hooks/usePagination"; const ROWS_PER_PAGE = 10; @@ -53,24 +52,38 @@ const Home: React.FC = () => { const { issues, prs, + totalIssues, + totalPrs, loading, error: dataError, fetchData, } = useGitHubData(octokit); - const { page, itemsPerPage, handleChangePage, paginateData } = - usePagination(ROWS_PER_PAGE); const [tab, setTab] = useState(0); - const [issueFilter, setIssueFilter] = useState("all"); - const [prFilter, setPrFilter] = useState("all"); - const [searchTitle, setSearchTitle] = useState(""); - const [selectedRepo, setSelectedRepo] = useState(""); - const [startDate, setStartDate] = useState(""); - const [endDate, setEndDate] = useState(""); + const [page, setPage] = useState(0); + + const [issueFilter, setIssueFilter] = useState("all"); + const [prFilter, setPrFilter] = useState("all"); + const [searchTitle, setSearchTitle] = useState(""); + const [selectedRepo, setSelectedRepo] = useState(""); + const [startDate, setStartDate] = useState(""); + const [endDate, setEndDate] = useState(""); + + // Fetch data when username, tab, or page changes + useEffect(() => { + if (username) { + fetchData(username, page + 1, ROWS_PER_PAGE); + } + }, [username, tab, page, fetchData]); const handleSubmit = (e: React.FormEvent): void => { e.preventDefault(); - fetchData(username); + setPage(0); + fetchData(username, 1, ROWS_PER_PAGE); + }; + + const handlePageChange = (_: unknown, newPage: number) => { + setPage(newPage); }; const formatDate = (dateString: string): string => @@ -81,7 +94,7 @@ const Home: React.FC = () => { if (["open", "closed", "merged"].includes(filterType)) { filtered = filtered.filter((item) => filterType === "merged" - ? item.pull_request?.merged_at + ? !!item.pull_request?.merged_at : item.state === filterType ); } @@ -108,30 +121,18 @@ const Home: React.FC = () => { return filtered; }; - const currentData = - tab === 0 ? filterData(issues, issueFilter) : filterData(prs, prFilter); - const displayData = paginateData(currentData); + // Current data and filtered data according to tab and filters + const currentRawData = tab === 0 ? issues : prs; + const currentFilteredData = filterData( + currentRawData, + tab === 0 ? issueFilter : prFilter + ); + const totalCount = tab === 0 ? totalIssues : totalPrs; return ( - - + + {/* Auth Form */} +
{ value={username} onChange={(e) => setUsername(e.target.value)} required - sx={{ flex: 1 }} + sx={{ flex: 1, minWidth: 150 }} /> { onChange={(e) => setToken(e.target.value)} type="password" required - sx={{ flex: 1 }} + sx={{ flex: 1, minWidth: 150 }} />