@@ -33,8 +33,14 @@ import { useGitHubData } from "../../hooks/useGitHubData";
3333import type { GitHubItem } from "../../hooks/useGitHubData" ;
3434
3535const ROWS_PER_PAGE = 10 ;
36+ const LOOKUP_HISTORY_KEY = "github-tracker-lookup-history" ;
3637const stateOptions = [ "all" , "open" , "closed" , "merged" ] as const ;
3738
39+ interface LookupHistoryItem {
40+ username : string ;
41+ searchedAt : string ;
42+ }
43+
3844const formatDate = ( dateString : string ) : string =>
3945 new Intl . DateTimeFormat ( "en" , {
4046 month : "short" ,
@@ -70,6 +76,15 @@ const getStatusIcon = (item: GitHubItem) => {
7076 return < IssueOpenedIcon size = { 18 } className = "icon-issue-open" /> ;
7177} ;
7278
79+ const getLookupHistory = ( ) : LookupHistoryItem [ ] => {
80+ try {
81+ const savedHistory = localStorage . getItem ( LOOKUP_HISTORY_KEY ) ;
82+ return savedHistory ? JSON . parse ( savedHistory ) : [ ] ;
83+ } catch {
84+ return [ ] ;
85+ }
86+ } ;
87+
7388const Tracker : React . FC = ( ) => {
7489 const theme = useTheme ( ) ;
7590 const {
@@ -99,6 +114,11 @@ const Tracker: React.FC = () => {
99114 const [ selectedRepo , setSelectedRepo ] = useState ( "" ) ;
100115 const [ startDate , setStartDate ] = useState ( "" ) ;
101116 const [ endDate , setEndDate ] = useState ( "" ) ;
117+ const [ lookupHistory , setLookupHistory ] = useState < LookupHistoryItem [ ] > ( [ ] ) ;
118+
119+ useEffect ( ( ) => {
120+ setLookupHistory ( getLookupHistory ( ) ) ;
121+ } , [ ] ) ;
102122
103123 useEffect ( ( ) => {
104124 if ( username ) {
@@ -158,10 +178,37 @@ const Tracker: React.FC = () => {
158178 setPrFilter ( "all" ) ;
159179 } ;
160180
161- const handleSubmit = ( e : React . FormEvent < HTMLFormElement > ) : void => {
181+ const saveLookupHistory = ( nextUsername : string ) => {
182+ const normalizedUsername = nextUsername . trim ( ) ;
183+
184+ if ( ! normalizedUsername ) return ;
185+
186+ const nextHistory = [
187+ { username : normalizedUsername , searchedAt : new Date ( ) . toISOString ( ) } ,
188+ ...lookupHistory . filter (
189+ ( item ) => item . username . toLowerCase ( ) !== normalizedUsername . toLowerCase ( )
190+ ) ,
191+ ] . slice ( 0 , 5 ) ;
192+
193+ setLookupHistory ( nextHistory ) ;
194+ localStorage . setItem ( LOOKUP_HISTORY_KEY , JSON . stringify ( nextHistory ) ) ;
195+ } ;
196+
197+ const handleSubmit = async ( e : React . FormEvent < HTMLFormElement > ) : Promise < void > => {
162198 e . preventDefault ( ) ;
163199 setPage ( 0 ) ;
164- fetchData ( username , 1 , ROWS_PER_PAGE ) ;
200+ saveLookupHistory ( username ) ;
201+ await fetchData ( username , 1 , ROWS_PER_PAGE ) ;
202+ } ;
203+
204+ const handleHistorySelect = async ( historyUsername : string ) => {
205+ setUsername ( historyUsername ) ;
206+ setPage ( 0 ) ;
207+
208+ if ( token ) {
209+ saveLookupHistory ( historyUsername ) ;
210+ await fetchData ( historyUsername , 1 , ROWS_PER_PAGE ) ;
211+ }
165212 } ;
166213
167214 const hasData = issues . length > 0 || prs . length > 0 ;
@@ -245,6 +292,25 @@ const Tracker: React.FC = () => {
245292 >
246293 { loading ? "Fetching activity..." : "Fetch activity" }
247294 </ Button >
295+
296+ { lookupHistory . length > 0 && (
297+ < Box >
298+ < Typography color = "text.secondary" fontSize = { 13 } fontWeight = { 700 } sx = { { mb : 1 } } >
299+ Recent username history
300+ </ Typography >
301+ < Stack direction = "row" spacing = { 1 } flexWrap = "wrap" useFlexGap >
302+ { lookupHistory . map ( ( item ) => (
303+ < Chip
304+ key = { `${ item . username } -${ item . searchedAt } ` }
305+ label = { `${ item . username } · ${ formatDate ( item . searchedAt ) } ` }
306+ clickable
307+ variant = "outlined"
308+ onClick = { ( ) => handleHistorySelect ( item . username ) }
309+ />
310+ ) ) }
311+ </ Stack >
312+ </ Box >
313+ ) }
248314 </ Stack >
249315 </ Paper >
250316 </ Stack >
0 commit comments