Skip to content

Commit fd91212

Browse files
authored
Merge pull request #315 from prgrms-web-devcourse-final-project/refactor/cardMoadlSheet
[REFACTOR] 메인페이지 card moadl sheet 수정
2 parents 223365b + b33076b commit fd91212

File tree

7 files changed

+76
-242
lines changed

7 files changed

+76
-242
lines changed

src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ function App() {
4444

4545
{/* PrivateRoute 적용 */}
4646
<Route element={<PrivateRoute />}>
47-
<Route path="/home" element={<Home />} />
47+
<Route path="/home" element={<Home />}>
48+
<Route path=":id" element={<CardDetailModalTemp />} />
49+
</Route>
4850
<Route path="/chat" element={<Chat />} />
4951
<Route path="/post" element={<Post />} />
5052
<Route path="/post/:postId/edit" element={<Post />} />

src/components/modalSheet/CardDetailModal.tsx

Lines changed: 0 additions & 139 deletions
This file was deleted.

src/layouts/bottomNav/BottomNav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default function BottomNav() {
4141
//바텀 nav 바 필요한 페이지
4242
const showNav =
4343
//메인 페이지
44-
location.pathname === '/home' ||
44+
location.pathname.startsWith('/home') ||
4545
//마이 페이지
4646
location.pathname.startsWith('/mypage') ||
4747
//유저 페이지

src/pages/home/Home.tsx

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,29 @@
11
import { useInfiniteQuery } from '@tanstack/react-query';
22
import { useInView } from 'react-intersection-observer';
33
import SearchBar from '@/components/SearchBar';
4-
import MainCard from '@/pages/home/components/MainCard';
54
import { useEffect, useState } from 'react';
65
import EmotionFilter from '@/components/EmotionFilter';
76
import { useSheetStore } from '@/store/sheetStore';
8-
import CardDetailModal from '@/components/modalSheet/CardDetailModal';
97
import { getEmotionRecords } from '@/apis/emotionRecord';
10-
import { formatDate } from '@/utils/formatDate';
8+
119
import MusicSearchSheet from '@/components/modalSheet/MusicSearchSheet';
1210
import { useMusicCardStore } from '@/store/MusicCardStore';
13-
import InfoMessage from '@/components/InfoMessage';
11+
1412
import LoadingMini from '@/components/loading/LoadingMini';
1513
import Loading from '@/components/loading/Loading';
14+
import MainCardList from '@/pages/home/components/MainCardList';
15+
import { Outlet } from 'react-router';
1616

1717
function Home() {
1818
const { isMusicSheetOpen, openSheet, closeAllSheets } = useSheetStore(); // 모달 시트
1919
const { selectedPostMusic, clearPostMusic } = useMusicCardStore(); // 선택된 음악
2020

2121
const [searchText, setSearchText] = useState(''); // 검색어
2222
const [selectedEmotion, setSelectedEmotion] = useState<string | null>(null); // 선택된 감정 필터
23-
const [selectedRecordId, setSelectedRecordId] = useState<number | null>(null); // 선택한 타인 감정 게시글 id -> 게시글 상세 모달 열기
2423

2524
// 감정 필터링
2625
const onEmotionClick = (emotion: string) => {
2726
setSelectedEmotion((prev) => (prev === emotion ? null : emotion));
28-
// // console.log(selectedEmotion);
29-
};
30-
31-
// 유저 상세 페이지 모달 열기
32-
const handleOpenSheet = (recordId: number) => {
33-
setSelectedRecordId(recordId);
34-
openSheet('isCardSheetOpen'); // 모달 열기
3527
};
3628

3729
// 감정 기록 불러오기
@@ -44,8 +36,6 @@ function Home() {
4436
} = useInfiniteQuery({
4537
queryKey: ['emotionRecords', selectedPostMusic?.spotifyId, selectedEmotion],
4638
queryFn: async ({ pageParam }) => {
47-
// // console.log('pageParam:', pageParam);
48-
4939
const { data } = await getEmotionRecords(
5040
pageParam,
5141
10,
@@ -68,10 +58,7 @@ function Home() {
6858
initialPageParam: 1, // 첫 페이지 번호 초기화!
6959
});
7060

71-
useEffect(() => {
72-
// 첫 페이지 로드
73-
// // console.log('페이지 로드', isLoading);
74-
}, [isLoading]);
61+
const allRecords = emotionRecords?.pages.flatMap((page) => page.records) ?? [];
7562

7663
// 무한 스크롤 감지 요소 추가
7764
const { ref, inView } = useInView();
@@ -119,41 +106,15 @@ function Home() {
119106
</div>
120107

121108
{/* 메인카드 리스트 */}
122-
<div className="flex-1">
123-
{emotionRecords?.pages[0].records.length > 0 ? (
124-
<>
125-
<div className="flex flex-col items-center gap-2.5 pb-5 ">
126-
{emotionRecords?.pages.map((page) =>
127-
page.records.map((record: EmotionRecord) => (
128-
<div className="w-full" key={record.recordId}>
129-
<div onClick={() => handleOpenSheet(record.recordId)}>
130-
<MainCard
131-
albumImage={record.spotifyMusic.albumImage} // 앨범 이미지
132-
nickname={record.nickName} // 닉네임
133-
emotion={record.emotion} // 감정
134-
title={record.spotifyMusic.title} // 노래 제목
135-
artist={record.spotifyMusic.artist} // 가수
136-
comment={record.comment} // 글 내용
137-
createdAt={formatDate(record.createdAt)} // 날짜
138-
/>
139-
</div>
140-
</div>
141-
)),
142-
)}
143-
{hasNextPage && !isFetchingNextPage && (
144-
<div className="m-auto" ref={ref}>
145-
<LoadingMini />
146-
</div>
147-
)}
148-
</div>
149-
</>
150-
) : (
151-
<div className="flex items-center justify-center w-full h-full">
152-
<InfoMessage text="아직 작성된 글이 없어요" />
109+
<div className="pb-5">
110+
<MainCardList records={allRecords} />
111+
{hasNextPage && !isFetchingNextPage && (
112+
<div className="m-auto" ref={ref}>
113+
<LoadingMini />
153114
</div>
154115
)}
155116
</div>
156-
{selectedRecordId !== null && <CardDetailModal recordId={selectedRecordId} />}
117+
<Outlet />
157118
{isLoading && <Loading />}
158119
{isMusicSheetOpen && <MusicSearchSheet />}
159120
</div>
Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,50 @@
11
import EmotionBadge from '@/components/EmotionBadge';
2+
import { formatDate } from '@/utils/formatDate';
23
import defaultImage from '@assets/images/default.png';
4+
import { Link } from 'react-router';
35

46
interface MainCardProps {
5-
albumImage: string; // 앨범 이미지
6-
nickname: string; // 닉네임
7-
emotion: string; // 감정
8-
title: string; // 노래 제목
9-
artist: string; // 가수
10-
comment: string; // 글 내용
11-
createdAt: string; // 날짜
7+
record: EmotionRecord;
128
}
139

14-
export default function MainCard({
15-
albumImage,
16-
nickname,
17-
emotion,
18-
title,
19-
artist,
20-
comment,
21-
createdAt,
22-
}: MainCardProps) {
10+
export default function MainCard({ record }: MainCardProps) {
2311
return (
24-
<div className="flex-none w-full cursor-pointer">
25-
<div className="flex flex-col gap-1 bg-white/80 rounded-lg card-shadow px-3 py-2.5 hover:bg-white transition ">
26-
{/* 닉네임 + 상태 */}
27-
<div className="flex items-center gap-1">
28-
<span className="caption-m text-gray-70">{nickname}</span>
29-
<span className="caption-r text-gray-60">님은 지금</span>
30-
<EmotionBadge size="small" emotion={emotion} />
31-
</div>
12+
<Link
13+
to={`/home/${record.recordId}`}
14+
state={{ scrollLock: true }}
15+
className="flex flex-col gap-1 bg-white/80 rounded-lg card-shadow px-3 py-2.5"
16+
>
17+
{/* 닉네임 + 상태 */}
18+
<div className="flex items-center gap-1">
19+
<span className="caption-m text-gray-70">{record.nickName}</span>
20+
<span className="caption-r text-gray-60">님은 지금</span>
21+
<EmotionBadge size="small" emotion={record.emotion} />
22+
</div>
3223

33-
{/* 노래 + 글 정보 */}
34-
<div className="flex gap-2">
35-
{/* 앨범커버 */}
36-
<div className="w-16 h-16 rounded-lg overflow-hidden flex-shrink-0">
37-
<img
38-
className="w-full h-full object-cover"
39-
src={albumImage || defaultImage}
40-
onError={(e) => {
41-
const target = e.target as HTMLImageElement;
42-
target.onerror = null; // 무한 루프 방지
43-
target.src = defaultImage; // 기본 이미지로 변경
44-
}}
45-
alt="앨범이미지"
46-
/>
47-
</div>
48-
{/* 정보 */}
49-
<div className="flex flex-col gap-1">
50-
<p className="body-b text-gray-80 line-clamp-1 break-all">
51-
{title} - {artist}
52-
</p>
53-
<p className="caption-r text-gray-60 line-clamp-1 break-all">{comment}</p>
54-
<span className="text-[9px] text-gray-60 font-light">{createdAt}</span>
55-
</div>
24+
{/* 노래 + 글 정보 */}
25+
<div className="flex gap-2">
26+
{/* 앨범커버 */}
27+
<div className="flex-shrink-0 w-16 h-16 overflow-hidden rounded-lg">
28+
<img
29+
className="object-cover w-full h-full"
30+
src={record.spotifyMusic.albumImage || defaultImage}
31+
onError={(e) => {
32+
const target = e.target as HTMLImageElement;
33+
target.onerror = null; // 무한 루프 방지
34+
target.src = defaultImage; // 기본 이미지로 변경
35+
}}
36+
alt="앨범이미지"
37+
/>
38+
</div>
39+
{/* 정보 */}
40+
<div className="flex flex-col gap-1">
41+
<p className="break-all body-b text-gray-80 line-clamp-1">
42+
{record.spotifyMusic.title} - {record.spotifyMusic.artist}
43+
</p>
44+
<p className="break-all caption-r text-gray-60 line-clamp-1">{record.comment}</p>
45+
<span className="text-[9px] text-gray-60 font-light">{formatDate(record.createdAt)}</span>
5646
</div>
5747
</div>
58-
</div>
48+
</Link>
5949
);
6050
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { InfoMessage } from '@/components';
2+
import MainCard from '@/pages/home/components/MainCard';
3+
4+
interface MainCardListProps {
5+
records: EmotionRecord[];
6+
}
7+
8+
export default function MainCardList({ records }: MainCardListProps) {
9+
if (records.length === 0) {
10+
return (
11+
<div className="flex items-center justify-center w-full h-full">
12+
<InfoMessage text="아직 작성된 글이 없어요" />
13+
</div>
14+
);
15+
}
16+
return (
17+
<div className="flex flex-col gap-2.5">
18+
{records.map((record) => (
19+
<MainCard key={record.recordId} record={record} />
20+
))}
21+
</div>
22+
);
23+
}

0 commit comments

Comments
 (0)