-
Notifications
You must be signed in to change notification settings - Fork 0
/
App.js
183 lines (172 loc) · 5.9 KB
/
App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import React, { useState } from 'react'
import { NavLink, Routes, Route, useNavigate } from 'react-router-dom'
import Articles from './Articles'
import LoginForm from './LoginForm'
import Message from './Message'
import ArticleForm from './ArticleForm'
import Spinner from './Spinner'
import axiosWithAuth from '../axios'
const articlesUrl = 'http://localhost:9000/api/articles'
const loginUrl = 'http://localhost:9000/api/login'
export default function App() {
// ✨ MVP can be achieved with these states
const [message, setMessage] = useState('')
const [articles, setArticles] = useState([])
const [currentArticleId, setCurrentArticleId] = useState()
const [spinnerOn, setSpinnerOn] = useState(false)
// ✨ Research `useNavigate` in React Router v.6
const navigate = useNavigate()
const redirectToLogin = () => {
navigate('/');
}
const redirectToArticles = () => {
navigate('/articles');
}
const logout = () => {
// ✨ implement
// If a token is in local storage it should be removed,
// and a message saying "Goodbye!" should be set in its proper state.
// In any case, we should redirect the browser back to the login screen,
// using the helper above.
localStorage.removeItem('token');
setMessage('Goodbye!');
redirectToLogin();
}
const login = ({ username, password }) => {
// ✨ implement
// We should flush the message state, turn on the spinner
// and launch a request to the proper endpoint.
// On success, we should set the token to local storage in a 'token' key,
// put the server success message in its proper state, and redirect
// to the Articles screen. Don't forget to turn off the spinner!
setMessage('');
setSpinnerOn(true);
axiosWithAuth().post('/login', { username, password })
.then(resp => {
localStorage.setItem('token', resp.data.token);
setMessage(resp.data.message);
redirectToArticles();
setSpinnerOn(false)
})
.catch(err => {
console.error(err);
setSpinnerOn(false);
})
}
const getArticles = () => {
// ✨ implement
// We should flush the message state, turn on the spinner
// and launch an authenticated request to the proper endpoint.
// On success, we should set the articles in their proper state and
// put the server success message in its proper state.
// If something goes wrong, check the status of the response:
// if it's a 401 the token might have gone bad, and we should redirect to login.
// Don't forget to turn off the spinner!
setMessage('');
setSpinnerOn(true);
axiosWithAuth().get('/articles')
.then(resp => {
setArticles(resp.data.articles);
setMessage(resp.data.message);
setSpinnerOn(false);
})
.catch(err => {
console.error(err)
navigate('/');
setSpinnerOn(false)
})
}
const postArticle = article => {
// ✨ implement
// The flow is very similar to the `getArticles` function.
// You'll know what to do! Use log statements or breakpoints
// to inspect the response from the server.
setMessage('');
setSpinnerOn(true);
axiosWithAuth().post('/articles', article)
.then(resp => {
setArticles([...articles, resp.data.article]);
setMessage(resp.data.message);
setSpinnerOn(false)
})
.catch(err => {
console.error(err)
navigate('/');
setSpinnerOn(false)
})
}
const updateArticle = ({ article_id, article }) => {
// ✨ implement
// You got this!
setMessage('');
setSpinnerOn(true)
axiosWithAuth().put(`/articles/${article_id}`, article)
.then(resp => {
setArticles((prevArticles) => {
return prevArticles.map(art =>
art.article_id === article_id ? resp.data.article : art
)
});
setMessage(resp.data.message);
setSpinnerOn(false)
})
.catch(err => {
console.error(err);
setSpinnerOn(false)
})
}
const deleteArticle = article_id => {
// ✨ implement
setMessage('');
setSpinnerOn(true);
axiosWithAuth().delete(`/articles/${article_id}`)
.then(resp => {
setArticles(articles.filter(article => (article.article_id !== article_id)))
setMessage(resp.data.message);
setSpinnerOn(false)
})
.catch(err => {
console.error(err);
setSpinnerOn(false)
})
}
const currentArticle = articles ? articles.find(article => article.article_id === currentArticleId) : null;
return (
// ✨ fix the JSX: `Spinner`, `Message`, `LoginForm`, `ArticleForm` and `Articles` expect props ❗
<>
<Spinner on={spinnerOn} />
<Message message={message}/>
<button id="logout" onClick={logout}>Logout from app</button>
<div id="wrapper" style={{ opacity: spinnerOn ? "0.25" : "1" }}> {/* <-- do not change this line */}
<h1>Advanced Web Applications</h1>
<nav>
<NavLink id="loginScreen" to="/">Login</NavLink>
<NavLink id="articlesScreen" to="/articles">Articles</NavLink>
</nav>
<Routes>
<Route path="/" element={<LoginForm login={login} />} />
<Route path="articles" element={
<>
<ArticleForm
postArticle={postArticle}
updateArticle={updateArticle}
currentArticleId={currentArticleId}
setCurrentArticleId={setCurrentArticleId}
currentArticle={currentArticle}
/>
<Articles
articles={articles}
getArticles={getArticles}
updateArticle={updateArticle}
deleteArticle={deleteArticle}
currentArticleId={currentArticleId}
setCurrentArticleId={setCurrentArticleId}
/>
</>
} />
</Routes>
<footer>Bloom Institute of Technology 2022</footer>
</div>
</>
)
}