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: 실제 API 연동 및 혼합 접근법 활용 상태 관리 추가 #51

Merged
merged 6 commits into from
Dec 9, 2024
47 changes: 44 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^2.3.0",
"@tanstack/query-core": "^5.62.3",
"@tanstack/react-query": "^5.60.6",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
Expand All @@ -16,6 +17,8 @@
"@types/styled-components": "^5.1.34",
"@vitejs/plugin-react": "^4.3.3",
"axios": "^1.7.7",
"jotai": "^2.10.3",
"jotai-tanstack-query": "^0.9.0",
"react": "^18.3.1",
"react-daum-postcode": "^3.1.3",
"react-dom": "^18.3.1",
Expand Down
3 changes: 0 additions & 3 deletions src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import axios from 'axios';
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_URL, // API URL
timeout: 5000, // 요청 제한 시간 (ms)
headers: {
'Content-Type': 'application/json', // JSON 형식 사용
},
});

// 요청/응답 인터셉터 설정 (선택 사항)
Expand Down
8 changes: 4 additions & 4 deletions src/components/common/CategoryWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const CategoryWrapper: React.FC<CategoryWrapperProps> = ({
{categories.map((category) => (
<CategoryItem
key={category.id}
active={category.id === currentCategory}
$active={category.id === currentCategory}
onClick={() => handleCategoryClick(category.id)}
>
{category.name}
Expand All @@ -65,15 +65,15 @@ const HeaderTitle = styled.h2`
white-space: nowrap; /* 텍스트 줄바꿈 방지 */
`;

const CategoryItem = styled.div<{ active: boolean }>`
const CategoryItem = styled.div<{ $active: boolean }>`
padding: 1rem 1rem;
font-weight: ${({ active }) => (active ? 'bold' : 'normal')};
font-weight: ${({ $active }) => ($active ? 'bold' : 'normal')};
cursor: pointer;
position: relative;

&::after {
content: '';
display: ${({ active }) => (active ? 'block' : 'none')};
display: ${({ $active }) => ($active ? 'block' : 'none')};
height: 2px;
background-color: black;
width: 100%;
Expand Down
20 changes: 14 additions & 6 deletions src/components/common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ const Header = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};

const handleCommunityClick = (
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>
) => {
if (!isLoggedIn || !isAdmin) {
e.preventDefault();
alert('로그인 후 이용할 수 있는 페이지입니다.');
setIsMobileMenuOpen(!isMobileMenuOpen);
}
};

return (
<HeaderContainer>
<HeaderContent>
Expand Down Expand Up @@ -47,14 +57,14 @@ const Header = () => {
</StyledLink>
</NavItem>
<NavItem>
<StyledLink to="/community/post" onClick={toggleMobileMenu}>
<StyledLink to="/community/post" onClick={handleCommunityClick}>
Community
</StyledLink>
</NavItem>
<NavItem>
{isLoggedIn && (
<StyledLink
to={isAdmin ? '/adminpage' : '/mypage/setting'}
to={isAdmin ? '#' : '/mypage/setting'}
onClick={toggleMobileMenu}
>
{isAdmin ? 'Admin Page' : 'My Page'}
Expand All @@ -63,12 +73,10 @@ const Header = () => {
{isAdmin && (
<SubMenu>
<SubMenuItem>
<StyledLink to="/adminpage/post-management">
Post Management
</StyledLink>
<StyledLink to="/admin/post">Post Management</StyledLink>
</SubMenuItem>
<SubMenuItem>
<StyledLink to="/adminpage/chat-management">
<StyledLink to="/admin/chatlist">
Chat Management
</StyledLink>
</SubMenuItem>
Expand Down
83 changes: 35 additions & 48 deletions src/components/common/PostList.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,35 @@
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { getPosts, Post } from '../pages/community/api/postApi';
import WriteButton from './WriteButton';
import SearchBar from './SearchBar';
import Pagination from './Pagination';
import { useNavigate } from 'react-router-dom';
import { SSEEvent, Post } from '../../types/postTypes';
import { getImageSrc } from '../../utils/GetImageSrc';
import { formatDateWithOffset } from '../../utils/formatDate';

interface PostListProps {
posts: Post[];
selectedCategory: string;
posts: Post[];
onPostSelect?: (postId: number) => void; // onPostSelect 추가
realTimeData: Record<number, SSEEvent>; // 실시간 데이터 매핑 추가
}

const POSTS_PER_PAGE = 6; // 한 페이지에 표시할 게시글 수

const PostList: React.FC<PostListProps & { hideWriteButton?: boolean }> = ({
selectedCategory,
posts,
realTimeData,
onPostSelect,
hideWriteButton,
}) => {
const navigate = useNavigate();
const [posts, setPosts] = useState<Post[]>([]); // 실제 게시글 데이터
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState(''); // 입력된 검색어
const [searchQuery, setSearchQuery] = useState(''); // 실제 검색 실행 시의 검색어
const [loading, setLoading] = useState(false); // 로딩 상태

// 게시글 데이터 로드
const loadPosts = async () => {
try {
setLoading(true);
const data = await getPosts(selectedCategory, searchQuery); // API 호출
setPosts(data);
} catch (error) {
console.error('게시물 조회 중 오류 발생:', error);
alert('게시물 조회 중 오류가 발생했습니다. 다시 시도해주세요.');
} finally {
setLoading(false);
}
};

// 카테고리나 검색어 변경 시 데이터 로드
useEffect(() => {
loadPosts();
}, [selectedCategory, searchQuery]);

// 선택된 카테고리에 따른 게시글 필터링 (status 조건 추가)
// 선택된 카테고리에 따른 게시글 필터링
const categoryFilteredPosts = posts
.filter((post) => {
if (selectedCategory === 'NOT_APPROVED') {
Expand Down Expand Up @@ -88,6 +74,10 @@ const PostList: React.FC<PostListProps & { hideWriteButton?: boolean }> = ({

// 포스트 클릭 핸들러
const handlePostClick = (communityPostId: number) => {
if (onPostSelect) {
onPostSelect(communityPostId); // 부모 컴포넌트에 선택 이벤트 전달
}

if (selectedCategory === 'NOT_APPROVED') {
navigate(`/admin/post/approval/${communityPostId}`, {
state: { communityPostId },
Expand All @@ -97,6 +87,11 @@ const PostList: React.FC<PostListProps & { hideWriteButton?: boolean }> = ({
}
};

// 특정 포스트의 현재 참여 수 계산
const getParticipationCount = (postId: number): number => {
return realTimeData[postId]?.participationCount || 0;
};

return (
<Container>
<ActionsContainer>
Expand All @@ -108,9 +103,7 @@ const PostList: React.FC<PostListProps & { hideWriteButton?: boolean }> = ({
/>
</ActionsContainer>

{loading ? (
<NoPostMessage>게시물을 불러오는 중입니다...</NoPostMessage>
) : categoryFilteredPosts.length === 0 ? (
{categoryFilteredPosts.length === 0 ? (
<NoPostMessage>
선택된 카테고리에 해당하는 게시글이 없습니다.
</NoPostMessage>
Expand All @@ -124,36 +117,30 @@ const PostList: React.FC<PostListProps & { hideWriteButton?: boolean }> = ({
key={post.communityPostId}
onClick={() => handlePostClick(post.communityPostId)}
>
<PostImage src={post.imageUrls[0]} alt={post.title} />
<PostImage
src={getImageSrc(post.imageUrls[0])}
alt={`post.title`}
/>
<PostContent>
<PostTitle>{post.title}</PostTitle>
<PostDetails>
<PostAuthor>{post.nickname}</PostAuthor>
<PostDate>
<PostCreatedAt>
{new Date(post.createdAt).toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
})}
{formatDateWithOffset(post.createdAt)}
</PostCreatedAt>
{'~'}
<PostCloseAt>
{new Date(post.closeAt).toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false,
})}
</PostCloseAt>
{selectedCategory !== 'NOT_APPROVED' && (
<>
{'~'}
<PostCloseAt>
{formatDateWithOffset(post.closeAt)}
</PostCloseAt>
</>
)}
</PostDate>
<PostJoinStatus>
참여 현황: {post.currentQuantity} / {post.availableNumber}
참여 현황: {getParticipationCount(post.communityPostId)} /{' '}
{post.availableNumber}
</PostJoinStatus>
</PostDetails>
<PostDescription>{post.description}</PostDescription>
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/admin/ChatRoomManagementPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from 'styled-components';
import { useLocation, useNavigate } from 'react-router-dom';
import ChatRoomModal from '../community/modal/ChatRoomModal'; // 기존 채팅 모달 컴포넌트
import Pagination from '../../common/Pagination'; // 기존 페이지네이션 컴포넌트
import { fetchChatRooms } from '../community/api/chatApi';
import { fetchAllChatRooms } from '../community/api/chatApi';
import { FaBackspace } from 'react-icons/fa';
import { webSocketService } from '../../../utils/webSocket';

Expand Down Expand Up @@ -32,7 +32,7 @@ const ChatRoomManagementPage = () => {
useEffect(() => {
const fetchData = async () => {
try {
const rooms = await fetchChatRooms();
const rooms = await fetchAllChatRooms();
setChatRooms(rooms);
} catch (error) {
console.error('Failed to fetch chat rooms:', error);
Expand Down
Loading