@@ -18,76 +18,163 @@ export default function App() {
1818
1919 // ✨ Research `useNavigate` in React Router v.6
2020 const navigate = useNavigate ( )
21- const redirectToLogin = ( ) => { /* ✨ implement */ }
22- const redirectToArticles = ( ) => { /* ✨ implement */ }
21+ const redirectToLogin = ( ) => { navigate ( '/' ) ;
2322
24- const logout = ( ) => {
25- // ✨ implement
26- // If a token is in local storage it should be removed,
27- // and a message saying "Goodbye!" should be set in its proper state.
28- // In any case, we should redirect the browser back to the login screen,
29- // using the helper above.
30- }
23+ }
24+ const redirectToArticles = ( ) => {
25+ navigate ( '/articles' ) ;
26+ } ;
3127
28+ const logout = ( ) => {
29+ localStorage . removeItem ( 'token' ) ;
30+ setMessage ( 'Goodbye!' ) ;
31+ redirectToLogin ( ) ;
32+ } ;
33+
3234 const login = ( { username, password } ) => {
33- // ✨ implement
34- // We should flush the message state, turn on the spinner
35- // and launch a request to the proper endpoint.
36- // On success, we should set the token to local storage in a 'token' key,
37- // put the server success message in its proper state, and redirect
38- // to the Articles screen. Don't forget to turn off the spinner!
35+ setMessage ( '' ) ;
36+ setSpinnerOn ( true ) ;
37+ axios . post ( loginURL , { username, password } )
38+ . then ( response => {
39+ const token = response . data . token ;
40+ localStorage . setItem ( 'token' , token ) ;
41+ setMessage ( 'Login successful!' ) ;
42+ redirectToArticles ( ) ;
43+ } )
44+ . catch ( error => {
45+ setMessage ( ' Login failed. Please check your credentials.' ) ;
46+ } )
47+ . finally ( ( ) => {
48+ setSpinnerOn ( false ) ;
49+ } )
3950 }
4051
4152 const getArticles = ( ) => {
42- // ✨ implement
43- // We should flush the message state, turn on the spinner
44- // and launch an authenticated request to the proper endpoint.
45- // On success, we should set the articles in their proper state and
46- // put the server success message in its proper state.
47- // If something goes wrong, check the status of the response:
48- // if it's a 401 the token might have gone bad, and we should redirect to login.
49- // Don't forget to turn off the spinner!
50- }
53+ setMessage ( '' ) ; // Clear any previous messages
54+ setSpinnerOn ( true ) ; // Show the spinner while fetching articles
55+
56+ const token = localStorage . getItem ( 'token' ) ; // Retrieve the token from local storage
57+
58+ axios . get ( articlesUrl , {
59+ headers : { Authorization : token } // Pass the token in the Authorization header
60+ } )
61+ . then ( response => {
62+ setArticles ( response . data ) ; // Update the articles state with the response data
63+ setMessage ( 'Articles retrieved successfully!' ) ; // Set a success message
64+ } )
65+ . catch ( error => {
66+ if ( error . response ?. status === 401 ) {
67+ setMessage ( 'Session expired. Please log in again.' ) ; // Set a message for unauthorized access
68+ redirectToLogin ( ) ; // Redirect to the login page
69+ } else {
70+ setMessage ( 'Failed to retrieve articles. Please try again.' ) ; // General error message
71+ }
72+ } )
73+ . finally ( ( ) => {
74+ setSpinnerOn ( false ) ; // Hide the spinner after the request is complete
75+ } ) ;
76+ } ;
77+
5178
5279 const postArticle = article => {
53- // ✨ implement
54- // The flow is very similar to the `getArticles` function.
55- // You'll know what to do! Use log statements or breakpoints
56- // to inspect the response from the server.
57- }
80+ setMessage ( '' ) ; // Clear any previous messages
81+ setSpinnerOn ( true ) ; // Show the spinner while making the request
82+
83+ const token = localStorage . getItem ( 'token' ) ; // Retrieve the token
84+
85+ axios . post ( articlesUrl , article , {
86+ headers : { Authorization : token } // Pass the token in the Authorization header
87+ } )
88+ . then ( response => {
89+ setArticles ( [ ...articles , response . data ] ) ; // Add the new article to the state
90+ setMessage ( 'Article successfully added!' ) ; // Set a success message
91+ } )
92+ . catch ( error => {
93+ setMessage ( 'Failed to add article. Please try again.' ) ; // Set an error message
94+ } )
95+ . finally ( ( ) => {
96+ setSpinnerOn ( false ) ; // Hide the spinner after the request is complete
97+ } ) ;
98+ } ;
99+
58100
59101 const updateArticle = ( { article_id, article } ) => {
60- // ✨ implement
61- // You got this!
62- }
102+ setMessage ( '' ) ; // Clear any previous messages
103+ setSpinnerOn ( true ) ; // Show the spinner while making the request
104+
105+ const token = localStorage . getItem ( 'token' ) ; // Retrieve the token
106+
107+ axios . put ( `${ articlesUrl } /${ article_id } ` , article , {
108+ headers : { Authorization : token } // Pass the token in the Authorization header
109+ } )
110+ . then ( response => {
111+ setArticles ( articles . map ( art =>
112+ art . article_id === article_id ? response . data : art // Replace updated article
113+ ) ) ;
114+ setMessage ( 'Article successfully updated!' ) ; // Set a success message
115+ } )
116+ . catch ( error => {
117+ setMessage ( 'Failed to update article. Please try again.' ) ; // Set an error message
118+ } )
119+ . finally ( ( ) => {
120+ setSpinnerOn ( false ) ; // Hide the spinner after the request is complete
121+ } ) ;
122+ } ;
123+
63124
64125 const deleteArticle = article_id => {
65- // ✨ implement
66- }
126+ setMessage ( '' ) ; // Clear any previous messages
127+ setSpinnerOn ( true ) ; // Show the spinner while making the request
128+
129+ const token = localStorage . getItem ( 'token' ) ; // Retrieve the token
130+
131+ axios . delete ( `${ articlesUrl } /${ article_id } ` , {
132+ headers : { Authorization : token } // Pass the token in the Authorization header
133+ } )
134+ . then ( ( ) => {
135+ setArticles ( articles . filter ( art => art . article_id !== article_id ) ) ; // Remove the deleted article
136+ setMessage ( 'Article successfully deleted!' ) ; // Set a success message
137+ } )
138+ . catch ( error => {
139+ setMessage ( 'Failed to delete article. Please try again.' ) ; // Set an error message
140+ } )
141+ . finally ( ( ) => {
142+ setSpinnerOn ( false ) ; // Hide the spinner after the request is complete
143+ } ) ;
144+ } ;
145+
67146
68147 return (
69- // ✨ fix the JSX: `Spinner`, `Message`, `LoginForm`, `ArticleForm` and `Articles` expect props ❗
70148 < >
71- < Spinner />
72- < Message />
149+ < Spinner on = { spinnerOn } />
150+ < Message message = { message } />
73151 < button id = "logout" onClick = { logout } > Logout from app</ button >
74- < div id = "wrapper" style = { { opacity : spinnerOn ? "0.25" : "1" } } > { /* <-- do not change this line */ }
152+ < div id = "wrapper" style = { { opacity : spinnerOn ? "0.25" : "1" } } >
75153 < h1 > Advanced Web Applications</ h1 >
76154 < nav >
77155 < NavLink id = "loginScreen" to = "/" > Login</ NavLink >
78156 < NavLink id = "articlesScreen" to = "/articles" > Articles</ NavLink >
79157 </ nav >
80158 < Routes >
81- < Route path = "/" element = { < LoginForm /> } />
159+ < Route path = "/" element = { < LoginForm login = { login } /> } />
82160 < Route path = "articles" element = {
83161 < >
84- < ArticleForm />
85- < Articles />
162+ < ArticleForm
163+ currentArticleId = { currentArticleId }
164+ postArticle = { postArticle }
165+ updateArticle = { updateArticle }
166+ setCurrentArticleId = { setCurrentArticleId }
167+ />
168+ < Articles
169+ articles = { articles }
170+ deleteArticle = { deleteArticle }
171+ setCurrentArticleId = { setCurrentArticleId }
172+ />
86173 </ >
87174 } />
88175 </ Routes >
89176 < footer > Bloom Institute of Technology 2024</ footer >
90177 </ div >
91178 </ >
92- )
179+ ) ;
93180}
0 commit comments