1+ import { useState , useCallback } from 'react' ;
2+ import { Octokit } from '@octokit/core' ;
3+
4+ export interface GitHubRepo {
5+ id : number ;
6+ name : string ;
7+ full_name : string ;
8+ html_url : string ;
9+ description : string | null ;
10+ language : string | null ;
11+ stargazers_count : number ;
12+ forks_count : number ;
13+ open_issues_count : number ;
14+ visibility : string ;
15+ fork : boolean ;
16+ pushed_at : string ;
17+ created_at : string ;
18+ updated_at : string ;
19+ topics : string [ ] ;
20+ license : { name : string } | null ;
21+ default_branch : string ;
22+ size : number ;
23+ }
24+
25+ export const useGitHubRepos = ( getOctokit : ( ) => Octokit | null ) => {
26+ const [ repos , setRepos ] = useState < GitHubRepo [ ] > ( [ ] ) ;
27+ const [ totalRepos , setTotalRepos ] = useState ( 0 ) ;
28+ const [ loading , setLoading ] = useState ( false ) ;
29+ const [ error , setError ] = useState ( '' ) ;
30+
31+ const fetchRepos = useCallback (
32+ async ( username : string , page = 1 , perPage = 12 ) => {
33+ const octokit = getOctokit ( ) ;
34+ if ( ! octokit || ! username . trim ( ) ) return ;
35+
36+ setLoading ( true ) ;
37+ setError ( '' ) ;
38+
39+ try {
40+ const response = await octokit . request ( 'GET /users/{username}/repos' , {
41+ username,
42+ per_page : perPage ,
43+ page,
44+ sort : 'pushed' ,
45+ direction : 'desc' ,
46+ type : 'owner' ,
47+ } ) ;
48+
49+ const linkHeader = ( response . headers as any ) ?. link ?? '' ;
50+ const lastMatch = linkHeader . match ( / p a g e = ( \d + ) > ; r e l = " l a s t " / ) ;
51+ const total = lastMatch
52+ ? parseInt ( lastMatch [ 1 ] , 10 ) * perPage
53+ : ( page - 1 ) * perPage + response . data . length ;
54+
55+ setRepos ( response . data as GitHubRepo [ ] ) ;
56+ setTotalRepos ( total ) ;
57+ } catch ( err : any ) {
58+ const status = err ?. status ;
59+ const message = err ?. message ?. toLowerCase ( ) ?? '' ;
60+
61+ if ( status === 403 ) {
62+ setError ( 'GitHub API rate limit exceeded. Please provide a PAT to continue.' ) ;
63+ } else if ( status === 404 || message . includes ( 'not found' ) ) {
64+ setError ( 'User not found. Please check the GitHub username.' ) ;
65+ } else if ( status === 401 ) {
66+ setError ( 'Invalid token. Please check your Personal Access Token.' ) ;
67+ } else {
68+ setError ( 'Unable to fetch repositories. Please verify the username or network connection.' ) ;
69+ }
70+ } finally {
71+ setLoading ( false ) ;
72+ }
73+ } ,
74+ [ getOctokit ]
75+ ) ;
76+
77+ return { repos, totalRepos, loading, error, fetchRepos } ;
78+ } ;
0 commit comments