Skip to content

Commit f86ed3e

Browse files
initial commit
1 parent 8c355d9 commit f86ed3e

File tree

7 files changed

+89
-188
lines changed

7 files changed

+89
-188
lines changed

frontend/components/Api.js

Lines changed: 0 additions & 77 deletions
This file was deleted.

frontend/components/App.js

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import LoginForm from './LoginForm'
55
import Message from './Message'
66
import ArticleForm from './ArticleForm'
77
import Spinner from './Spinner'
8+
import axios from 'axios';
89

910
const articlesUrl = 'http://localhost:9000/api/articles'
1011
const loginUrl = 'http://localhost:9000/api/login'
@@ -34,15 +35,17 @@ export default function App() {
3435
const login = ({ username, password }) => {
3536
setMessage ('');
3637
setSpinnerOn(true);
37-
axios.post (loginURL, {username, password })
38+
39+
axios.post (loginUrl, {username, password })
3840
.then(response => {
3941
const token = response.data.token;
4042
localStorage.setItem('token', token);
4143
setMessage('Login successful!');
4244
redirectToArticles();
45+
getArticles()
4346
})
44-
.catch (error => {
45-
setMessage (' Login failed. Please check your credentials.');
47+
.catch (() => {
48+
setMessage ('Login failed. Please check your credentials.');
4649
})
4750
.finally(() => {
4851
setSpinnerOn(false);
@@ -52,22 +55,24 @@ export default function App() {
5255
const getArticles = () => {
5356
setMessage(''); // Clear any previous messages
5457
setSpinnerOn(true); // Show the spinner while fetching articles
55-
5658
const token = localStorage.getItem('token'); // Retrieve the token from local storage
5759

5860
axios.get(articlesUrl, {
59-
headers: { Authorization: token } // Pass the token in the Authorization header
61+
headers: { Authorization: token }, // Pass the token in the Authorization header
6062
})
61-
.then(response => {
62-
setArticles(response.data); // Update the articles state with the response data
63-
setMessage('Articles retrieved successfully!'); // Set a success message
63+
.then((response) => {
64+
// Log the response to debug its structure
65+
console.log('Response data:', response.data);
66+
setArticles(response.data.articles); // Use the array directly
67+
setMessage(response.data.message);
6468
})
65-
.catch(error => {
69+
.catch((error) => {
70+
console.error('Error fetching articles:', error);
6671
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
72+
setMessage('Session expired. Please log in again.');
73+
redirectToLogin();
6974
} else {
70-
setMessage('Failed to retrieve articles. Please try again.'); // General error message
75+
setMessage('Failed to retrieve articles. Please try again.');
7176
}
7277
})
7378
.finally(() => {
@@ -86,10 +91,12 @@ export default function App() {
8691
headers: { Authorization: token } // Pass the token in the Authorization header
8792
})
8893
.then(response => {
89-
setArticles([...articles, response.data]); // Add the new article to the state
90-
setMessage('Article successfully added!'); // Set a success message
94+
console.log ("postresponse",response);
95+
setArticles([...articles, response.data.article]); // Add the new article to the state
96+
setMessage(response.data.message); // Set a success message
97+
9198
})
92-
.catch(error => {
99+
.catch (() => {
93100
setMessage('Failed to add article. Please try again.'); // Set an error message
94101
})
95102
.finally(() => {
@@ -109,11 +116,11 @@ export default function App() {
109116
})
110117
.then(response => {
111118
setArticles(articles.map(art =>
112-
art.article_id === article_id ? response.data : art // Replace updated article
119+
art.article_id === article_id ? response.data.article : art // Replace updated article
113120
));
114-
setMessage('Article successfully updated!'); // Set a success message
121+
setMessage(response.data.message); // Set a success message
115122
})
116-
.catch(error => {
123+
.catch(()=> {
117124
setMessage('Failed to update article. Please try again.'); // Set an error message
118125
})
119126
.finally(() => {
@@ -131,11 +138,11 @@ export default function App() {
131138
axios.delete(`${articlesUrl}/${article_id}`, {
132139
headers: { Authorization: token } // Pass the token in the Authorization header
133140
})
134-
.then(() => {
141+
.then((response) => {
135142
setArticles(articles.filter(art => art.article_id !== article_id)); // Remove the deleted article
136-
setMessage('Article successfully deleted!'); // Set a success message
143+
setMessage(response.data.message); // Set a success message
137144
})
138-
.catch(error => {
145+
.catch(() => {
139146
setMessage('Failed to delete article. Please try again.'); // Set an error message
140147
})
141148
.finally(() => {
@@ -160,15 +167,17 @@ export default function App() {
160167
<Route path="articles" element={
161168
<>
162169
<ArticleForm
163-
currentArticleId={currentArticleId}
170+
currentArticle = {articles.find(art=> art.article_id == currentArticleId)}
164171
postArticle={postArticle}
165172
updateArticle={updateArticle}
166173
setCurrentArticleId={setCurrentArticleId}
167174
/>
168175
<Articles
169176
articles={articles}
177+
getArticles={getArticles}
170178
deleteArticle={deleteArticle}
171179
setCurrentArticleId={setCurrentArticleId}
180+
currentArticleId={currentArticleId}
172181
/>
173182
</>
174183
} />

frontend/components/ArticleForm.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,13 @@ export default function ArticleForm(props) {
3434
postArticle(values);
3535
}
3636
setValues(initialFormValues);
37-
setCurrentArticleId(null);
37+
setCurrentArticleId();
3838
};
39-
}
4039

4140
const isDisabled = () => {
4241
// Assuming `values` contains the form data as an object, e.g.,
4342
// { title: "some text", body: "some content" }
44-
45-
if (!values.title || !values.body) {
43+
if (!values.title || !values.text || !values.topic) {
4644
// If either title or body is empty, disable the form
4745
return true;
4846
}
@@ -80,11 +78,11 @@ export default function ArticleForm(props) {
8078
</select>
8179
<div className="button-group">
8280
<button disabled={isDisabled()} id="submitArticle">Submit</button>
83-
<button onClick={ () => setCurrentArticleID(null)}>Cancel edit</button>
81+
<button onClick={ () => setCurrentArticleId(null)}>Cancel edit</button>
8482
</div>
8583
</form>
8684
)
87-
85+
}
8886

8987
// 🔥 No touchy: ArticleForm expects the following props exactly:
9088
ArticleForm.propTypes = {

frontend/components/Articles.js

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,45 @@ import React, { useEffect } from 'react';
22
import { Navigate } from 'react-router-dom';
33
import PT from 'prop-types';
44

5-
export default function Articles({
6-
articles,
7-
getArticles,
8-
deleteArticle,
9-
setCurrentArticleId,
10-
}) {
5+
export default function Articles({ articles, getArticles, deleteArticle, setCurrentArticleId, currentArticleId}) {
116
const token = localStorage.getItem('token');
127

13-
// If no token exists, redirect to login
14-
if (!token) {
15-
return <Navigate to="/login" />;
8+
// Ensure token validation
9+
if (!token || token === 'undefined' || token === '') {
10+
return <Navigate to="/" />;
1611
}
1712

18-
// Fetch articles on first render
1913
useEffect(() => {
20-
getArticles();
21-
}, [getArticles]);
14+
if (token) {
15+
getArticles();
16+
}
17+
}, [token]);
18+
19+
console.log (articles);
2220

2321
return (
2422
<div className="articles">
2523
<h2>Articles</h2>
26-
{
27-
!articles.length
28-
? <p>No articles yet</p>
29-
: articles.map(art => (
30-
<div className="article" key={art.article_id}>
31-
<div>
32-
<h3>{art.title}</h3>
33-
<p>{art.text}</p>
34-
<p>Topic: {art.topic}</p>
35-
</div>
36-
<div>
37-
<button onClick={() => setCurrentArticleId(art.article_id)}>
38-
Edit
39-
</button>
40-
<button onClick={() => deleteArticle(art.article_id)}>
41-
Delete
42-
</button>
43-
</div>
44-
</div>
45-
))
46-
}
24+
{articles.length === 0 ? (
25+
<p>No articles yet</p>
26+
) : (
27+
articles.map((art) => (
28+
<div key={art.article_id} className="article">
29+
<h3>{art.title}</h3>
30+
<p>{art.text}</p>
31+
<p>Topic: {art.topic}</p>
32+
<button onClick={() => setCurrentArticleId(art.article_id)}>Edit</button>
33+
<button onClick={() => deleteArticle(art.article_id)}>Delete</button>
34+
</div>
35+
))
36+
)}
4737
</div>
4838
);
4939
}
5040

41+
5142
Articles.propTypes = {
52-
articles: PT.arrayOf(PT.shape({ // the array can be empty
43+
articles: PT.arrayOf(PT.shape({
5344
article_id: PT.number.isRequired,
5445
title: PT.string.isRequired,
5546
text: PT.string.isRequired,
@@ -58,5 +49,5 @@ Articles.propTypes = {
5849
getArticles: PT.func.isRequired,
5950
deleteArticle: PT.func.isRequired,
6051
setCurrentArticleId: PT.func.isRequired,
61-
currentArticleId: PT.number, // can be undefined or null
52+
currentArticleId: PT.number,
6253
};

frontend/components/Message.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@ const StyledMessage = styled.div`
1212
`
1313

1414
export default function Message({ message }) {
15-
return (
16-
<StyledMessage key={message} id="message">
17-
{message}
18-
</StyledMessage>
19-
)
15+
return message ? <StyledMessage id="message">{message}</StyledMessage> : null;
2016
}
2117

18+
2219
Message.propTypes = {
2320
message: PT.string.isRequired,
2421
}

0 commit comments

Comments
 (0)