Skip to content

Commit dca90d6

Browse files
authored
feat: 임시저장된 편지 삭제 기능 구현 (#84)
* fix: 공유 게시글 목록 페이지네이션에서 무한 스크롤로 전환 * refactor: 필요없는 코드 삭제 * feat: 임시저장된 편지 삭제 기능 구현 * design: 임시저장 편지 삭제 아이콘 클릭 시 색상 변경
1 parent 177f8cf commit dca90d6

File tree

3 files changed

+69
-25
lines changed

3 files changed

+69
-25
lines changed

src/apis/draftLetters.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,30 @@ export interface DraftLetter {
1616
matched: boolean;
1717
}
1818

19-
export const getDraftLetters = async () // token: string
20-
: Promise<DraftLetter[]> => {
19+
export const getDraftLetters = async (): Promise<DraftLetter[]> => {
2120
try {
22-
const { data } = await client.get('/api/letters?status=draft', {
23-
// headers: {
24-
// Authorization: `Bearer ${token}`,
25-
// },
26-
});
21+
const { data } = await client.get('/api/letters?status=draft', {});
2722
console.log('임시저장된 편지 데이터', data);
2823
return data.data;
2924
} catch (error) {
30-
console.error(`❌임시저장된 편지를 불러오던 중 에러가 발생했습니다`, error);
25+
console.error('❌임시저장된 편지를 불러오던 중 에러가 발생했습니다', error);
3126
throw new Error('임시저장된 편지 불러오기 실패');
3227
}
3328
};
29+
30+
export const deleteDraftLetters = async (letterId: number) => {
31+
try {
32+
const { data } = await client.delete(`/api/letters/${letterId}/temporary-save`);
33+
34+
if (data.data?.letterId) {
35+
console.log('삭제된 임시저장 편지 ID:', data.data.letterId);
36+
} else {
37+
console.error('❌서버 응답에 letterId가 존재하지 않습니다.');
38+
}
39+
40+
return data.data.letterId;
41+
} catch (error) {
42+
console.error('❌임시저장된 편지를 삭제하던 중 에러가 발생했습니다:', error);
43+
throw error;
44+
}
45+
};

src/pages/Home/components/ShowDraftModal.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';
22
import React, { useEffect, useState } from 'react';
33
// import { useNavigate } from 'react-router';
44

5-
import { DraftLetter, getDraftLetters } from '@/apis/draftLetters';
5+
import { DraftLetter, getDraftLetters, deleteDraftLetters } from '@/apis/draftLetters';
66
import ModalBackgroundWrapper from '@/components/ModalBackgroundWrapper';
77
import ModalOverlay from '@/components/ModalOverlay';
88

@@ -22,14 +22,29 @@ const ShowDraftModal = ({ onClose }: ShowDraftModalProps) => {
2222
// });
2323
// };
2424

25-
useEffect(() => {
25+
const handleGetDraftLetters = () => {
2626
getDraftLetters()
2727
.then((data) => {
2828
setDraftLetters(data || []);
2929
})
3030
.catch((error) => {
3131
console.error('❌ 임시저장된 편지를 불러오는데 실패했습니다', error);
3232
});
33+
};
34+
35+
const handleDeleteDraftLetters = async (letterId: number) => {
36+
//TODO: 정말로 삭제하시겠습니까? 모달창
37+
try {
38+
await deleteDraftLetters(letterId);
39+
setDraftLetters((prev) => prev.filter((letter) => letter.letterId !== letterId));
40+
console.log(`letterId는 `, letterId);
41+
} catch (error) {
42+
console.error(`❌임시저장된 편지를 삭제하던 중 에러가 발생했습니다.`, error);
43+
}
44+
};
45+
46+
useEffect(() => {
47+
handleGetDraftLetters();
3348
}, [onClose]);
3449

3550
return (
@@ -52,7 +67,11 @@ const ShowDraftModal = ({ onClose }: ShowDraftModalProps) => {
5267
// onClick={() => handleNavigation(draft.letterId)}
5368
>
5469
<p className="truncate">{draft.title}</p>
55-
<div className="text-gray-20">
70+
<div
71+
className="text-gray-20 active:text-gray-600"
72+
tabIndex={0}
73+
onClick={() => handleDeleteDraftLetters(draft.letterId)}
74+
>
5675
<DeleteOutlineRoundedIcon />
5776
</div>
5877
</div>

src/pages/Home/components/ShowShareAccessModal.tsx

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
22
import { useNavigate } from 'react-router';
33

44
import { getSharePostDetail, getSharePostList } from '@/apis/share';
5-
import { SharePostResponse } from '@/apis/share';
5+
import { SharePostResponse, SharePost } from '@/apis/share';
66
import ModalBackgroundWrapper from '@/components/ModalBackgroundWrapper';
77
import ModalOverlay from '@/components/ModalOverlay';
88

@@ -14,20 +14,30 @@ interface ShowShareAccessModalProps {
1414
const ShowShareAccessModal = ({ onClose }: ShowShareAccessModalProps) => {
1515
const navigate = useNavigate();
1616

17-
const [sharePosts, setSharePosts] = useState<SharePostResponse>();
17+
const [sharePosts, setSharePosts] = useState<SharePost[]>([]);
18+
const [currentPage, setCurrentPage] = useState(1);
19+
const [hasMore, setHasMore] = useState(true);
20+
21+
const fetchPosts = async (page: number) => {
22+
try {
23+
const data: SharePostResponse = await getSharePostList(page, 10);
24+
setSharePosts((prev) => [...prev, ...data.content]);
25+
setHasMore(page < data.totalPages);
26+
} catch (error) {
27+
console.error('❌ 게시글 목록을 불러오는 데 실패했습니다.', error);
28+
}
29+
};
1830

1931
useEffect(() => {
20-
const fetchPosts = async () => {
21-
try {
22-
const data = await getSharePostList(1, 10);
23-
setSharePosts(data);
24-
} catch (error) {
25-
console.error('❌ 게시글 목록을 불러오는 데 실패했습니다.', error);
26-
}
27-
};
32+
fetchPosts(currentPage);
33+
}, [currentPage]);
2834

29-
fetchPosts();
30-
}, []);
35+
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
36+
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
37+
if (scrollTop + clientHeight >= scrollHeight - 10 && hasMore) {
38+
setCurrentPage((prev) => prev + 1);
39+
}
40+
};
3141

3242
const handleNavigation = async (sharePostId: number) => {
3343
try {
@@ -55,8 +65,11 @@ const ShowShareAccessModal = ({ onClose }: ShowShareAccessModalProps) => {
5565
허락 여부를 체크해주세요!
5666
</p>
5767
</div>
58-
<div className="mt-6 flex max-h-60 min-h-auto w-[251px] flex-col gap-[10px] overflow-y-scroll [&::-webkit-scrollbar]:hidden">
59-
{sharePosts?.content.map((post) => (
68+
<div
69+
className="mt-6 flex max-h-60 min-h-auto w-[251px] flex-col gap-[10px] overflow-y-scroll [&::-webkit-scrollbar]:hidden"
70+
onScroll={handleScroll}
71+
>
72+
{sharePosts?.map((post) => (
6073
<button
6174
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
6275
key={post.sharePostId}

0 commit comments

Comments
 (0)