feat: titles page
This commit is contained in:
parent
6836cfa057
commit
b976c35b8e
44 changed files with 1539 additions and 107 deletions
103
modules/frontend/src/pages/UserPage/UserPage.module.css
Normal file
103
modules/frontend/src/pages/UserPage/UserPage.module.css
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
body,
|
||||
html {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background-color: #777;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 100vw;
|
||||
padding: 30px 40px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 25px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.avatarWrapper {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
min-width: 120px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.avatarImg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.avatarPlaceholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background: #ccc;
|
||||
font-size: 42px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.userInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
/* margin: 25px auto; */
|
||||
/* padding: 0 20px; */
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.created {
|
||||
font-size: 16px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.loader,
|
||||
.error {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
font-size: 18px;
|
||||
}
|
||||
67
modules/frontend/src/pages/UserPage/UserPage.tsx
Normal file
67
modules/frontend/src/pages/UserPage/UserPage.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom"; // <-- import
|
||||
import { DefaultService } from "../../api/services/DefaultService";
|
||||
import type { User } from "../../api/models/User";
|
||||
import styles from "./UserPage.module.css";
|
||||
|
||||
const UserPage: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>(); // <-- get user id from URL
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
|
||||
const getUserInfo = async () => {
|
||||
try {
|
||||
const userInfo = await DefaultService.getUsers(id, "all"); // <-- use dynamic id
|
||||
setUser(userInfo);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError("Failed to fetch user info.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
getUserInfo();
|
||||
}, [id]);
|
||||
|
||||
if (loading) return <div className={styles.loader}>Loading...</div>;
|
||||
if (error) return <div className={styles.error}>{error}</div>;
|
||||
if (!user) return <div className={styles.error}>User not found.</div>;
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.avatarWrapper}>
|
||||
{user.avatar_id ? (
|
||||
<img
|
||||
src={`/images/${user.avatar_id}.png`}
|
||||
alt="User Avatar"
|
||||
className={styles.avatarImg}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.avatarPlaceholder}>
|
||||
{user.disp_name?.[0] || "U"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.userInfo}>
|
||||
<h1 className={styles.name}>{user.disp_name || user.nickname}</h1>
|
||||
<p className={styles.nickname}>@{user.nickname}</p>
|
||||
{/* <p className={styles.created}>
|
||||
Joined: {new Date(user.creation_date).toLocaleDateString()}
|
||||
</p> */}
|
||||
</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
{user.user_desc && <p className={styles.desc}>{user.user_desc}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserPage;
|
||||
Loading…
Add table
Add a link
Reference in a new issue