1- import { createContext , useContext , useState , useCallback } from 'react'
2- import { fetchOrg , fetchRepos , fetchContributors , fetchIssues , fetchRateLimit } from '../services/github'
1+ import { createContext , useContext , useState , useCallback , useEffect } from 'react'
2+ import { fetchOrg , fetchRepos , fetchContributors , fetchIssues , } from '../services/github'
33import { buildAnalyticalModel } from '../services/analytics'
44
55const Ctx = createContext ( null )
66
7+ function getStoredRateLimit ( ) {
8+ const stored = localStorage . getItem ( 'oe_rate_limit' )
9+
10+ if ( ! stored ) return null
11+
12+ try {
13+ const data = JSON . parse ( stored )
14+
15+ if ( Date . now ( ) > data . reset * 1000 ) {
16+ localStorage . removeItem ( 'oe_rate_limit' )
17+ return null
18+ }
19+
20+ return data
21+ } catch {
22+ localStorage . removeItem ( 'oe_rate_limit' )
23+ return null
24+ }
25+ }
26+
727export function AppProvider ( { children } ) {
8- const [ pat , setPat ] = useState ( ( ) => localStorage . getItem ( 'oe_pat' ) || '' )
9- const [ orgs , setOrgs ] = useState ( [ ] )
10- const [ model , setModel ] = useState ( null )
28+ const [ pat , setPat ] = useState ( ( ) => localStorage . getItem ( 'oe_pat' ) || '' )
29+ const [ orgs , setOrgs ] = useState ( [ ] )
30+ const [ model , setModel ] = useState ( null )
1131 const [ issuesData , setIssuesData ] = useState ( { } )
12- const [ rateLimit , setRateLimit ] = useState ( null )
13- const [ loading , setLoading ] = useState ( false )
14- const [ loadMsg , setLoadMsg ] = useState ( '' )
32+ const [ rateLimit , setRateLimit ] = useState ( getStoredRateLimit )
33+ const [ loading , setLoading ] = useState ( false )
34+ const [ loadMsg , setLoadMsg ] = useState ( '' )
1535 const [ govLoading , setGovLoading ] = useState ( false )
16- const [ error , setError ] = useState ( '' )
36+ const [ error , setError ] = useState ( '' )
37+
38+ useEffect ( ( ) => {
39+ const handler = e => {
40+ setRateLimit ( e . detail )
41+ localStorage . setItem ( 'oe_rate_limit' , JSON . stringify ( e . detail ) )
42+ }
43+
44+ window . addEventListener ( 'rate-limit-update' , handler )
45+
46+ return ( ) => {
47+ window . removeEventListener ( 'rate-limit-update' , handler )
48+ }
49+ } , [ ] )
50+
51+ useEffect ( ( ) => {
52+ if ( ! rateLimit ?. reset ) return
53+
54+ const timeout = setTimeout ( ( ) => {
55+ localStorage . removeItem ( 'oe_rate_limit' )
56+ setRateLimit ( null )
57+ } , Math . max ( 0 , rateLimit . reset * 1000 - Date . now ( ) ) )
58+
59+ return ( ) => clearTimeout ( timeout )
60+ } , [ rateLimit ] )
1761
1862 const savePat = useCallback ( token => {
1963 setPat ( token )
@@ -25,7 +69,7 @@ export function AppProvider({ children }) {
2569 setLoading ( true ) ; setError ( '' ) ; setModel ( null ) ; setOrgs ( [ ] ) ; setIssuesData ( { } )
2670 try {
2771 setLoadMsg ( 'Fetching organization metadata...' )
28- const orgRes = await Promise . allSettled ( orgNames . map ( n => fetchOrg ( n , pat ) ) )
72+ const orgRes = await Promise . allSettled ( orgNames . map ( n => fetchOrg ( n , pat ) ) )
2973 const validOrgs = orgRes . filter ( r => r . status === 'fulfilled' ) . map ( r => r . value )
3074 if ( ! validOrgs . length ) throw new Error ( 'No valid organizations found. Check the names and try again.' )
3175 setOrgs ( validOrgs )
@@ -50,11 +94,9 @@ export function AppProvider({ children }) {
5094 setLoadMsg ( 'Building analytical data model...' )
5195 setModel ( buildAnalyticalModel ( validOrgs , reposPerOrg , contribsPerRepo ) )
5296
53- const rl = await fetchRateLimit ( pat )
54- if ( rl ) setRateLimit ( rl )
5597
5698 // Save to recent searches
57- const prev = JSON . parse ( localStorage . getItem ( 'oe_recent' ) || '[]' )
99+ const prev = JSON . parse ( localStorage . getItem ( 'oe_recent' ) || '[]' )
58100 const entry = orgNames . join ( ', ' )
59101 localStorage . setItem ( 'oe_recent' , JSON . stringify ( [ ...new Set ( [ entry , ...prev ] ) ] . slice ( 0 , 6 ) ) )
60102 return true
@@ -72,7 +114,7 @@ export function AppProvider({ children }) {
72114 const runAudit = useCallback ( async ( ) => {
73115 if ( ! model || govLoading ) return
74116 setGovLoading ( true )
75- const map = { }
117+ const map = { }
76118 const repos = model . allRepos . slice ( 0 , 15 )
77119
78120 // Batches of 5 using Promise.allSettled
0 commit comments