Skip to content

Commit 266d0e5

Browse files
authored
feat: 편지 공유 요청 수신 조회 기능 구현 (#90)
* feat: 편지 공유 요청 수신 조회 기능 구현 * refactor: incomingLetters.ts 코드 리팩토링 * refactor: incomingLettersStore.ts에서 필요 없는 필드 정리 * feat: 오고 있는 편지 도착까지 걸리는 시간 카운트다운 기능 구현 * design: 오고 있는 편지 모달에서 데이터가 없을 때 대체 텍스트 추가 * design: 임시저장된 편지 모달에서 데이터가 없을 때 대체 텍스트 추가 * design: 편지 공유 요청 수신 조회 모달에서 데이터가 없을 때 대체 텍스트 추가
1 parent 62d67cd commit 266d0e5

File tree

6 files changed

+105
-83
lines changed

6 files changed

+105
-83
lines changed

src/apis/incomingLetters.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
import client from './client';
22

3-
export const getIncomingLetters = async (token: string) => {
3+
export const getIncomingLetters = async () => {
44
try {
5-
const { data } = await client.get('/api/letters?status=delivery', {
6-
headers: {
7-
Authorization: `Bearer ${token}`,
8-
},
9-
});
10-
console.log('불러온 데이터', data);
5+
const { data } = await client.get('/api/letters?status=delivery');
6+
console.log('오고있는 편지 데이터', data);
117
return data;
128
} catch (error) {
139
console.error('❌오고 있는 편지 목록을 불러오던 중 에러 발생', error);

src/apis/share.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface SharePost {
2121
letters: ShareLetter[];
2222
}
2323

24-
// 페이징 포함
24+
// 공유 게시글 목록 조회 - 페이징 포함
2525
export interface SharePostResponse {
2626
content: SharePost[];
2727
currentPage: number;
@@ -30,6 +30,15 @@ export interface SharePostResponse {
3030
totalPages: number;
3131
}
3232

33+
// 편지 공유 요청 수신 조회
34+
export interface ShareProposal {
35+
shareProposalId: number;
36+
requesterZipCode: string;
37+
recipientZipCode: string;
38+
message: string;
39+
status: 'REJECTED' | 'APPROVED' | 'PENDING';
40+
}
41+
3342
// 편지 공유 수락 / 거절
3443
export interface SharePostApproval {
3544
shareProposalId: number;
@@ -84,6 +93,19 @@ export const postShareProposals = async (
8493
}
8594
};
8695

96+
// 편지 공유 요청 수신 조회
97+
export const getShareProposalList = async () => {
98+
try {
99+
const response = await client.get('/api/share-proposals/inbox');
100+
console.log(`🌟공유 요청 목록`, response.data);
101+
102+
return response.data.data;
103+
} catch (error) {
104+
console.error('❌ 편지 공유 요청을 조회하던 중 에러가 발생했습니다', error);
105+
throw error;
106+
}
107+
};
108+
87109
// 편지 공유 수락 / 거절
88110
export const postShareProposalApproval = async (
89111
shareProposalId: number,

src/pages/Home/components/ShowDraftModal.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,26 @@ const ShowDraftModal = ({ onClose }: ShowDraftModalProps) => {
6060
<p className="caption-r text-black">로그아웃 시 임시 저장된 편지는 사라집니다</p>
6161
</div>
6262
<div className="mt-6 flex max-h-60 min-h-auto w-[251px] flex-col gap-[10px] overflow-y-scroll [&::-webkit-scrollbar]:hidden">
63-
{draftLetters.map((draft) => (
64-
<div
65-
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
66-
key={draft.letterId}
67-
// onClick={() => handleNavigation(draft.letterId)}
68-
>
69-
<p className="truncate">{draft.title}</p>
63+
{draftLetters.length > 0 ? (
64+
draftLetters.map((draft) => (
7065
<div
71-
className="text-gray-20 active:text-gray-600"
72-
tabIndex={0}
73-
onClick={() => handleDeleteDraftLetters(draft.letterId)}
66+
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
67+
key={draft.letterId}
68+
// onClick={() => handleNavigation(draft.letterId)}
7469
>
75-
<DeleteOutlineRoundedIcon />
70+
<p className="truncate">{draft.title}</p>
71+
<div
72+
className="text-gray-20 active:text-gray-600"
73+
tabIndex={0}
74+
onClick={() => handleDeleteDraftLetters(draft.letterId)}
75+
>
76+
<DeleteOutlineRoundedIcon />
77+
</div>
7678
</div>
77-
</div>
78-
))}
79+
))
80+
) : (
81+
<p className="caption-m text-center text-gray-50">작성 중인 편지가 없어요</p>
82+
)}
7983
</div>
8084
</ModalBackgroundWrapper>
8185
</div>

src/pages/Home/components/ShowIncomingLettersModal.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@ const ShowIncomingLettersModal = ({ onClose }: ShowIncomingLettersModalProps) =>
2929
<p className="caption-r text-black">시간은 실제 시간을 기반으로 책정됩니다.</p>
3030
</div>
3131
<div className="mt-6 flex max-h-60 min-h-auto w-[251px] flex-col gap-[10px] overflow-y-scroll [&::-webkit-scrollbar]:hidden">
32-
{data.map((letter) => (
33-
<div
34-
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
35-
key={letter.letterId}
36-
>
37-
<p className="truncate">{letter.title}</p>
38-
<p>{letter.remainingTime}</p>
39-
</div>
40-
))}
32+
{data.length > 0 ? (
33+
data.map((letter) => (
34+
<div
35+
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
36+
key={letter.letterId}
37+
>
38+
<p className="truncate">{letter.title}</p>
39+
<p>{letter.remainingTime}</p>
40+
</div>
41+
))
42+
) : (
43+
<p className="caption-m text-center text-gray-50">오고 있는 편지가 없어요</p>
44+
)}
4145
</div>
4246
</ModalBackgroundWrapper>
4347
</div>

src/pages/Home/components/ShowShareAccessModal.tsx

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import React, { useEffect, useState } from 'react';
22
import { useNavigate } from 'react-router';
33

4-
import { getSharePostDetail, getSharePostList } from '@/apis/share';
5-
import { SharePostResponse, SharePost } from '@/apis/share';
4+
import { getSharePostDetail } from '@/apis/share';
5+
import { getShareProposalList } from '@/apis/share';
6+
import { ShareProposal } from '@/apis/share';
7+
68
import ModalBackgroundWrapper from '@/components/ModalBackgroundWrapper';
79
import ModalOverlay from '@/components/ModalOverlay';
810

@@ -14,35 +16,22 @@ interface ShowShareAccessModalProps {
1416
const ShowShareAccessModal = ({ onClose }: ShowShareAccessModalProps) => {
1517
const navigate = useNavigate();
1618

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-
};
19+
const [shareProposals, setShareProposals] = useState<ShareProposal[]>([]);
3020

3121
useEffect(() => {
32-
fetchPosts(currentPage);
33-
}, [currentPage]);
34-
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-
};
22+
getShareProposalList()
23+
.then((data) => {
24+
setShareProposals(data || []);
25+
})
26+
.catch((error) => {
27+
console.error('❌ 공유 요청 목록을 불러오는 데 실패했습니다.', error);
28+
});
29+
}, []);
4130

42-
const handleNavigation = async (sharePostId: number) => {
31+
const handleNavigation = async (shareProposalId: number) => {
4332
try {
44-
const postDetail = await getSharePostDetail(sharePostId);
45-
navigate(`/board/letter/${sharePostId}`, {
33+
const postDetail = await getSharePostDetail(shareProposalId);
34+
navigate(`/board/letter/${shareProposalId}`, {
4635
state: { postDetail, isShareLetterPreview: true },
4736
});
4837
} catch (error) {
@@ -65,19 +54,20 @@ const ShowShareAccessModal = ({ onClose }: ShowShareAccessModalProps) => {
6554
허락 여부를 체크해주세요!
6655
</p>
6756
</div>
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) => (
73-
<button
74-
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
75-
key={post.sharePostId}
76-
onClick={() => handleNavigation(post.sharePostId)}
77-
>
78-
<p>{post.writerZipCode}님의 공유 요청</p>
79-
</button>
80-
))}
57+
<div className="mt-6 flex max-h-60 min-h-auto w-[251px] flex-col gap-[10px] overflow-y-scroll [&::-webkit-scrollbar]:hidden">
58+
{shareProposals.length > 0 ? (
59+
shareProposals.map((proposal) => (
60+
<button
61+
className="text-gray-80 body-m flex h-10 w-full items-center justify-between gap-1 rounded-lg bg-white p-3"
62+
key={proposal.shareProposalId}
63+
onClick={() => handleNavigation(proposal.shareProposalId)}
64+
>
65+
<p>{proposal.requesterZipCode}님의 공유 요청</p>
66+
</button>
67+
))
68+
) : (
69+
<p className="caption-m text-center text-gray-50">새로운 공유 요청이 없어요</p>
70+
)}
8171
</div>
8272
</ModalBackgroundWrapper>
8373
</div>

src/stores/incomingLettersStore.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ interface IncomingLetters {
1212

1313
interface IncomingLettersStore {
1414
data: IncomingLetters[];
15-
arrivedCount: number;
16-
message: string;
17-
timestamp: string;
1815
fetchIncomingLetters: () => void;
1916
}
2017

@@ -36,31 +33,40 @@ const calculatingRemainingTime = (deliveryCompletedAt: string): string => {
3633

3734
export const useIncomingLettersStore = create<IncomingLettersStore>((set) => ({
3835
data: [],
39-
arrivedCount: 0,
40-
message: '',
41-
timestamp: '',
4236
fetchIncomingLetters: async () => {
4337
try {
44-
const token = localStorage.getItem('token') || '';
45-
const data = await getIncomingLetters(token);
38+
const data = await getIncomingLetters();
4639

47-
let arrivedCount = 0;
4840
const updatedLetters = data.data.map((letter: IncomingLetters) => {
4941
const remainingTime = calculatingRemainingTime(letter.deliveryCompletedAt);
50-
if (remainingTime === '00:00:00') arrivedCount += 1; // 도착한 편지 카운트
5142

5243
return { ...letter, remainingTime };
5344
});
5445

5546
const inProgressLetters = updatedLetters.filter(
5647
(letter: IncomingLetters) => letter.remainingTime !== '00:00:00',
5748
);
49+
5850
set({
5951
data: inProgressLetters,
60-
arrivedCount,
61-
message: data.message,
62-
timestamp: data.timestamp,
6352
});
53+
54+
setInterval(() => {
55+
set((state) => {
56+
const updatedLetters = state.data.map((letter: IncomingLetters) => {
57+
const remainingTime = calculatingRemainingTime(letter.deliveryCompletedAt);
58+
return { ...letter, remainingTime };
59+
});
60+
61+
const filteredLetters = updatedLetters.filter(
62+
(letter) => letter.remainingTime !== '00:00:00',
63+
);
64+
65+
return {
66+
data: filteredLetters,
67+
};
68+
});
69+
}, 1000);
6470
} catch (error) {
6571
console.error('❌오고 있는 편지 목록을 불러오던 중 에러 발생', error);
6672
}

0 commit comments

Comments
 (0)