Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/Steven90411/Blog_Project
Browse files Browse the repository at this point in the history
…into develop
  • Loading branch information
Steven90411 committed Sep 5, 2024
2 parents fd9220c + 73fb247 commit 4462c94
Show file tree
Hide file tree
Showing 46 changed files with 879 additions and 557 deletions.
2 changes: 2 additions & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v2.1.9/css/unicons.css">
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Expand Down Expand Up @@ -30,6 +31,7 @@
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

<div id="root"></div>
<!--
This HTML file is a template.
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const App = () => {
<Routes>
<Route path='/ChangePassword' element={<MainLayout><ChangePassword/></MainLayout>}/>
<Route path="/" element={<MainLayout><Index /></MainLayout>} />
<Route path="/login" element={<LoginPage />} />
<Route path="/login" element={<MainLayout><LoginPage /></MainLayout>} />
<Route path="/register" element={<MainLayout><Register /></MainLayout>} />
<Route path="/test1" element={<MainLayout><Test1 /></MainLayout>} />
<Route path="/forgot-password" element={<MainLayout><ForgotPasswordPage /></MainLayout>} />
Expand Down
33 changes: 17 additions & 16 deletions frontend/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UserContext } from './UserContext';

const Header = () => {
//const [username, setUsername] = useState('');
// const [userImage, setUserImage] = useState('');
// const [userImage, setUserImage] = useState('');
const location = useLocation();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const { user, setUser } = useContext(UserContext);
Expand Down Expand Up @@ -59,59 +59,60 @@ const Header = () => {

useEffect(() => {
const fetchUserInfo = async () => {
const token = localStorage.getItem('token');
const token = localStorage.getItem('token'); // 從本地存儲獲取 token
if (token) {
try {
// const response = await fetch('http://niceblog.myvnc.com:8080/blog/api/protected-endpoint', {
const response = await fetch('http://localhost:8080/blog/api/protected-endpoint', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Authorization': `Bearer ${token}`, // 將 token 作為 Authorization header 發送
},
});

if (response.ok) {
const data = await response.json();
setUser({
username: data.username || '访客1',
userImage: data.userImage || '/Image/GG', // 设置默认头像
userImage: data.userImage || '/Image/GG', // 設置默認頭像
email: data.email,
id: data.id
id: data.id,
password: data.password
});
console.log(data)
console.log('id is ',data.id)
console.log('data at header is ',data);
} else if (response.status === 401) {
// 如果收到 401 响应,检查是否有新的 token
// 如果收到 401 響應,檢查是否有新的 token
const data = await response.json();
if (data.token) {
// 更新本地存储中的 token
// 更新本地存儲中的 token
localStorage.setItem('token', data.token);

// 使用新的 token 重新发起请求
return fetchUserInfo(); // 递归调用以重试请求
// 使用新的 token 重新發起請求
return fetchUserInfo(); // 遞歸調用以重試請求
} else {
setUser({
username: null,
userImage: '/Image/GG' // 设置默认头像
userImage: '/Image/GG' // 設置默認頭像
});
}
} else {
setUser({
username: null,
userImage: '/Image/GG' // 设置默认头像
userImage: '/Image/GG' // 設置默認頭像
});
}
} catch (error) {
console.error('Error:', error);
setUser({
username: null,
userImage: '/Image/GG' // 设置默认头像
userImage: '/Image/GG' // 設置默認頭像
});
}
}
};
fetchUserInfo();
}, [location]);

fetchUserInfo(); // 初始化時調用函數來設置用戶信息
}, [location, setUser]); // location 改變時重新執行

return (
<header className={styles["top-bar"]}>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/ImageUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ function ImageUpload({ id, onClose }) {
body: formData,
});

console.log('API 回應狀態碼:', response.status);
console.log('API 回應:', await response.text());
// console.log('API 回應狀態碼:', response.status);
// console.log('API 回應:', await response.text());

if (response.ok) {
alert('圖片已成功上傳');
Expand Down
36 changes: 22 additions & 14 deletions frontend/src/components/SearchBar.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
// src/components/SearchBar.js
import React, { useState } from 'react';
import styles from '../styles/components/SearchBar.module.css';
import { useNavigate } from 'react-router-dom';
import styles from '../styles/components/SearchBar.module.css'; // 引入 CSS 模組

function SearchBar() {
const [query, setQuery] = useState(''); // 用來儲存使用者輸入的搜尋詞
const navigate = useNavigate();

function SearchBar({ onSearch }) {
const [query, setQuery] = useState('');

const handleSearch = () => {
onSearch(query);
// 處理搜尋提交
const handleSearch = (e) => {
e.preventDefault(); // 阻止頁面重新載入
if (query.trim()) {
navigate(`/searchPage?query=${encodeURIComponent(query)}`); // 導航到搜尋結果頁面
}
};

return (
<div className={styles.search_bar}>
<input
type="text"
placeholder="搜尋標題或作者"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button onClick={handleSearch}>搜尋</button>
<div className={styles.container}>
<form onSubmit={handleSearch} className={styles['search-bar']}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)} // 更新搜尋詞
placeholder="搜尋文章或作者"
/>
<button type="submit">搜尋</button>
</form>
</div>
);
}
Expand Down
50 changes: 25 additions & 25 deletions frontend/src/components/UserArticles.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
import React, { useState, useEffect } from 'react';
import styles from "../styles/components/UserArticles.module.css";
import articleService from '../services/ArticleService';
import { useNavigate } from 'react-router-dom';

// 用來顯示用戶發表的文章列表
const UserArticles = ({ authorId }) => {
// 管理文章資料
const [articles, setArticles] = useState([]);
const [error, setError] = useState(null); // 用來顯示錯誤
const [loading, setLoading] = useState(true); // 加入 loading 狀態
const navigate = useNavigate();

// 獲取文章資料
useEffect(() => {
const apiUrl = `http://localhost:8080/blog/api/articles/author/${authorId}`;
const initialize = async () => {
try {
const userArticles = await articleService.getUserArticleByAuthorId(authorId);
setArticles(userArticles);
// console.log(articles);
} catch (err) {
setError("無法獲取文章資料,請稍後再試。");
} finally {
setLoading(false);
}
};

fetch(apiUrl)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
setError('');
return response.json();
})
.then(data => {
console.log('獲取到的數據:', data); // 輸出數據以進行調試
if (Array.isArray(data)) {
setArticles(data);
} else {
setError('數據格式錯誤');
}
})
.catch(error => {
console.error("獲取文章失敗:", error.message);
setError('無法連接到服務器');
})
.finally(() => setLoading(false)); // 無論成功與否,結束後都設置為不再 loading
}, [authorId]); // 依賴於 id,當 id 改變時重新獲取資料
if (authorId) {
initialize();
}
}, [authorId]);

if (loading) {
return <div className="col-12"><p>載入中...</p></div>;
Expand All @@ -55,13 +50,18 @@ const UserArticles = ({ authorId }) => {
<li className="list-group-item mb-3 p-3 border rounded shadow-sm" key={index}>
<div className="d-flex flex-column">
<h4 className="mb-2">
<a href={article.url} className="text-decoration-none text-dark fw-bold">
<a href={`/singleArticle/${article.articleId}`} className="text-decoration-none text-dark fw-bold">
{article.title}
</a>
</h4>
<p className={`lh-base text-muted mb-2 ${styles.truncate}`}>{article.contentTEXT}</p>
<div className="d-flex justify-content-end">
<button className="btn btn-dark btn-sm fw-bold">編輯</button>
<button
className="btn btn-dark btn-sm fw-bold"
onClick={()=>{navigate(`/edit-article/${article.articleId}`);}}
>
編輯
</button>
</div>
</div>
</li>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/UserAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ const UserAvatar = ({ id }) => {

fetch(`http://localhost:8080/blog/api/userProfile/${id}`)
.then(response => {
console.log('網頁回應:', response);
// console.log('網頁回應:', response);
return response.json();
})
.then(data => {
console.log("得到的數據", data)
// console.log("得到的數據", data)
setUserData(data);

setLoading(false);
Expand Down
25 changes: 19 additions & 6 deletions frontend/src/components/UserProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const UserProfile = ({ userId }) => {
minute: '2-digit',
second: '2-digit'
});


// 用來管理暫時的編輯資料
const [tempUser, setTempUser] = useState('');
Expand All @@ -44,9 +44,16 @@ const UserProfile = ({ userId }) => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const navigate = useNavigate();
console.log('username is ', user?.username)

// 獲取後端資料
useEffect(() => {
// 設置暫時用戶數據
setTempUser({
username: user?.username || '',
email: user?.email || '',
});

setLoading(true);

setTempUser({
Expand All @@ -65,7 +72,7 @@ const UserProfile = ({ userId }) => {
setError("獲取用戶資料失敗");
setLoading(false);
});
}, [userId]);
}, [userId, user?.username, user?.email]);

// 輸入變化
const handleInputChange = (e) => {
Expand All @@ -87,7 +94,7 @@ const UserProfile = ({ userId }) => {
setLoading(true);

// fetch(`http://niceblog.myvnc.com:8080/blog/api/userProfile/update-${field}/${userId}`, {
fetch(`http://localhost:8080/blog/api/userProfile/update-${field}/${userId}`, {
fetch(`http://localhost:8080/blog/api/userProfile/update-${field}/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Expand All @@ -98,17 +105,23 @@ const UserProfile = ({ userId }) => {
})
.then(response => {
if (!response.ok) {
throw new Error("保存數據失敗");
return response.text().then(text => {
throw new Error(text);
});
}
return response.json(); // 確保正常響應的處理
})
.then(data => {
// 更新 UserContext
setUser(prevUser => ({ ...prevUser, [field]: tempUser[field] }));
setLoading(false);
toggleEdit(field); // 保存成功後切回顯示模式
setError("");
})
.catch(error => {
setLoading(false);
console.error("保存數據失敗", error);
setError("保存數據失敗");
setError(error.message || "保存數據失敗");
});
};

Expand Down Expand Up @@ -208,7 +221,7 @@ const UserProfile = ({ userId }) => {

<div className="col-12 mb-3">
<label htmlFor="registrationDate" className="form-label fw-bold">用戶註冊日期:</label>
<p className={styles.userProfie_p}>{formattedDate1}</p>
<p className='fw-bold'>{formattedDate1}</p>
</div>

<div className="col-12">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/ArticleEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const ArticleEditor = () => {
}
} catch (error) {
console.error('Error during initialization:', error);
navigate('/login'); // 如果無法獲取用戶信息,重定向到登錄頁面
// navigate('/UserData'); // 如果無法獲取用戶信息,重定向到登錄頁面
}
};

Expand Down
Loading

0 comments on commit 4462c94

Please sign in to comment.