@@ -19,6 +19,10 @@ function App() {
1919 const [ cookies , setCookies ] = useState ( null ) ;
2020 const [ cookiesLoading , setCookiesLoading ] = useState ( true ) ;
2121 const [ cookiesError , setCookiesError ] = useState ( null ) ;
22+ const [ user , setUser ] = useState ( null ) ;
23+ const [ userLoading , setUserLoading ] = useState ( true ) ;
24+ const [ userError , setUserError ] = useState ( null ) ;
25+ const [ needsLogin , setNeedsLogin ] = useState ( false ) ;
2226
2327 // Helper: decode percent-encoded cookie values safely
2428 const safeDecode = ( val ) => {
@@ -63,6 +67,58 @@ function App() {
6367 } ) ;
6468 } , [ ] ) ;
6569
70+ // Fetch user data with auth refresh logic
71+ useEffect ( ( ) => {
72+ const fetchUser = async ( ) => {
73+ try {
74+ // Try to fetch user data
75+ const userRes = await fetch ( buildApiPath ( "/api/user" ) , {
76+ credentials : "include" ,
77+ } ) ;
78+
79+ // If unauthorized, try to refresh the token
80+ if ( userRes . status === 401 ) {
81+ const refreshRes = await fetch ( buildApiPath ( "/auth/refresh" ) , {
82+ credentials : "include" ,
83+ } ) ;
84+
85+ // If refresh succeeded, retry fetching user data
86+ if ( refreshRes . ok ) {
87+ const retryRes = await fetch ( buildApiPath ( "/api/user" ) , {
88+ credentials : "include" ,
89+ } ) ;
90+
91+ if ( retryRes . ok ) {
92+ const data = await retryRes . json ( ) ;
93+ setUser ( data ) ;
94+ setUserLoading ( false ) ;
95+ return ;
96+ }
97+ }
98+
99+ // If refresh failed or retry failed, user needs to login
100+ setNeedsLogin ( true ) ;
101+ setUserLoading ( false ) ;
102+ return ;
103+ }
104+
105+ // If the response was ok, parse and set user data
106+ if ( userRes . ok ) {
107+ const data = await userRes . json ( ) ;
108+ setUser ( data ) ;
109+ setUserLoading ( false ) ;
110+ } else {
111+ throw new Error ( "Network response was not ok" ) ;
112+ }
113+ } catch ( err ) {
114+ setUserError ( err . message ) ;
115+ setUserLoading ( false ) ;
116+ }
117+ } ;
118+
119+ fetchUser ( ) ;
120+ } , [ ] ) ;
121+
66122 return (
67123 < >
68124 < h1 > J26 Infra test and demo</ h1 >
@@ -149,6 +205,69 @@ function App() {
149205 </ tbody >
150206 </ table >
151207 ) }
208+ < h2 > Call /api/user</ h2 >
209+ { userLoading && < p > Loading...</ p > }
210+ { userError && < p style = { { color : "red" } } > Error: { userError } </ p > }
211+ { needsLogin && (
212+ < button
213+ type = "button"
214+ onClick = { ( ) => {
215+ const currentPage = encodeURIComponent ( window . location . href ) ;
216+ window . location . href = buildApiPath (
217+ `/auth/login?redirect_uri=${ currentPage } `
218+ ) ;
219+ } }
220+ style = { {
221+ padding : "10px 20px" ,
222+ fontSize : "16px" ,
223+ cursor : "pointer" ,
224+ backgroundColor : "#007bff" ,
225+ color : "white" ,
226+ border : "none" ,
227+ borderRadius : "4px" ,
228+ marginTop : "1em" ,
229+ } }
230+ >
231+ Login
232+ </ button >
233+ ) }
234+ { user && (
235+ < table style = { { borderCollapse : "collapse" , marginTop : "1em" } } >
236+ < thead >
237+ < tr >
238+ < th style = { { border : "1px solid #ccc" , padding : "8px" } } > Key</ th >
239+ < th style = { { border : "1px solid #ccc" , padding : "8px" } } >
240+ Value
241+ </ th >
242+ </ tr >
243+ </ thead >
244+ < tbody >
245+ { Object . entries ( user ) . map ( ( [ key , value ] ) => (
246+ < tr key = { key } >
247+ < td
248+ style = { {
249+ border : "1px solid #ccc" ,
250+ padding : "8px" ,
251+ fontWeight : "bold" ,
252+ } }
253+ >
254+ { key }
255+ </ td >
256+ < td
257+ style = { {
258+ border : "1px solid #ccc" ,
259+ padding : "8px" ,
260+ textAlign : "left" ,
261+ wordBreak : "break-all" ,
262+ } }
263+ >
264+ { Array . isArray ( value ) ? value . join ( ", " ) : String ( value ) }
265+ </ td >
266+ </ tr >
267+ ) ) }
268+ </ tbody >
269+ </ table >
270+ ) }
152271 </ >
153272 ) ;
154273}
0 commit comments