Skip to content

Commit 2fb1cc6

Browse files
authored
fix: QA 반영 (#112)
* feat: ToastUI 적용 -내 편지함의 alert를 toastUI로 변경했습니다. * fix: letterBoard length 없음 문제 해결 - 계속 확인 필 * Fix: - 헤더 뒤로가기를 홈으로 가기로 변경 - 편지함 캐싱 수정 -> 새로고침시 데이터 잘 불러와짐 - 신고 타입 수정 - mailbox 타입 분리 - mailBox 공유시 id를 상대방 id로 수정 * fix: 추가 커밋 * fix: 내 게시물 삭제 아이콘 표시, query key 중복 오류 해결 * fix: 파비콘 경로 수정 * fix: 새로고침시 데이터 바로 반영 * fix: 탈퇴한 회원 로그인 페이지로 리디렉션 * Feat: Menu 버튼 추가 * fix: build 오류 해결 --------- Co-authored-by: nirii00 <[email protected]>
1 parent 6059368 commit 2fb1cc6

File tree

17 files changed

+207
-180
lines changed

17 files changed

+207
-180
lines changed

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="kr">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/public/favicon.ico" />
5+
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>36.5</title>
88
<link

src/components/HomeButton.tsx

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

src/components/MenuButton.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import MenuRoundedIcon from '@mui/icons-material/MenuRounded';
2+
import EditNoteRoundedIcon from '@mui/icons-material/EditNoteRounded';
3+
import MarkunreadOutlinedIcon from '@mui/icons-material/MarkunreadOutlined';
4+
import CalendarTodayOutlinedIcon from '@mui/icons-material/CalendarTodayOutlined';
5+
6+
import { useState } from 'react';
7+
import { Link } from 'react-router';
8+
import { twMerge } from 'tailwind-merge';
9+
10+
export default function MenuButton() {
11+
const [isOpen, setIsOpen] = useState(false);
12+
13+
return (
14+
<>
15+
<div className="flex w-full max-w-150 justify-end pr-5 text-center">
16+
<Link
17+
to="/letter/box"
18+
className={twMerge(
19+
'bg-primary-3 fixed bottom-[220px] z-50 h-12 w-12 rotate-360 content-center rounded-full text-white transition-all duration-200 hover:scale-105 active:scale-90',
20+
isOpen
21+
? 'translate-y-0 rotate-0 opacity-100'
22+
: 'translate-y-[120%] rotate-180 opacity-0',
23+
)}
24+
>
25+
<MarkunreadOutlinedIcon fontSize="small" onClick={() => setIsOpen(false)} />
26+
</Link>
27+
<Link
28+
to="/board/letter"
29+
className={twMerge(
30+
'bg-primary-3 fixed bottom-[160px] z-50 h-12 w-12 rotate-360 content-center rounded-full text-white transition-all duration-200 hover:scale-105 active:scale-90',
31+
isOpen
32+
? 'translate-y-0 rotate-0 opacity-100'
33+
: 'translate-y-[120%] rotate-180 opacity-0',
34+
)}
35+
>
36+
<CalendarTodayOutlinedIcon fontSize="small" onClick={() => setIsOpen(false)} />
37+
</Link>
38+
<Link
39+
to="/letter/write"
40+
className={twMerge(
41+
'bg-primary-3 fixed bottom-[100px] z-50 h-12 w-12 rotate-360 content-center rounded-full text-white transition-all duration-200 hover:scale-105 active:scale-90',
42+
isOpen
43+
? 'translate-y-0 rotate-0 opacity-100'
44+
: 'translate-y-[120%] rotate-180 opacity-0',
45+
)}
46+
>
47+
<EditNoteRoundedIcon fontSize="medium" onClick={() => setIsOpen(false)} />
48+
</Link>
49+
50+
<div
51+
className={twMerge(
52+
'bg-primary-3 fixed bottom-[30px] z-50 h-13 w-13 content-center rounded-full text-white transition-all duration-200 hover:scale-105 active:scale-90',
53+
isOpen ? 'rotate-90' : 'rotate-0',
54+
)}
55+
>
56+
<MenuRoundedIcon onClick={() => setIsOpen((state) => !state)} />
57+
</div>
58+
</div>
59+
</>
60+
);
61+
}

src/layouts/Header.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { Link, useNavigate } from 'react-router';
33
import { AlarmIcon, ArrowLeftIcon, PersonIcon } from '@/assets/icons';
44

55
const Header = () => {
6-
// TODO: 뒤로 가기 버튼이 보이는 조건 추가
7-
// TODO: 스크롤 발생 시, 어떻게 보여져야 하는지
86
const navigate = useNavigate();
97
return (
108
<header className="fixed top-0 z-40 flex h-16 w-full max-w-150 items-center justify-between p-5">

src/pages/Auth/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,12 @@ const AuthCallbackPage = () => {
6969

7070
useEffect(() => {
7171
if (!stateToken) {
72-
navigate('/notFound');
7372
if (error === 'deleted_member') {
74-
alert('탈퇴한 회원입니다.');
73+
navigate('/login');
74+
alert('탈퇴한 회원입니다. 관리자에게 문의 부탁드립니다.');
75+
return;
7576
}
77+
navigate('/notFound');
7678
return;
7779
}
7880

src/pages/Home/index.tsx

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

4-
import HomeButton from '@/components/HomeButton';
4+
import MenuButton from '@/components/MenuButton';
55
import NoticeRollingPaper from '@/components/NoticeRollingPaper';
66
import useViewport from '@/hooks/useViewport';
77
import useAuthStore from '@/stores/authStore';
@@ -46,7 +46,7 @@ const HomePage = () => {
4646
</section>
4747
</div>
4848

49-
<HomeButton />
49+
<MenuButton />
5050
</div>
5151
);
5252
};

src/pages/LetterBoard/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import NoticeRollingPaper from '@/components/NoticeRollingPaper';
99
import PageTitle from '@/components/PageTitle';
1010

1111
import LetterPreview from './components/LetterPreview';
12+
import MenuButton from '@/components/MenuButton';
1213

1314
const LetterBoardPage = () => {
1415
const navigate = useNavigate();
@@ -21,7 +22,7 @@ const LetterBoardPage = () => {
2122
console.error('게시글 목록을 불러오는데 실패했습니다.');
2223
return { content: [], currentPage: page, totalPages: 1 };
2324
}
24-
console.log('page', response);
25+
console.log('게시글 목록', response);
2526
return response as SharePostResponse;
2627
} catch (e) {
2728
console.error(e);
@@ -38,11 +39,15 @@ const LetterBoardPage = () => {
3839
getNextPageParam: (res) => {
3940
if (!res || !res?.content || res?.currentPage >= res?.totalPages) {
4041
return undefined;
42+
} else if (res) {
43+
return res.currentPage + 1;
4144
}
42-
return res.currentPage + 1;
4345
},
4446
staleTime: 1000 * 60 * 5,
4547
gcTime: 1000 * 60 * 10,
48+
refetchOnMount: true,
49+
refetchOnReconnect: true,
50+
refetchOnWindowFocus: true,
4651
});
4752

4853
const postLists = data?.pages?.flatMap((page) => page?.content || []) || [];
@@ -95,6 +100,7 @@ const LetterBoardPage = () => {
95100
</p>
96101
)}
97102
</main>
103+
<MenuButton />
98104
<BackgroundBottom />
99105
</>
100106
);

src/pages/LetterBoardDetail/components/Header.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Link, useNavigate } from 'react-router';
1+
import { useNavigate } from 'react-router';
22

33
import {
44
ArrowLeftIcon,
@@ -30,16 +30,9 @@ const Header = ({
3030
return (
3131
<header className="fixed top-0 z-40 w-full max-w-150">
3232
<div className="flex h-16 items-center justify-between bg-white p-5">
33-
{isShareLetterPreview ? (
34-
<button onClick={() => navigate(-1)}>
35-
<ArrowLeftIcon className="text-primary-1 h-6 w-6" />
36-
</button>
37-
) : (
38-
<Link to="/board/letter">
39-
<ArrowLeftIcon className="text-primary-1 h-6 w-6" />
40-
</Link>
41-
)}
42-
33+
<button onClick={() => navigate(-1)}>
34+
<ArrowLeftIcon className="text-primary-1 h-6 w-6" />
35+
</button>
4336
{!isShareLetterPreview && (
4437
<div className="flex items-center gap-3">
4538
<div className="flex items-center gap-1">
@@ -53,6 +46,7 @@ const Header = ({
5346
<p className="body-l-m text-primary-1">{likeCount}</p>
5447
</div>
5548
{isWriter ? (
49+
// TODO: 게시물 삭제
5650
<DeleteIcon className="text-primary-1 h-6 w-6" />
5751
) : (
5852
<button type="button" onClick={onOpenReportModal}>

src/pages/LetterBoardDetail/index.tsx

Lines changed: 30 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,31 @@
11
import { useEffect, useState } from 'react';
2-
import { useLocation, useNavigate } from 'react-router';
32
import { twMerge } from 'tailwind-merge';
43

54
import {
65
getSharePostDetail,
7-
postShareProposalApproval,
86
SharePost,
97
postSharePostLike,
108
getSharePostLikeCount,
119
} from '@/apis/share';
12-
import BlurImg from '@/assets/images/landing-blur.png';
1310
import ReportModal from '@/components/ReportModal';
1411

1512
import Header from './components/Header';
1613
import Letter from './components/Letter';
14+
import { useParams } from 'react-router';
15+
import useAuthStore from '@/stores/authStore';
1716

18-
interface ShareLetterPreviewProps {
19-
confirmDisabled?: boolean;
20-
children?: React.ReactNode;
21-
}
22-
23-
const LetterBoardDetailPage = ({ confirmDisabled }: ShareLetterPreviewProps) => {
24-
const [likeCount, setLikeCount] = useState(122);
17+
const LetterBoardDetailPage = () => {
18+
const [likeCount, setLikeCount] = useState(0);
2519
const [isLike, setIsLike] = useState(false);
26-
const isWriter = false;
27-
const [activeReportModal, setActiveReportModal] = useState(false);
28-
const sharePostId: string = location.pathname.split('/')[3];
29-
// const location = useLocation();
30-
const navigate = useNavigate();
31-
// const isShareLetterPreview = location.state?.isShareLetterPreview || false;
32-
const isShareLetterPreview = false;
20+
const [isWriter, setIsWriter] = useState(false);
3321
const [postDetail, setPostDetail] = useState<SharePost>();
22+
const [activeReportModal, setActiveReportModal] = useState(false);
23+
24+
const { id } = useParams();
25+
26+
const myZipCode = useAuthStore.getState().zipCode;
3427

35-
const postLike = async () => {
28+
const postLike = async (sharePostId: string) => {
3629
try {
3730
const response = await postSharePostLike(sharePostId);
3831
if (!response) throw new Error('error while fetching like count');
@@ -43,24 +36,13 @@ const LetterBoardDetailPage = ({ confirmDisabled }: ShareLetterPreviewProps) =>
4336
}
4437
};
4538

46-
const handleToggleLike = () => {
39+
const handleToggleLike = (sharePostId: string) => {
40+
if (sharePostId === 'error') {
41+
return;
42+
}
4743
setLikeCount((prev) => prev + (isLike ? -1 : 1));
4844
setIsLike((prev) => !prev);
49-
postLike();
50-
};
51-
52-
const handleProposalApproval = async (
53-
action: 'approve' | 'reject',
54-
shareProposalId: number = location.state?.postDetail?.sharePostId,
55-
) => {
56-
try {
57-
const result = await postShareProposalApproval(shareProposalId, action);
58-
console.log(`✅ 편지 공유 ${action === 'approve' ? '수락' : '거절'}됨:`, result);
59-
60-
navigate('/');
61-
} catch (error) {
62-
console.error(error);
63-
}
45+
postLike(sharePostId);
6446
};
6547

6648
useEffect(() => {
@@ -80,27 +62,31 @@ const LetterBoardDetailPage = ({ confirmDisabled }: ShareLetterPreviewProps) =>
8062
console.log('✅ 편지 좋아요 갯수:', response);
8163
setLikeCount(response.likeCount);
8264
setIsLike(response.liked);
65+
console.log('myZip', myZipCode);
66+
console.log('responseZip', response.zipCode);
67+
console.log('responseZip', response);
68+
69+
if (myZipCode === response.zipCode || !response.zipCode) {
70+
setIsWriter(true);
71+
}
8372
} catch (error) {
8473
console.error('❌ 편지 좋아요 갯수를 가져오는 중 에러가 발생했습니다', error);
8574
throw new Error('편지 좋아요 갯수 가져오기 실패');
8675
}
8776
};
8877

89-
// if (location.state?.postDetail) {
90-
fetchPostDetail(sharePostId);
91-
fetchLikeCounts(sharePostId);
92-
// } else {
93-
// console.warn('postDetail not found in location.state');
94-
// }
95-
// }, [location.state]);
78+
if (id) {
79+
fetchPostDetail(id);
80+
fetchLikeCounts(id);
81+
}
9682
}, []);
9783

9884
return (
9985
<>
10086
{activeReportModal && (
10187
<ReportModal
102-
reportType="POST"
103-
letterId={parseInt(sharePostId)}
88+
reportType="SHARE_POST"
89+
letterId={id ? parseInt(id) : 0}
10490
onClose={() => setActiveReportModal(false)}
10591
/>
10692
)}
@@ -109,9 +95,8 @@ const LetterBoardDetailPage = ({ confirmDisabled }: ShareLetterPreviewProps) =>
10995
likeCount={likeCount}
11096
isLike={isLike}
11197
isWriter={isWriter}
112-
onToggleLike={handleToggleLike}
98+
onToggleLike={() => (id ? handleToggleLike(id) : handleToggleLike('error'))}
11399
onOpenReportModal={() => setActiveReportModal(true)}
114-
isShareLetterPreview={isShareLetterPreview}
115100
/>
116101
<main className="px-5 pt-18 pb-3">
117102
<p className="body-b mb-6 px-5">FROM. {postDetail?.zipCode}</p>
@@ -132,34 +117,6 @@ const LetterBoardDetailPage = ({ confirmDisabled }: ShareLetterPreviewProps) =>
132117
/>
133118
))}
134119
</section>
135-
136-
{isShareLetterPreview && (
137-
<>
138-
<img
139-
src={BlurImg}
140-
alt="landing blur"
141-
className="fixed bottom-0 left-0 z-10 w-screen"
142-
/>
143-
<section className="fixed bottom-[30px] left-1/2 z-20 flex w-73 translate-x-[-50%] gap-6">
144-
<button
145-
type="button"
146-
className="body-m secondary-btn h-10 flex-1 basis-1/2"
147-
onClick={() => handleProposalApproval('reject', postDetail?.sharePostId)}
148-
>
149-
거부하기
150-
</button>
151-
152-
<button
153-
type="button"
154-
className="primary-btn body-m h-10 flex-1 basis-1/2"
155-
disabled={confirmDisabled}
156-
onClick={() => handleProposalApproval('approve', postDetail?.sharePostId)}
157-
>
158-
승인하기
159-
</button>
160-
</section>
161-
</>
162-
)}
163120
</main>
164121
</div>
165122
</>

0 commit comments

Comments
 (0)