Skip to content

Commit

Permalink
Merge pull request #88 from PaulKo121/develop
Browse files Browse the repository at this point in the history
更新css 新增僅供閱讀的用戶資料頁面
  • Loading branch information
PaulKo121 authored Sep 10, 2024
2 parents 63d5099 + 33ee075 commit d5d5e29
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 27 deletions.
4 changes: 2 additions & 2 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Header from './components/Header';
import Footer from './components/Footer';
import EmailVerificationPage from './pages/EmailVerificationPage';
import ChangePassword from './pages/ChangePassword';
import UserDataReadOnly from './pages/UserDataReadOnly';
import TagPage from './pages/TagPage';

const MainLayout = ({ children }) => (
Expand All @@ -31,7 +32,6 @@ const App = () => {
<Routes>
<Route path='/ChangePassword' element={<MainLayout><ChangePassword/></MainLayout>}/>
<Route path="/" element={<MainLayout><Index /></MainLayout>} />
<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 All @@ -44,12 +44,12 @@ const App = () => {
<Route path="/edit-article/:articleId" element={<MainLayout><ArticleEditor /></MainLayout>} />
<Route path="/verify-email" element={<MainLayout><EmailVerificationPage /></MainLayout>} />
<Route path="/tag/:tagId" element={<MainLayout><TagPage /></MainLayout>} />
<Route path="/UserData/:userId" element={<MainLayout><UserDataReadOnly /></MainLayout>} />
{/* 你可以在這裡增加更多路由 */}
</Routes>
<Footer />
</Router>
);
};


export default App;
66 changes: 66 additions & 0 deletions frontend/src/components/UserArticlesReadOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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 UserArticlesReadOnly = ({ authorId }) => {
// 管理文章資料
const [articles, setArticles] = useState([]);
const [error, setError] = useState(null); // 用來顯示錯誤
const [loading, setLoading] = useState(true); // 加入 loading 狀態
const navigate = useNavigate();

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

if (authorId) {
initialize();
}
}, [authorId]);

if (loading) {
return <div className="col-12"><p>載入中...</p></div>;
}

if (error) {
return <div className="col-12"><p>{error}</p></div>;
}

if (articles.length === 0) {
return <div className="col-12"><p>沒有發表過的文章。</p></div>;
}

return (
<div className="col-12">
<h2 className="mb-4 fw-bold">發表過的文章</h2>
<ul className="list-group">
{articles.map((article, index) => (
<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={`/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>
</li>
))}
</ul>
</div>
);
};

export default UserArticlesReadOnly;
4 changes: 2 additions & 2 deletions frontend/src/components/UserAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ const UserAvatar = ({ id }) => {

return (
<div className={`${styles.profile_picture_wrapper} text-center`}>
{loading && <p>載入中...</p>}
{error && <p className={styles.error}>{error}</p>}
{loading && <p className={styles.p}>載入中...</p>}
{error && <p className={styles.p}>{error}</p>}
<label className={`${styles.avatarName} form_label d_block`}>我的頭像</label>
<div className="image-container mb-3">
<img
Expand Down
57 changes: 57 additions & 0 deletions frontend/src/components/UserAvatarReadOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useState, useEffect, useContext } from 'react';
import styles from "../styles/components/UserAvatar.module.css";
import Modal from 'react-modal';
import ImageUpload from "./ImageUpload";
import { UserContext } from './UserContext';

const UserAvatarReadOnly = ({ id }) => {

// 用來管理用戶資料
const [userData, setUserData] = useState({
username: '',
imagelink: ''
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');

// 透過圖片路徑顯示圖片
// 獲取後端資料
useEffect(() => {
setLoading(true);

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

setLoading(false);
})
.catch(error => {
console.error("獲取用戶資料失敗", error);
setError("獲取用戶資料失敗");
setLoading(false);
})
}, [id]);

return (
<div className={`${styles.profile_picture_wrapper} text-center`}>
{loading && <p className={styles.p}>載入中...</p>}
{error && <p className={styles.p}>{error}</p>}
<label className={`${styles.avatarName} form_label d_block`}>{userData.username}的頭像</label>
<div className="image-container mb-3">
<img
id={styles.profile_avatar}
src={userData.imagelink}
alt="頭像"
className="img-fluid rounded border border-3 border-dark"
/>
</div>
</div>
);
};

export default UserAvatarReadOnly;
20 changes: 10 additions & 10 deletions frontend/src/components/UserProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const UserProfile = ({ userId }) => {
{error && <p className="text-danger">{error}</p>}

<div className="col-12 mb-1">
<label htmlFor="username" className="form-label fw-bold">用戶名:</label>
<label htmlFor="username" className={`form-label fw-bold ${styles.label}`}>用戶名:</label>
<div className="d-flex">
<input
type="text"
Expand All @@ -149,15 +149,15 @@ const UserProfile = ({ userId }) => {
{editing.username ? (
<button
type="button"
className="btn btn-dark ms-2 fw-bold"
className="btn btn-dark ms-2"
onClick={() => handleSave('username')}
>
儲存
</button>
) : (
<button
type="button"
className="btn btn-dark ms-2 fw-bold"
className="btn btn-dark ms-2"
onClick={() => toggleEdit('username')}
>
編輯
Expand All @@ -167,7 +167,7 @@ const UserProfile = ({ userId }) => {
</div>

<div className="col-12 mb-3">
<label htmlFor="email" className="form-label fw-bold">電子郵件:</label>
<label htmlFor="email" className={`form-label fw-bold ${styles.label}`}>電子郵件:</label>
<div className="d-flex">
<input
type="email"
Expand Down Expand Up @@ -199,7 +199,7 @@ const UserProfile = ({ userId }) => {
</div>

<div className="col-12 mb-3">
<label htmlFor="password" className="form-label fw-bold">密碼:</label>
<label htmlFor="password" className={`form-label fw-bold ${styles.label}`}>密碼:</label>
<div className="d-flex">
<input
type="password"
Expand All @@ -211,7 +211,7 @@ const UserProfile = ({ userId }) => {
/>
<button
type="button"
className={`btn btn-dark p-1 fw-bold w-30`}
className={`btn btn-dark p-1 fw-bold w-30 ${styles.profile_button}`}
onClick={handleClick}
>
更改密碼
Expand All @@ -220,13 +220,13 @@ const UserProfile = ({ userId }) => {
</div>

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

<div className="col-12">
<label htmlFor="lastLogin" className="form-label fw-bold">最後上線時間:</label>
<p className='fw-bold'>{formattedDate2}</p>
<label htmlFor="lastLogin" className={`form-label fw-bold ${styles.label}`}>最後上線時間:</label>
<p className={`fw-bold ${styles.time}`}>{formattedDate2}</p>
</div>
</div>
);
Expand Down
89 changes: 89 additions & 0 deletions frontend/src/components/UserProfileReadOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useState, useEffect, useContext } from 'react';
import styles from "../styles/components/UserProfile.module.css";

// 用來顯示和編輯用戶的基本資料(用戶名、電子郵件、密碼)
const UserProfileReadOnly = ({ userId }) => {

// 用來管理用戶資料
const [userData, setUserData] = useState({
username: '',
email: '',
createdDate: '',
lastLoginDate: ''
});

// 變換時間格式
const formattedDate1 = new Date(userData.createdDate).toLocaleString('zh-TW', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});

const formattedDate2 = new Date(userData.lastLoginDate).toLocaleString('zh-TW', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});

// 防止用戶在請求未完成時重複提交
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');

// 獲取後端資料
useEffect(() => {

setLoading(true);

fetch(`http://localhost:8080/blog/api/userProfile/${userId}`)
.then(response => response.json())
.then(data => {
setUserData(data);
console.log(data);
setLoading(false);
})
.catch(error => {
console.error("獲取用戶資料失敗", error);
setError("獲取用戶資料失敗");
setLoading(false);
});
}, [userId]);

return (
<div className="row">
{loading && <p>載入中...</p>}
{error && <p className="text-danger">{error}</p>}

<div className="col-12 mb-1">
<label htmlFor="username" className={`form-label fw-bold ${styles.label}`}>用戶名:</label>
<div className="d-flex">
<p className={`fw-bold ${styles.time}`}>{userData.username}</p>
</div>
</div>

<div className="col-12 mb-3">
<label htmlFor="email" className={`form-label fw-bold ${styles.label}`}>電子郵件:</label>
<div className="d-flex">
<p className={`fw-bold ${styles.time}`}>{userData.email}</p>
</div>
</div>

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

<div className="col-12">
<label htmlFor="lastLogin" className={`form-label fw-bold ${styles.label}`}>最後上線時間:</label>
<p className={`fw-bold ${styles.time}`}>{formattedDate2}</p>
</div>
</div>
);
}

export default UserProfileReadOnly;
40 changes: 40 additions & 0 deletions frontend/src/pages/UserDataReadOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState, useEffect } from "react";
import UserProfileReadOnly from "../components/UserProfileReadOnly";
import UserAvatarReadOnly from "../components/UserAvatarReadOnly";
import UserArticlesReadOnly from "../components/UserArticlesReadOnly";
import { useParams } from 'react-router-dom';
import styles from "../styles/pages/UserData.module.css"
import { UserContext } from '../components/UserContext';


const UserDataReadOnly = () => {

const { userId } = useParams(); // 從路由參數中獲取 userId

return (
<div className="container mt-2">
<h1 className="text-center mb-4">Account Name 的小窩</h1>
<div className="card mx-auto" style={{ maxWidth: '70%' }}>
<div className="card-body p-1">
<main className="mt-4">
<div className="row">
<div className="col-md-6 mb-3">
<UserProfileReadOnly userId={userId} />
</div>
<div className="col-md-6 mb-3 d-flex justify-content-center align-items-center">
<UserAvatarReadOnly id={userId} />
</div>
</div>
<div className="row">
<div className="col-12">
<UserArticlesReadOnly authorId={userId} />
</div>
</div>
</main>
</div>
</div>
</div>
);
}

export default UserDataReadOnly;
9 changes: 6 additions & 3 deletions frontend/src/styles/components/UserAvatar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ body, h1, p, a {
}

.avatarName{
color: black;
font-weight: bold;
font-size:large;
font-family: Arial, sans-serif; /* 設置字體 */
Expand All @@ -24,8 +25,6 @@ body, h1, p, a {
.photo {
font-weight: bold;
width: 70%;
background-color: #333;
color: #fff;
border: none;
padding: 5px;
border-radius: 5px;
Expand All @@ -35,4 +34,8 @@ body, h1, p, a {
.mymodal {
width: 500px;
height: 300px;
}
}

.p {
color: black;
}
Loading

0 comments on commit d5d5e29

Please sign in to comment.