Skip to content

Commit 055112a

Browse files
committed
[feat] 주소, api설정
1 parent aad4c31 commit 055112a

File tree

5 files changed

+263
-220
lines changed

5 files changed

+263
-220
lines changed
Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import { getApi } from '@/app/api/config/appConfig';
22
import { Post } from '@/domains/community/types/post';
33
import { ParamValue } from 'next/dist/server/request/params';
4+
import { tabItem } from '../main/CommunityTab';
45

56
export const fetchPost = async (lastId?: number | null): Promise<Post[] | null> => {
67
try {
7-
const res = await fetch(`${getApi}/posts?postSortStatus=LATEST`, {
8-
method: 'GET',
9-
cache: 'no-store',
10-
});
8+
const res = await fetch(
9+
`${getApi}/posts?${lastId ? `lastId=${lastId}&` : ''}postSortStatus=LATEST`,
10+
{
11+
method: 'GET',
12+
cache: 'no-store',
13+
}
14+
);
1115
const data = await res.json();
1216
return data.data;
1317
} catch (err) {
@@ -29,15 +33,63 @@ export const fetchPostById = async (postId: ParamValue) => {
2933
}
3034
};
3135

32-
// export const fetchPostByTab = async (selectedTab: string): Promise<Post[] | null> => {
33-
// try {
34-
// const data = await fetchPost();
35-
// if (!data) return null;
36-
37-
// const filtered = data.filter((post) => post.categoryName === selectedTab);
38-
// return filtered;
39-
// } catch (err) {
40-
// console.error('글 목록 필터링 실패', err);
41-
// return null;
42-
// }
43-
// };
36+
export const fetchPostByTab = async (category: string, lastId?: number): Promise<Post[] | null> => {
37+
try {
38+
const res = await fetch(
39+
`${getApi}/posts?categoryId=${tabItem.findIndex((tab) => tab.key === category)}&${lastId ? `lastId=${lastId}&` : ''}postSortStatus=LATEST`,
40+
{
41+
method: 'GET',
42+
cache: 'no-store',
43+
}
44+
);
45+
46+
const data = await res.json();
47+
if (!data) return null;
48+
49+
const filtered = data.data.filter((post: Post) => post.categoryName === category);
50+
return filtered;
51+
} catch (err) {
52+
console.error('글 목록 필터링 실패', err);
53+
return null;
54+
}
55+
};
56+
57+
export const fetchPostByFilter = async ({
58+
filter,
59+
lastId,
60+
category,
61+
lastLikeCount,
62+
lastCommentCount,
63+
}: {
64+
filter: string;
65+
lastId?: number;
66+
category?: string;
67+
lastLikeCount?: number;
68+
lastCommentCount?: number;
69+
}) => {
70+
try {
71+
let url;
72+
switch (filter) {
73+
case '인기순':
74+
url = `${getApi}/posts?${category ? `categoryId=${tabItem.findIndex((tab) => tab.key === category)}&` : ''}${lastId ? `lastId=${lastId}&` : ''}lastLikeCount=${lastLikeCount}&postSortStatus=POPULAR`;
75+
break;
76+
case '댓글순':
77+
url = `${getApi}/posts?${category ? `categoryId=${tabItem.findIndex((tab) => tab.key === category)}&` : ''}${lastId ? `lastId=${lastId}&` : ''}lastCommentCount=${lastCommentCount}&postSortStatus=COMMENTS`;
78+
break;
79+
default:
80+
url = `${getApi}/posts?${category ? `categoryId=${tabItem.findIndex((tab) => tab.key === category)}&` : ''}${lastId ? `lastId=${lastId}&` : ''}postSortStatus=LATEST`;
81+
break;
82+
}
83+
84+
const res = await fetch(url ?? '', {
85+
method: 'GET',
86+
cache: 'no-store',
87+
});
88+
89+
const data = await res.json();
90+
if (!data) return null;
91+
} catch (err) {
92+
console.error('글 목록 필터링 실패', err);
93+
return null;
94+
}
95+
};

src/domains/community/main/Community.tsx

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,59 @@
11
'use client';
22

3-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3+
import { useEffect, useState } from 'react';
44
import CommunityFilter from './CommunityFilter';
55
import CommunityTab from './CommunityTab';
66
import PostCard from './PostCard';
77
import WriteBtn from './WriteBtn';
88
import { Post } from '../types/post';
9+
import { getApi } from '@/app/api/config/appConfig';
910
import { fetchPost } from '../api/fetchPost';
1011

1112
function Community() {
1213
const [posts, setPosts] = useState<Post[] | null>([]);
1314
const [isLoading, setIsLoading] = useState(true);
1415

15-
const [loading, setLoading] = useState(false);
16-
const [morePost, setMorePost] = useState(true);
16+
const [isEnd, setIsEnd] = useState(false);
1717

18-
const observerRef = useRef<HTMLDivElement | null>(null);
19-
const lastId = useMemo(() => {
20-
return posts && posts.length > 0 ? posts[posts.length - 1].postId : null;
21-
}, [posts]);
22-
23-
const fetchMorePosts = useCallback(async () => {
24-
if (!morePost || loading) {
25-
console.log('[더보기] 요청 차단 - morePost: ', morePost, 'isLoading: ', loading);
26-
return;
27-
}
18+
const loadMorePosts = async (lastPostId: number) => {
19+
if (isEnd || isLoading) return;
20+
console.log('시작');
2821

2922
setIsLoading(true);
30-
console.log('[더보기] 요청 시작 - lastId: ', lastId);
31-
32-
const data = await fetchPost(lastId);
33-
34-
console.log('[더보기] 응답: ', data);
35-
36-
if (!data || data.length === 0) {
37-
console.log('[더보기] 더 이상 데이터 없음');
38-
setMorePost(false);
39-
} else {
40-
setPosts((prev) => [...(prev ?? []), ...data]);
41-
}
42-
43-
setIsLoading(false);
44-
}, [lastId, loading, morePost]);
45-
46-
useEffect(() => {
47-
(async () => {
48-
setIsLoading(true);
49-
console.log('[초기 로딩] 게시물 요청 시작');
50-
51-
const initialData = await fetchPost();
52-
console.log('[초기 로딩] 게시물 응답:', initialData);
53-
54-
setPosts(initialData);
55-
setIsLoading(false);
56-
})();
57-
}, []);
58-
59-
useEffect(() => {
60-
if (!observerRef.current) return;
61-
62-
const observer = new IntersectionObserver(
63-
(entries) => {
64-
const [entry] = entries;
65-
console.log('[관찰자] 감지됨?', entry.isIntersecting);
66-
if (entry.isIntersecting) {
67-
fetchMorePosts();
68-
}
69-
},
70-
{
71-
root: null,
72-
rootMargin: '100px',
73-
threshold: 1.0,
23+
try {
24+
const newPosts = await fetchPost(lastPostId);
25+
console.log(newPosts);
26+
27+
if (newPosts?.length === 0) {
28+
setIsEnd(true);
29+
} else {
30+
setPosts((prev) => [...(prev ?? []), ...(newPosts ?? [])]);
7431
}
75-
);
76-
77-
console.log('[관찰자] 등록됨');
78-
observer.observe(observerRef.current);
79-
80-
return () => {
81-
console.log('[관찰자] 해제됨');
82-
observer.disconnect();
83-
};
84-
}, [posts, isLoading, fetchMorePosts]);
32+
} finally {
33+
setIsLoading(false);
34+
}
35+
};
8536

8637
return (
8738
<>
8839
<section
8940
aria-label="탭과 글쓰기"
9041
className="flex justify-between item-center sm:flex-row flex-col gap-4 mt-1"
9142
>
92-
<CommunityTab setPosts={setPosts} />
43+
<CommunityTab setPosts={setPosts} setIsLoading={setIsLoading} />
9344
<WriteBtn />
9445
</section>
9546

9647
<section aria-label="게시물 목록">
9748
<CommunityFilter posts={posts} setPosts={setPosts} />
98-
<PostCard posts={posts} isLoading={isLoading} />
99-
{morePost && <div ref={observerRef} className="h-10" />}
49+
<PostCard
50+
posts={posts}
51+
setPost={setPosts}
52+
isLoading={isLoading}
53+
setIsLoading={setIsLoading}
54+
isEnd={isEnd}
55+
onLoadMore={loadMorePosts}
56+
/>
10057
</section>
10158
</>
10259
);

src/domains/community/main/CommunityFilter.tsx

Lines changed: 31 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,41 @@
11
'use client';
22

3-
import { getApi } from '@/app/api/config/appConfig';
43
import { Post } from '../types/post';
54
import SelectBox from '@/shared/components/select-box/SelectBox';
6-
import { Dispatch, SetStateAction } from 'react';
5+
import { Dispatch, SetStateAction, useEffect } from 'react';
6+
import { fetchPostByFilter } from '../api/fetchPost';
7+
import { useRouter, useSearchParams } from 'next/navigation';
78

89
type Props = {
910
posts: Post[] | null;
1011
setPosts: Dispatch<SetStateAction<Post[] | null>>;
1112
};
1213

14+
const sortMap = {
15+
최신순: 'LATEST',
16+
인기순: 'POPULAR',
17+
댓글순: 'COMMENTS',
18+
} as const;
19+
1320
function CommunityFilter({ posts, setPosts }: Props) {
14-
const handleChange = (selectTitle: string) => {
21+
const searchParams = useSearchParams();
22+
const query = searchParams.get('category');
23+
const router = useRouter();
24+
25+
useEffect(() => {
26+
console.log(query);
27+
}, [query]);
28+
29+
const handleChange = async (selectTitle: string) => {
30+
if (!query) return;
1531
console.log(selectTitle);
1632

17-
const fetchData = async () => {
18-
if (selectTitle === '최신순') {
19-
try {
20-
const res = await fetch(`${getApi}/posts?postSortStatus=LATEST`, {
21-
method: 'GET',
22-
});
23-
const data = await res.json();
24-
setPosts(data.data);
25-
} catch (err) {
26-
console.error('에러', err);
27-
return null;
28-
}
29-
} else if (selectTitle === '인기순') {
30-
try {
31-
const res = await fetch(
32-
`${getApi}/posts?postSortStatus=POPULAR&lastId={lastId}&lastLikeCount={lastLikeCount}`,
33-
{
34-
method: 'GET',
35-
mode: 'no-cors',
36-
}
37-
);
38-
const data = await res.json();
39-
setPosts(data.data);
40-
} catch (err) {
41-
console.error('에러', err);
42-
return null;
43-
}
44-
} else if (selectTitle === '댓글순') {
45-
try {
46-
const res = await fetch(
47-
`${getApi}/posts?postSortStatus=COMMENTS&lastId={lastId}&lastCommentCount={lastCommentCount}`,
48-
{
49-
method: 'GET',
50-
mode: 'no-cors',
51-
}
52-
);
53-
const data = await res.json();
54-
setPosts(data.data);
55-
} catch (err) {
56-
console.error('에러', err);
57-
return null;
58-
}
59-
}
60-
};
61-
fetchData();
33+
const data = await fetchPostByFilter({
34+
filter: selectTitle,
35+
category: query,
36+
});
37+
if (!data) return;
38+
setPosts(data);
6239
};
6340

6441
return (
@@ -70,7 +47,12 @@ function CommunityFilter({ posts, setPosts }: Props) {
7047
<SelectBox
7148
option={['최신순', '인기순', '댓글순']}
7249
title={'최신순'}
73-
onChange={(value) => handleChange(value)}
50+
onChange={(value) => {
51+
const sortValue = sortMap[value as keyof typeof sortMap];
52+
53+
handleChange(value);
54+
router.push(`?category=${query || '전체'}&postSortStatus=${sortValue}`);
55+
}}
7456
/>
7557
</section>
7658
);

0 commit comments

Comments
 (0)