Skip to content

Commit 6d821ae

Browse files
committed
refactor: 내 편지함 및 상세 querykey 적용
- useState을 삭제 하고 데이터 관리 및 성능 최적화를 위해 tanstack query 적용
1 parent 3dcac47 commit 6d821ae

File tree

5 files changed

+118
-68
lines changed

5 files changed

+118
-68
lines changed

src/apis/mailBox.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export const getMailbox = async () => {
1212

1313
export const getMailboxDetail = async (id: number) => {
1414
try {
15+
// const response = await client.get(`/api/mailbox/${id}/page=${pageParam}&size=20`);
1516
const response = await client.get(`/api/mailbox/${id}`);
17+
1618
if (!response) throw new Error('error while fetching mailbox detail data');
1719
return response.data;
1820
} catch (error) {

src/pages/LetterBox/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const LetterBoxPage = () => {
6161
boxId={data.letterMatchingId}
6262
key={index}
6363
zipCode={data.oppositeZipCode}
64-
letterCount={90}
64+
letterCount={data.letterCount}
6565
isChecked={data.oppositeRead}
6666
isClosed={data.active}
6767
/>

src/pages/LetterBoxDetail/components/LetterPreview.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useNavigate } from 'react-router';
22

33
import LetterWrapper from '@/components/LetterWrapper';
4+
import formatDate from '@/utils/formatDate';
45

56
interface LetterPreviewProps {
67
id: number;
@@ -41,7 +42,7 @@ const LetterPreview = ({
4142
return (
4243
<LetterWrapper isSender={isSend}>
4344
<div className="mb-3 flex items-center justify-between">
44-
<p className="body-r text-gray-80">{date}</p>
45+
<p className="body-r text-gray-80">{formatDate(date)}</p>
4546
<label htmlFor={`${id}`} className="relative">
4647
<input
4748
id={`${id}`}

src/pages/LetterBoxDetail/index.tsx

Lines changed: 102 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ChangeEvent, useEffect, useState } from 'react';
1+
import { useMutation, useQuery } from '@tanstack/react-query';
2+
import { ChangeEvent, useState } from 'react';
23
import { useLocation, useNavigate } from 'react-router';
34

45
import { getMailboxDetail, postMailboxDisconnect } from '@/apis/mailBox';
@@ -10,19 +11,19 @@ import PageTitle from '@/components/PageTitle';
1011
import InformationTooltip from './components/InformationTooltip';
1112
import LetterPreview from './components/LetterPreview';
1213

13-
const LetterBoxDetailPage = () => {
14-
interface MailBoxDetailProps {
15-
letterId: number;
16-
title: string;
17-
myLetter: boolean;
18-
active: boolean;
19-
// createdAt: date;
20-
}
14+
// import useAuthStore from '@/stores/authStore';
15+
interface MailBoxDetailProps {
16+
letterId: number;
17+
title: string;
18+
myLetter: boolean;
19+
active: boolean;
20+
createdAt: string;
21+
}
2122

23+
const LetterBoxDetailPage = () => {
2224
const location = useLocation();
2325
const userInfo = { ...location.state };
24-
25-
const [mailLists, setMailLists] = useState<MailBoxDetailProps[] | []>([]);
26+
// const {userId} = useAuthStore.getState();
2627

2728
const [isShareMode, setShareMode] = useState(false);
2829
const [isOpenDisConnectModal, setIsOpenDisConnectModal] = useState(false);
@@ -32,20 +33,71 @@ const LetterBoxDetailPage = () => {
3233

3334
const navigate = useNavigate();
3435

35-
const fetchData = async () => {
36-
try {
37-
const response = await getMailboxDetail(userInfo.id || '');
38-
if (!response) throw new Error('LetterBoxDetailPage, fetchData error');
39-
setMailLists(response.data);
36+
// const {
37+
// data: mailLists = [],
38+
// isLoading,
39+
// isError,
40+
// fetchNextPage,
41+
// hasNextPage,
42+
// isFetchingNextPage,
43+
// } = useInfiniteQuery({
44+
// queryKey: ['mailBoxDetail', userInfo.id],
45+
// queryFn: async ({ pageParam }) => {
46+
// const response = await getMailboxDetail(userInfo.id, pageParam);
47+
// console.log(response.data);
48+
// return response.data as MailBoxDetailProps[];
49+
// },
50+
// enabled: !!userInfo.id,
51+
// initialPageParam: 0,
52+
// getNextPageParam: (lastPage, allPages) => {
53+
// return lastPage?.length == 0 || !lastPage || lastPage?.length < 20
54+
// ? undefined
55+
// : allPages.length + 1;
56+
// },
57+
// staleTime: 1000 * 60 * 5,
58+
// gcTime: 1000 * 60 * 10,
59+
// });
60+
61+
const {
62+
data: mailLists = [],
63+
isLoading,
64+
isError,
65+
} = useQuery({
66+
queryKey: ['mailBoxDetail', userInfo.id],
67+
queryFn: async () => {
68+
const response = await getMailboxDetail(userInfo.id);
4069
console.log(response.data);
41-
} catch (error) {
70+
return response.data as MailBoxDetailProps[];
71+
},
72+
staleTime: 1000 * 60 * 5,
73+
gcTime: 1000 * 60 * 10,
74+
});
75+
76+
const disconnectMutation = useMutation({
77+
mutationFn: async () => await postMailboxDisconnect(userInfo.id),
78+
onSuccess: () => {
79+
navigate(-1);
80+
},
81+
onError: (error) => {
82+
// TODO: 차단 실패 toastUI 띄워주기
83+
// 요청이 실패했어요 잠시 후에 다시 시도해주세요.
4284
console.error(error);
43-
}
44-
};
45-
46-
useEffect(() => {
47-
fetchData();
48-
}, []);
85+
},
86+
});
87+
88+
const shareMutation = useMutation({
89+
// Todo : useAuthStore -> myId 대체
90+
mutationFn: () => postShareProposals(selected, 1, userInfo.id, shareComment),
91+
onSuccess: () => {
92+
toggleShareMode();
93+
setShareComment('');
94+
},
95+
onError: (error) => {
96+
// TODO: 차단 실패 toastUI 띄워주기
97+
// 요청이 실패했어요 잠시 후에 다시 시도해주세요.
98+
console.error(error);
99+
},
100+
});
49101

50102
const toggleShareMode = () => {
51103
if (isShareMode) {
@@ -66,27 +118,9 @@ const LetterBoxDetailPage = () => {
66118
setShareComment(e.target.value);
67119
};
68120

69-
const handleDisconnect = async () => {
70-
try {
71-
const response = await postMailboxDisconnect(userInfo.id);
72-
if (!response) throw new Error('letterBoxDetail, disconnecting failed');
73-
console.log(response);
74-
navigate(-1);
75-
} catch (error) {
76-
console.error(error);
77-
}
78-
};
79-
80-
const handleShare = async () => {
81-
try {
82-
// TODO: myId -> 전역객체에서 가져오기
83-
const response = await postShareProposals(selected, 1, userInfo.id, shareComment);
84-
if (!response) throw new Error(response);
85-
console.log(response);
86-
} catch (error) {
87-
console.error(error);
88-
}
89-
};
121+
if (isError) {
122+
navigate('/NotFound');
123+
}
90124

91125
return (
92126
<>
@@ -99,7 +133,7 @@ const LetterBoxDetailPage = () => {
99133
onCancel={() => setIsOpenDisConnectModal(false)}
100134
onConfirm={() => {
101135
setIsOpenDisConnectModal(false);
102-
handleDisconnect();
136+
disconnectMutation.mutate();
103137
}}
104138
/>
105139
)}
@@ -117,9 +151,7 @@ const LetterBoxDetailPage = () => {
117151
}}
118152
onComplete={() => {
119153
setIsOpenShareModal(false);
120-
handleShare();
121-
toggleShareMode();
122-
setShareComment('');
154+
shareMutation.mutate();
123155
}}
124156
>
125157
<p className="text-gray-70 body-m mt-1">상대방 동의 후에 게시글이 업로드 됩니다.</p>
@@ -136,30 +168,34 @@ const LetterBoxDetailPage = () => {
136168
<div className="flex items-center gap-0.5 underline">
137169
{!userInfo.isClosed && (
138170
<button type="button" onClick={toggleShareMode}>
139-
{isShareMode ? '취소하기' : '편지 공유하기'}
171+
{isLoading ? '' : isShareMode ? '취소하기' : '편지 공유하기'}
140172
</button>
141173
)}
142-
{!isShareMode && !userInfo.isClosed && <InformationTooltip />}
174+
{!isShareMode && !userInfo.isClosed && !isLoading && <InformationTooltip />}
143175
</div>
144176
</section>
145177
<section className="mb-5 flex flex-col gap-4">
146-
{mailLists.map((letter) => (
147-
<LetterPreview
148-
key={letter.letterId}
149-
id={letter.letterId}
150-
// TODO: createdAt 추가해주시면 수정
151-
date={'2025.01.01'}
152-
title={letter.title}
153-
isSend={letter.myLetter}
154-
checked={selected.includes(letter.letterId)}
155-
isShareMode={isShareMode}
156-
isClosed={userInfo.isClosed}
157-
onToggle={() => toggleSelected(letter.letterId)}
158-
zipCode={userInfo.zipCode}
159-
/>
160-
))}
178+
{isLoading ? (
179+
//TODO: skeleton
180+
<div>Loading</div>
181+
) : (
182+
mailLists.map((letter) => (
183+
<LetterPreview
184+
key={letter.letterId}
185+
id={letter.letterId}
186+
date={letter.createdAt}
187+
title={letter.title}
188+
isSend={letter.myLetter}
189+
checked={selected.includes(letter.letterId)}
190+
isShareMode={isShareMode}
191+
isClosed={userInfo.isClosed}
192+
onToggle={() => toggleSelected(letter.letterId)}
193+
zipCode={userInfo.zipCode}
194+
/>
195+
))
196+
)}
161197
</section>
162-
{!isShareMode && !userInfo.isClosed && (
198+
{!isShareMode && !userInfo.isClosed && !isLoading && (
163199
<button
164200
type="button"
165201
className="body-sb text-gray-60 mt-auto text-left underline"

src/utils/formatDate.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const formatDate = (isoString: string) => {
2+
const date = new Date(isoString);
3+
return date
4+
.toLocaleDateString('ko-KR', {
5+
year: 'numeric',
6+
month: '2-digit',
7+
day: '2-digit',
8+
})
9+
.replace(/-/g, '.');
10+
};
11+
export default formatDate;

0 commit comments

Comments
 (0)