Skip to content

Commit b3620b7

Browse files
authored
Merge pull request #49 from CodeItBoost3/feature/scrap-api
Scrap API 연동 완료
2 parents b499592 + bb2af41 commit b3620b7

File tree

5 files changed

+134
-56
lines changed

5 files changed

+134
-56
lines changed

src/assets/icon/scrap/no-scrap.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/main/MemoryCard.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {useEffect, useState} from "react";
22
import ArrowDownIcon from '@/assets/icon/main/arrow-down.svg';
33
import ArrowUpIcon from '@/assets/icon/main/arrow-up.svg';
44

5-
function MemoryCard({ title, date, memory, sympathy, comments, index }) {
5+
function MemoryCard({ title, date, group, sympathy, comments, index }) {
66
const [isOpen, setIsOpen] = useState(false);
77

88
const handleMemoryCard = () => {
@@ -28,12 +28,12 @@ function MemoryCard({ title, date, memory, sympathy, comments, index }) {
2828
<div className="flex justify-between items-center relative box-border pb-5">
2929
<img src={ArrowUpIcon} className="absolute top-2.5 right-3.5" onClick={handleMemoryCard}/>
3030
<div className="text-darkGray-active text-sm flex flex-col gap-2 pl-6 pt-9">
31-
<p>추억</p>
31+
<p>그룹</p>
3232
<p>공감</p>
3333
<p>댓글</p>
3434
</div>
35-
<div className="flex text-sm text-black flex-col gap-2 pr-14 pt-9">
36-
<p>{memory}</p>
35+
<div className="flex text-sm text-black flex-col gap-2 pr-14 pt-9 text-right">
36+
<p>{group}</p>
3737
<p>{sympathy}</p>
3838
<p>{comments}</p>
3939
</div>

src/pages/Main.jsx

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import {useState, useEffect} from "react";
22
import {useNavigate} from "react-router-dom";
3+
4+
import dayjs from "dayjs";
5+
6+
import {useToast} from "@/hooks/useToast";
7+
38
import groupService from "@/services/group/groupService.js";
49
import userService from "@/services/user/userService";
5-
import {useToast} from "@/hooks/useToast";
10+
611

712
import PublicGroupCard from "@/components/common/PublicGroupCard";
813
import NoticeCard from "@/components/main/NoticeCard";
@@ -24,6 +29,7 @@ export default function Main() {
2429
const navigate = useNavigate();
2530
const addToast = useToast();
2631

32+
console.log(recentPosts)
2733
/** 사용자 정보 조회 **/
2834
useEffect(() => {
2935
const fetchUserInfo = async () => {
@@ -44,12 +50,16 @@ export default function Main() {
4450
useEffect(() => {
4551
const fetchGroupList = async () => {
4652
try {
47-
const data = await groupService.getGroupList({
53+
const response = await groupService.getGroupList({
4854
type: "public",
4955
sortBy: "latest",
5056
keyword: "",
5157
});
52-
setGroupList(data.data || []);
58+
if(response.status === "success") {
59+
setGroupList(response.data.groups || []);
60+
} else{
61+
throw new Error("그룹 목록 조회 실패");
62+
}
5363
} catch {
5464
addToast("그룹 목록 조회에 실패했습니다.");
5565
}
@@ -62,8 +72,13 @@ export default function Main() {
6272
useEffect(() => {
6373
const fetchRecentPosts = async () => {
6474
try {
65-
const data = await userService.getMyPosts();
66-
setRecentPosts(data.data || []);
75+
const response = await userService.getMyPosts();
76+
if(response.status === "success") {
77+
setRecentPosts(response.data.posts || []);
78+
} else{
79+
throw new Error("내가 작성한 글 목록 조회 실패");
80+
}
81+
console.log(response);
6782
} catch {
6883
addToast("최근에 작성한 글 조회에 실패했습니다.");
6984
}
@@ -115,8 +130,8 @@ export default function Main() {
115130
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
116131
{groupList.map((group) => (
117132
<PublicGroupCard
118-
key={group.groupId}
119133
id={group.groupId}
134+
key={group.groupId}
120135
title={group.groupName}
121136
description={group.description}
122137
image={group.image}
@@ -160,13 +175,13 @@ export default function Main() {
160175
{recentPosts.length > 0 ? (
161176
recentPosts.map((item, idx) => (
162177
<MemoryCard
163-
key={item.id}
178+
key={idx}
164179
index={idx}
165180
title={item.title}
166-
date={item.date}
167-
memory={item.memory}
168-
sympathy={item.sympathy}
169-
comments={item.comments}
181+
date={dayjs(item.createdAt).format("YYYY.MM.DD")}
182+
group={item.group.groupName}
183+
sympathy={item.likeCount}
184+
comments={item.commentCount}
170185
/>
171186
))
172187
) : (

src/pages/Scrap.jsx

Lines changed: 99 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
import { useState } from 'react';
2-
import { useSearchParams } from 'react-router-dom';
1+
import {useEffect, useState} from 'react';
2+
import { useSearchParams, useNavigate } from 'react-router-dom';
3+
import dayjs from 'dayjs';
4+
5+
import {useToast} from "@/hooks/useToast.js";
6+
7+
import scrapService from "@/services/scrap/scrapService.js";
8+
9+
import NoScrapIcon from "@/assets/icon/scrap/no-scrap.svg";
310

4-
import GroupTab from '@/components/group/GroupTab';
511
import PublicPostCard from '@/components/group/PublicPostCard';
6-
import PrivatePostCard from '@/components/group/PrivatePostCard';
712
import Pagination from "@/components/common/Pagination";
813
import SearchBar from "@/components/common/SearchBar";
914
import SearchButton from "@/components/common/SearchButton";
1015
import Select from '@/components/common/Select';
16+
import NeedLoginToGuest from "@/components/modal/NeedLoginToGuest.jsx";
1117

1218
const GROUP_PARAMS = 'group';
1319

14-
const publicMemories = [
15-
{ author: "달봉이아들", visibility: "공개", title: '추억 글 제목', location: '인천 앞바다', date: '24.01.19', tags: ["태그", "길면", "두줄", "낚시", "인천"], likes: 120, comments: 8 },
16-
{ author: "달봉이아들", visibility: "공개", title: '추억 글 제목', location: '인천 앞바다', date: '24.02.01', tags: ["여행", "추억", "가족", "사진"], likes: 98, comments: 12 },
17-
];
18-
19-
const privateMemories = [
20-
{ author: "달봉이아들", visibility: "비공개", title: '추억 글 제목', date: '24.01.19', likes: 120, comments: 8 },
21-
{ author: "달봉이아들", visibility: "비공개", title: '추억 글 제목', date: '24.02.01', likes: 98, comments: 12 },
22-
];
2320

2421
const options = [
2522
{ label: "최신순", value: "latest" },
@@ -30,13 +27,57 @@ const options = [
3027

3128

3229
export default function Scrap () {
30+
const [isLogin, setIsLogin] = useState(false);
3331
const [searchTerm, setSearchTerm] = useState('');
3432
const [searchParams, setSearchParams] = useSearchParams();
3533
const [currentPage, setCurrentPage] = useState(1);
3634
const [sortBy, setSortBy] = useState(searchParams.get("sortBy") || "mostLiked");
37-
35+
const [totalPages, setTotalPages] = useState(10);
36+
const [memories, setMemories] = useState([]);
3837
const tabName = searchParams.get(GROUP_PARAMS) || 'Public';
39-
const totalPages = 10;
38+
39+
const navigate = useNavigate();
40+
const addToast = useToast();
41+
42+
/** 로그인 유무 판단 **/
43+
useEffect(() => {
44+
const token = localStorage.getItem("accessToken");
45+
46+
if (!token) {
47+
setIsLogin(false);
48+
} else {
49+
setIsLogin(true);
50+
}
51+
}, []);
52+
53+
/** 스크랩한 추억글 목록 불러오기 **/
54+
useEffect(() => {
55+
const fetchScrapList = async() => {
56+
try{
57+
const response = await scrapService.getScrapList({
58+
sortBy,
59+
keyword: searchTerm,
60+
page: currentPage,
61+
});
62+
63+
if (response.status === "success"){
64+
setMemories(response.data.data || []);
65+
setTotalPages(response.data.totalPages);
66+
} else{
67+
throw new Error("스크랩한 추억글 조회 실패");
68+
}
69+
70+
} catch{
71+
addToast("스크랩한 추억글 조회에 실패했습니다.");
72+
}
73+
}
74+
75+
fetchScrapList();
76+
},[searchTerm, sortBy, currentPage]);
77+
78+
useEffect(() => {
79+
setSortBy(searchParams.get("sortBy") || "mostLiked");
80+
}, [searchParams]);
4081

4182
const handleSearch = () => {
4283
console.log("검색어:", searchTerm);
@@ -53,14 +94,21 @@ export default function Scrap () {
5394
}
5495
};
5596

97+
const handleLoginModal = (state) => {
98+
if(state === "register") {
99+
navigate("/login");
100+
} else {
101+
navigate("/");
102+
}
103+
}
104+
56105
return (
57106
<div className="max-w-[95%] h-full pt-3 pb-7">
58107
<div className="flex items-center mb-2">
59108
<span className="text-darkViolet text-2xl font-semibold">스크랩</span>
60109
<span className="text-black text-2xl font-semibold">한 추억 글 목록</span>
61110
</div>
62111

63-
<GroupTab />
64112
<div
65113
className="flex mt-4 items-center gap-5"
66114
style={{ flexBasis: '60%' }}
@@ -83,32 +131,45 @@ export default function Scrap () {
83131
</div>
84132

85133
<div className="w-full mt-3 py-3">
86-
<div className="mt-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
87-
{tabName === "Public"
88-
? publicMemories.map((memory, index) =>
89-
<PublicPostCard
90-
key={index}
91-
id={index + 1}
92-
groupId={1}
93-
{...memory}
94-
/>)
95-
: privateMemories.map((memory, index) =>
96-
<PrivatePostCard
97-
key={index}
98-
id={index + 1}
99-
groupId={1}
100-
{...memory}
101-
/>)}
102-
</div>
134+
{memories.length > 0 ? (
135+
<div className="mt-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
136+
{memories.map((memory) =>
137+
<PublicPostCard
138+
key={memory.postId}
139+
id={memory.postId}
140+
groupId={memory.post?.groupId}
141+
title={memory.post?.title || "제목 없음"}
142+
tag={memory.post?.tag.length ? memory.post?.tag : ["태그 없음"]}
143+
moment={dayjs(memory.post?.moment).format('YYYY-MM-DD')}
144+
author={memory.post?.nickname || "알 수 없음"}
145+
imageUrl={memory.post?.imageUrl ? `https://${memory.post.imageUrl}` : null}
146+
location={memory.post?.location || "장소 정보 없음"}
147+
likeCount={memory.post?.likeCount ?? 0}
148+
commentCount={memory.post?.commentCount ?? 0}
149+
/>)}
150+
</div>
151+
):(
152+
<div className="bg-white min-w-[85vw] h-[80vh] max-h-[80vh] w-full rounded-[30px]">
153+
<div className="flex flex-col items-center justify-center h-full text-center text-gray-500">
154+
<img src={NoScrapIcon} alt="No Group" className="w-30 h-30 mb-4"/>
155+
<p className="text-lg font-semibold">스크랩된 추억글이 없습니다!</p>
156+
<p className="text-sm text-gray-400">가입된 그룹에서 마음에 드는 추억글을 스크랩 해보세요!</p>
157+
<button onClick={() => navigate("/group")} className="mt-4 px-5 py-2 bg-normalViolet hover:bg-normalViolet-hover active:bg-normalViolet-active text-white text-sm font-medium rounded-md">
158+
그룹 살펴보기
159+
</button>
160+
</div>
161+
</div>
162+
)}
103163
</div>
104164

105-
<div className="p-4">
165+
{memories.length > 0 && <div className="p-4">
106166
<Pagination
107-
currentPage={currentPage}
108-
totalPages={totalPages}
109-
onPageChange={handlePageChange}
167+
currentPage={currentPage}
168+
totalPages={totalPages}
169+
onPageChange={handlePageChange}
110170
/>
111-
</div>
171+
</div>}
172+
{!isLogin && <NeedLoginToGuest onClick={handleLoginModal}/>}
112173
</div>
113174
);
114175
}

src/services/scrap/scrapService.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const getScrapDetail = async (postId) => {
3030
};
3131

3232
/** 스크랩 목록 조회 (페이지네이션, 검색, 정렬) */
33-
export const getScrapList = async ({ page = 1, pageSize = 10, sortBy = "latest", keyword = "", isPublic = null, postId = null }) => {
33+
export const getScrapList = async ({ page = 1, pageSize = 10, sortBy = "latest", keyword = "", postId = null }) => {
3434
const token = localStorage.getItem("accessToken");
3535
if (!token) {
3636
throw new Error("인증 토큰이 없습니다. 다시 로그인해 주세요.");
@@ -44,11 +44,10 @@ export const getScrapList = async ({ page = 1, pageSize = 10, sortBy = "latest",
4444
pageSize,
4545
sortBy,
4646
keyword,
47-
isPublic,
4847
postId,
4948
},
5049
});
51-
return response.data.data;
50+
return response.data;
5251
} catch (error) {
5352
console.error("스크랩 목록 조회 오류:", error);
5453
throw new Error(error.response?.data?.message || "스크랩 목록 조회 중 오류 발생");

0 commit comments

Comments
 (0)