@@ -809,118 +809,107 @@ <h4>Connect With Us</h4>
809809 let contributorsData = [ ] ;
810810 let filteredContributors = [ ] ;
811811
812- // Fetch contributors from GitHub API
813- async function fetchContributors ( ) {
814- try {
815- const url = `https://api.github.com/repos/${ owner } /${ repo } /contributors` ;
816- const response = await fetch ( url ) ;
812+ // GitHub API headers
813+ const apiHeaders = {
814+ 'Accept' : 'application/vnd.github.v3+json' ,
815+ 'User-Agent' : 'AnimateItNow-Contributors'
816+ } ;
817+
818+ // Fetch all pages of contributors
819+ async function fetchAllContributors ( ) {
820+ let allContributors = [ ] ;
821+ let page = 1 ;
822+ const perPage = 100 ;
823+
824+ while ( true ) {
825+ try {
826+ const url = `https://api.github.com/repos/${ owner } /${ repo } /contributors?per_page=${ perPage } &page=${ page } ` ;
827+ const response = await fetch ( url , { headers : apiHeaders } ) ;
828+
829+ // Check rate limit
830+ const remaining = response . headers . get ( 'X-RateLimit-Remaining' ) ;
831+ const resetTime = response . headers . get ( 'X-RateLimit-Reset' ) ;
832+
833+ if ( response . status === 403 ) {
834+ if ( resetTime ) {
835+ const resetDate = new Date ( parseInt ( resetTime ) * 1000 ) ;
836+ throw new Error ( `GitHub API rate limit exceeded. Please try again after ${ resetDate . toLocaleTimeString ( ) } ` ) ;
837+ }
838+ throw new Error ( `GitHub API error! Status: ${ response . status } . Rate limit may be exceeded.` ) ;
839+ }
817840
818- if ( ! response . ok ) {
819- throw new Error ( `GitHub API error! Status: ${ response . status } ` ) ;
820- }
841+ if ( ! response . ok ) {
842+ throw new Error ( `GitHub API error! Status: ${ response . status } ` ) ;
843+ }
821844
822- const contributors = await response . json ( ) ;
845+ const contributors = await response . json ( ) ;
823846
824- // If no data fetched, use dummy data for demonstration
825- if ( ! Array . isArray ( contributors ) || contributors . length === 0 ) {
826- console . warn (
827- "No data fetched from GitHub. Using dummy data for demonstration."
828- ) ;
829- return getDummyContributors ( ) ;
830- }
847+ if ( ! Array . isArray ( contributors ) || contributors . length === 0 ) {
848+ break ; // No more pages
849+ }
831850
832- return contributors ;
833- } catch ( error ) {
834- console . error ( "Error fetching contributors:" , error ) ;
835- // Return dummy data if fetch fails
836- return getDummyContributors ( ) ;
851+ allContributors = allContributors . concat ( contributors ) ;
852+
853+ // If we got less than perPage, we're on the last page
854+ if ( contributors . length < perPage ) {
855+ break ;
856+ }
857+
858+ page ++ ;
859+
860+ // Safety limit
861+ if ( page > 10 ) break ;
862+ } catch ( error ) {
863+ console . error ( "Error fetching contributors:" , error ) ;
864+ throw error ;
865+ }
837866 }
867+
868+ return allContributors ;
838869 }
839870
840- // Get dummy contributors for demonstration
841- function getDummyContributors ( ) {
842- return [
843- {
844- login : "anuj" ,
845- id : 1 ,
846- avatar_url : "https://via.placeholder.com/100/4f8cff/ffffff?text=A" ,
847- html_url : "https://github.com/anuj" ,
848- contributions : 150 ,
849- type : "User" ,
850- } ,
851- {
852- login : "alice" ,
853- id : 2 ,
854- avatar_url : "https://via.placeholder.com/100/2563eb/ffffff?text=A" ,
855- html_url : "https://github.com/alice" ,
856- contributions : 89 ,
857- type : "User" ,
858- } ,
859- {
860- login : "bob" ,
861- id : 3 ,
862- avatar_url : "https://via.placeholder.com/100/1dc5c8/ffffff?text=B" ,
863- html_url : "https://github.com/bob" ,
864- contributions : 76 ,
865- type : "User" ,
866- } ,
867- {
868- login : "charlie" ,
869- id : 4 ,
870- avatar_url : "https://via.placeholder.com/100/4f8cff/ffffff?text=C" ,
871- html_url : "https://github.com/charlie" ,
872- contributions : 64 ,
873- type : "User" ,
874- } ,
875- {
876- login : "diana" ,
877- id : 5 ,
878- avatar_url : "https://via.placeholder.com/100/2563eb/ffffff?text=D" ,
879- html_url : "https://github.com/diana" ,
880- contributions : 52 ,
881- type : "User" ,
882- } ,
883- {
884- login : "emma" ,
885- id : 6 ,
886- avatar_url : "https://via.placeholder.com/100/1dc5c8/ffffff?text=E" ,
887- html_url : "https://github.com/emma" ,
888- contributions : 41 ,
889- type : "User" ,
890- } ,
891- {
892- login : "frank" ,
893- id : 7 ,
894- avatar_url : "https://via.placeholder.com/100/4f8cff/ffffff?text=F" ,
895- html_url : "https://github.com/frank" ,
896- contributions : 35 ,
897- type : "User" ,
898- } ,
899- {
900- login : "grace" ,
901- id : 8 ,
902- avatar_url : "https://via.placeholder.com/100/2563eb/ffffff?text=G" ,
903- html_url : "https://github.com/grace" ,
904- contributions : 28 ,
905- type : "User" ,
906- } ,
907- ] ;
908- }
909-
910- // Fetch additional user details
911- async function fetchUserDetails ( login ) {
871+ // Fetch contributors from GitHub API with caching
872+ async function fetchContributors ( ) {
873+ const cacheKey = `contributors_${ owner } _${ repo } ` ;
874+ const cacheDuration = 30 * 60 * 1000 ; // 30 minutes
875+ const cachedItem = sessionStorage . getItem ( cacheKey ) ;
876+
877+ // Check cache first
878+ if ( cachedItem ) {
879+ const { timestamp, data } = JSON . parse ( cachedItem ) ;
880+ if ( new Date ( ) . getTime ( ) - timestamp < cacheDuration ) {
881+ console . log ( "📦 Loading contributors from cache" ) ;
882+ return data ;
883+ }
884+ }
885+
912886 try {
913- const url = `https://api.github.com/users/ ${ login } ` ;
914- const response = await fetch ( url ) ;
887+ console . log ( "🔄 Fetching contributors from GitHub API..." ) ;
888+ const contributors = await fetchAllContributors ( ) ;
915889
916- if ( ! response . ok ) {
917- return null ;
890+ if ( ! Array . isArray ( contributors ) || contributors . length === 0 ) {
891+ throw new Error ( "No contributors found in repository" ) ;
918892 }
919893
920- return await response . json ( ) ;
894+ // Cache the data
895+ sessionStorage . setItem ( cacheKey , JSON . stringify ( {
896+ timestamp : new Date ( ) . getTime ( ) ,
897+ data : contributors
898+ } ) ) ;
899+
900+ console . log ( `✅ Fetched ${ contributors . length } contributors` ) ;
901+ return contributors ;
921902 } catch ( error ) {
922- console . error ( `Error fetching user details for ${ login } :` , error ) ;
923- return null ;
903+ console . error ( "Error fetching contributors:" , error ) ;
904+
905+ // Try to use cached data even if expired
906+ if ( cachedItem ) {
907+ const { data } = JSON . parse ( cachedItem ) ;
908+ console . warn ( "⚠️ Using expired cache due to API error" ) ;
909+ return data ;
910+ }
911+
912+ throw error ;
924913 }
925914 }
926915
@@ -960,13 +949,13 @@ <h3 class="contributor-name">${
960949 </div>
961950 <div class="contributor-stat">
962951 <div class="contributor-stat-value">${
963- contributor . public_repos || "N/A "
952+ contributor . public_repos || "- "
964953 } </div>
965954 <div class="contributor-stat-label">Repos</div>
966955 </div>
967956 <div class="contributor-stat">
968957 <div class="contributor-stat-value">${
969- contributor . followers || "N/A "
958+ contributor . followers || "- "
970959 } </div>
971960 <div class="contributor-stat-label">Followers</div>
972961 </div>
@@ -1017,9 +1006,7 @@ <h3 class="contributor-name">${
10171006 } else {
10181007 filteredContributors = contributorsData . filter (
10191008 ( contributor ) =>
1020- contributor . login . toLowerCase ( ) . includes ( searchTerm ) ||
1021- ( contributor . name &&
1022- contributor . name . toLowerCase ( ) . includes ( searchTerm ) )
1009+ contributor . login . toLowerCase ( ) . includes ( searchTerm )
10231010 ) ;
10241011 }
10251012
@@ -1028,23 +1015,38 @@ <h3 class="contributor-name">${
10281015
10291016 // Initialize contributors page
10301017 async function init ( ) {
1031- const contributors = await fetchContributors ( ) ;
1032-
1033- // Fetch additional details for each contributor
1034- const contributorsWithDetails = await Promise . all (
1035- contributors . map ( async ( contributor ) => {
1036- const userDetails = await fetchUserDetails ( contributor . login ) ;
1037- return { ...contributor , ...userDetails } ;
1038- } )
1039- ) ;
1018+ try {
1019+ const contributors = await fetchContributors ( ) ;
10401020
1041- contributorsData = contributorsWithDetails . sort (
1042- ( a , b ) => b . contributions - a . contributions
1043- ) ;
1044- filteredContributors = [ ...contributorsData ] ;
1021+ // Contributors endpoint already includes: login, avatar_url, html_url, contributions, type
1022+ // No need for additional API calls per user
1023+ contributorsData = contributors . sort (
1024+ ( a , b ) => b . contributions - a . contributions
1025+ ) ;
1026+ filteredContributors = [ ...contributorsData ] ;
10451027
1046- updateStats ( contributorsData ) ;
1047- renderContributors ( filteredContributors ) ;
1028+ updateStats ( contributorsData ) ;
1029+ renderContributors ( filteredContributors ) ;
1030+ } catch ( error ) {
1031+ console . error ( "Error initializing contributors:" , error ) ;
1032+ const grid = document . getElementById ( "contributors-grid" ) ;
1033+ if ( grid ) {
1034+ grid . innerHTML = `
1035+ <div class="loading-state" style="text-align: center; padding: 40px;">
1036+ <div style="font-size: 3rem; margin-bottom: 20px;">⚠️</div>
1037+ <div style="font-size: 1.2rem; font-weight: 600; color: #dc3545; margin-bottom: 10px;">Error Loading Contributors</div>
1038+ <div style="font-size: 0.9rem; color: var(--text-light); margin-bottom: 20px;">${ error . message } </div>
1039+ <button onclick="sessionStorage.clear(); location.reload();" style="padding: 10px 20px; background: #6C63FF; color: white; border: none; border-radius: 5px; cursor: pointer;">Retry</button>
1040+ </div>
1041+ ` ;
1042+ }
1043+
1044+ // Show error in stats
1045+ document . getElementById ( "totalContributors" ) . textContent = "0" ;
1046+ document . getElementById ( "totalCommits" ) . textContent = "0" ;
1047+ document . getElementById ( "totalPRs" ) . textContent = "0" ;
1048+ return ;
1049+ }
10481050
10491051 // Set up search functionality
10501052 document
0 commit comments