Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 프로필 페이지 구현 #78

Merged
merged 7 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 49 additions & 30 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useParams } from 'react-router-dom';
import Signup from './auth/Signup';
import Login from './auth/Login';
import Dashboard from './auth/Dashboard';
import styled from 'styled-components';
import Navigation from './components/main/Navigation';
import PostFeed from './pages/PostFeed/PostFeed';
import ProfilePage from '../src/profile/ProfilePage.jsx';

const App = () => {
const [user, setUser] = useState(null);

useEffect(() => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
setUser(JSON.parse(storedUser));
}
}, []);

return (
<Router>
<div>
Expand All @@ -26,54 +36,63 @@ const App = () => {
<Route path="/signup" element={<Signup />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/postfeed" element={<PostFeed />} />
{/* 유저 페이지/마이페이지 */}
<Route path="/user/:userId" element={<ProfilePageWrapper user={user} />} />
</Routes>
</Container>
</Router>
);
};

const ProfilePageWrapper = ({ user }) => {
const { userId } = useParams(); // URL에서 유저 ID 가져오기

const [userData, setUserData] = useState(null);
const isMyPage = userId === user?._id; // 로컬 유저 ID와 비교

useEffect(() => {
const fetchUserData = async () => {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUserData(data);
} catch (error) {
console.error('유저 데이터 불러오기 실패:', error);
}
};

if (!isMyPage) { // 마이페이지가 아니라면, 유저 데이터를 불러옵니다.
fetchUserData();
}
}, [userId, isMyPage]);

if (!userData && !isMyPage) {
return <p>유저 정보를 불러오는 중...</p>;
}

return <ProfilePage user={isMyPage ? user : userData} isMyPage={isMyPage} />;
};

export default App;

// Styled Components
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin-top: 50px;
/* background-color: #f0f0f0; */

@media (max-width: 768px) {
padding: 20px;
}
/* min-width: 700px; */
padding: 20px;
`;

const Nav = styled.nav`
display: flex;
justify-content: space-around;
margin-bottom: 20px;
margin-top: 50px;

@media (max-width: 768px) {
margin-top: 10px;
}
`;

const NavLink = styled(Link)`
padding: 10px 20px;
margin: 0 10px;
background-color: #bf94e4;
color: white;
color: #333;
text-decoration: none;
border-radius: 5px;
font-size: 16px;
font-weight: bold;

&:hover {
background-color: #d3d3d3;
}

@media (max-width: 768px) {
padding: 8px 16px;
font-size: 14px;
background-color: #eee;
}
`;
56 changes: 26 additions & 30 deletions src/components/UserCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import ExampleImage from '../assets/images/default-profile.png';
import { useNavigate } from 'react-router-dom';
import { getUsers } from '../utils/api';

const UserCard = ({ user, onNavigate }) => {
const UserCard = ({ user, navigate }) => {
const { image, fullName, role, _id } = user;
// 코멘트가 50자를 넘을 경우 자르고 '...'을 붙임

let nickName = '...';
let bio = '...';
Expand All @@ -15,36 +16,35 @@ const UserCard = ({ user, onNavigate }) => {
try {
const parsedFullName = JSON.parse(fullName);
nickName = parsedFullName.nickName || nickName;
bio = parsedFullName.bio || bio;
bio = parsedFullName.bio || bio; // bio도 파싱
} catch (error) {
console.error('fullName 파싱 오류:', error);
}
}

// bio가 50자를 넘으면 자르기
const truncatedBio = bio.length > 50 ? bio.slice(0, 50) + '...' : bio;
const Introduce = bio.length > 50 ? bio.slice(0, 50) + '...' : bio;

const handleCardClick = () => {
onNavigate(`/userpage/${_id}`);
navigate(`/user/${_id}`);
};

return (
<StyledCard onClick={handleCardClick}>
<StyledProfileImage src={image || ExampleImage} alt={nickName} /> {/* 프로필 이미지 */}
<StyledUserInfo>
<StyledUserName>{nickName}</StyledUserName> {/* 유저 이름 */}
<StyledUserRole>{role}</StyledUserRole> {/* 유저 역할 */}
<StyledUserBio>{truncatedBio}</StyledUserBio> {/* 유저 자기소개 */}
</StyledUserInfo>
</StyledCard>
<Card onClick={handleCardClick}>
<ProfileImage src={image || ExampleImage} alt={nickName} /> {/* 프로필 이미지 */}
<UserInfo>
<UserName>{nickName}</UserName> {/* 유저 이름 */}
<UserTitle>{role}</UserTitle> {/* 유저 역할 */}
<UserBio>{Introduce}</UserBio> {/* 유저 자기소개 */}
</UserInfo>
</Card>
);
};

const App = () => {
const [users, setUsers] = useState([]);
const navigate = useNavigate(); // useNavigate 훅
const navigate = useNavigate();

// API 호출을 통해 유저 데이터 가져오기
useEffect(() => {
const fetchUsers = async () => {
try {
Expand All @@ -55,56 +55,52 @@ const App = () => {
}
};

fetchUsers();
fetchUsers(); // 유저 데이터 가져오기
}, []);

return (
<div>
<h1>유저 카드 리스트</h1>
<StyledUserList>
<UserList>
{users.map((user) => (
<UserCard key={user._id} user={user} onNavigate={navigate} />
<UserCard key={user._id} user={user} navigate={navigate} /> // navigate 전달
))}
</StyledUserList>
</UserList>
</div>
);
};

export default App;

// Styled Components
const StyledCard = styled.div`
const Card = styled.div`
display: flex;
align-items: center;
width: 420px;
border-radius: 16px;
padding: 8px;

&:hover {
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
}
`;

const StyledProfileImage = styled.img`
const ProfileImage = styled.img`
width: 80px;
height: 80px;
border-radius: 50%;
`;

const StyledUserInfo = styled.div`
const UserInfo = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
margin-left: 17px;
`;

const StyledUserName = styled.h2`
const UserName = styled.h2`
font-size: 1em;
margin: 0;
color: #333;
`;

const StyledUserRole = styled.p`
const UserTitle = styled.p`
margin: 5px 0;
display: flex;
justify-content: center;
Expand All @@ -114,10 +110,10 @@ const StyledUserRole = styled.p`
border-radius: 35px;
font-size: 12px;
color: #474150;
white-space: nowrap;
white-space: nowrap; /* 긴 텍스트가 줄 바꿈되지 않도록 */
`;

const StyledUserBio = styled.p`
const UserBio = styled.p`
margin: 5px 0;
text-align: left;
padding: 13px;
Expand All @@ -129,7 +125,7 @@ const StyledUserBio = styled.p`
color: white;
`;

const StyledUserList = styled.div`
const UserList = styled.div`
display: flex;
flex-direction: column;
align-items: center;
Expand Down
2 changes: 1 addition & 1 deletion src/components/UserProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const UserProfileCard = ({ user, onNavigate }) => {
}

const handleCardClick = () => {
onNavigate(`/userpage/${_id}`);
onNavigate(`/user/${_id}`);
};

return (
Expand Down
13 changes: 3 additions & 10 deletions src/components/main/Navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const Navigation = () => {
// 프로필 클릭 시 해당 유저 페이지로 이동
const handleProfileClick = () => {
if (user && user._id) {
navigate(`/userpage/${user._id}`); // 유저의 _id를 기반으로 이동
navigate(`/user/${user._id}`); // 유저의 _id를 기반으로 이동
}
};

Expand Down Expand Up @@ -124,10 +124,6 @@ const HeaderContainer = styled.header`
justify-content: space-between;
padding: 5px 10px;
background-color: #f8f9fa;

@media (max-width: 768px) {
align-items: flex-start; /* 왼쪽 정렬 */
}
`;

const Logo = styled.div`
Expand All @@ -141,9 +137,6 @@ const Navbar = styled.nav`
display: flex;
gap: 20px;

@media (max-width: 768px) {
/* flex-wrap: wrap; 아이템이 많아지면 줄바꿈 */
}
`;

const NavItem = styled.a`
Expand Down Expand Up @@ -236,7 +229,7 @@ const ProfileSection = styled.div`

.title {
display: flex;
padding: 10px 30px;
padding: 5px 30px;
background: #ede4db;
border-radius: 35px;
font-size: 14px;
Expand All @@ -255,10 +248,10 @@ const ProfileSection = styled.div`
width: 40px;
height: 40px;
margin-left: 5px;
margin-top: 5px;
}

img.notification {
margin-left: 5px;
width: 24px;
height: 24px;
}
Expand Down
Loading