Skip to content

Commit 2bea6b0

Browse files
authored
feat: 내 편지함 기능 구현 1차 (#30)
* feat: 내 편지함, 상세 기능 구현 1차 - 내 편지함 기능구현 - 렌더링 - 3의 배수가 아닌 경우 이미지 추가 - 아무것도 없을 때 노트 추가 - 내 편지함 상세 기능 구현 - 공유 작성 및 전송 - 편지 리스트 렌더링 - 상대방 차단하기 - TODO - [ ] tanstackQuery 적용 - [ ] 무한 스크롤? 적용할지? - [ ] 상태관리 확인하기 * refactor: API 컨벤션 통일 - API 파일이름 수정 - api.ts 삭제 * refactor: merge 후 오류 해결 --------- Co-authored-by: nirii00 <[email protected]>
1 parent 73835b9 commit 2bea6b0

File tree

18 files changed

+307
-138
lines changed

18 files changed

+307
-138
lines changed

src/apis/client.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
import axios from 'axios';
22

3-
export const client = axios.create({
3+
const client = axios.create({
44
baseURL: import.meta.env.VITE_API_URL,
55
});
6+
7+
// client.interceptors.request.use(
8+
// (config) => {
9+
// const token = localStorage.getItem('authToken');
10+
// if (token) {
11+
// config.headers['Authorization'] = `Bearer ${token}`;
12+
// }
13+
// return config;
14+
// },
15+
// (error) => {
16+
// //TODO: 에러처리
17+
// return Promise.reject(error);
18+
// },
19+
// );
20+
21+
export default client;

src/apis/letterDetail.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { client } from './client';
1+
import client from './client';
22

33
const getLetter = async (
44
letterId: string,

src/apis/mailBox.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import client from './client';
2+
3+
export const getMailbox = async () => {
4+
try {
5+
const response = await client.get('/api/mailbox');
6+
if (!response) throw new Error('error while fetching mailbox data');
7+
return response.data;
8+
} catch (error) {
9+
console.error(error);
10+
}
11+
};
12+
13+
export const getMailboxDetail = async (id: number) => {
14+
try {
15+
const response = await client.get(`/api/mailbox/${id}`);
16+
if (!response) throw new Error('error while fetching mailbox detail data');
17+
return response.data;
18+
} catch (error) {
19+
console.error(error);
20+
}
21+
};
22+
23+
export const postMailboxDisconnect = async (id: number) => {
24+
try {
25+
const response = await client.post(`/api/mailbox/${id}/disconnect`);
26+
if (!response) throw new Error('error while disconnecting mailbox');
27+
return response;
28+
} catch (error) {
29+
console.error(error);
30+
}
31+
};

src/apis/share.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import client from './client';
2+
3+
export const postShareProposals = async (
4+
letterIds: number[],
5+
requesterId: number,
6+
recipientId: number,
7+
message: string,
8+
) => {
9+
try {
10+
const response = await client.post('/api/share-proposals', {
11+
letterIds: letterIds,
12+
requesterId: requesterId,
13+
recipientId: recipientId,
14+
message: message,
15+
});
16+
if (!response) throw new Error('error while fetching mailbox data');
17+
return response;
18+
} catch (error) {
19+
console.error(error);
20+
}
21+
};

src/apis/write.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { client } from './client';
1+
import client from './client';
22

33
const postLetter = async (
44
data: LetterRequest,
12.3 KB
Loading

src/pages/Admin/Report.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useState } from 'react';
22

3-
import { client } from '@/apis/client';
3+
import client from '@/apis/client';
44
import { AlarmIcon } from '@/assets/icons';
55

66
import DetailFrame from './components/DetailFrame';

src/pages/LetterBoardDetail/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { useState } from 'react';
22
import { useLocation } from 'react-router';
3-
43
import { twMerge } from 'tailwind-merge';
54

5+
import BlurImg from '@/assets/images/landing-blur.png';
66
import ReportModal from '@/components/ReportModal';
77

88
import Header from './components/Header';
99
import Letter from './components/Letter';
1010

11-
import BlurImg from '@/assets/images/landing-blur.png';
1211
const DUMMY_LETTER = {
1312
receiver: '12E21',
1413
content:

src/pages/LetterBox/components/LetterBoxItem.tsx

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,66 @@
1-
import { Link } from 'react-router';
1+
import { useNavigate } from 'react-router';
22
import { twMerge } from 'tailwind-merge';
3-
43
interface LetterBoxItemProps {
4+
boxId: number;
55
zipCode: string;
66
letterCount: number;
77
isChecked?: boolean;
88
isClosed?: boolean;
99
}
1010

1111
const LetterBoxItem = ({
12+
boxId,
1213
zipCode,
1314
letterCount,
1415
isChecked = false,
1516
isClosed = false,
1617
}: LetterBoxItemProps) => {
18+
const navigate = useNavigate();
19+
const handleClickItem = (id: number) => {
20+
navigate(`${id}`, {
21+
state: {
22+
id,
23+
zipCode,
24+
isClosed,
25+
},
26+
});
27+
};
1728
return (
18-
<Link to="id">
19-
<article className="flex h-fit w-fit flex-col items-center">
20-
<div className="text-gray-70 flex h-25 w-20 flex-col gap-1.5 bg-linear-to-b from-[#D5B695] to-[#B3895D] p-1.5">
21-
<p
29+
<article
30+
className="flex h-fit w-fit flex-col items-center"
31+
onClick={() => handleClickItem(boxId)}
32+
>
33+
<div className="text-gray-70 flex h-25 w-20 flex-col gap-1.5 bg-linear-to-b from-[#D5B695] to-[#B3895D] p-1.5">
34+
<p
35+
className={twMerge(
36+
'body-m from-white px-1',
37+
isClosed
38+
? 'bg-[repeating-linear-gradient(#D9D9D9,#D9D9D9_17px,#C2C2C2_17px,#C2C2C2_23px)]'
39+
: 'bg-linear-to-b',
40+
isChecked ? 'to-[#FFF5ED]' : 'to-[#FFF4F2]',
41+
)}
42+
>
43+
{zipCode}
44+
</p>
45+
{isClosed ? (
46+
<div className="flex grow flex-col bg-[repeating-linear-gradient(#D9D9D9,#D9D9D9_15px,#C2C2C2_15px,#C2C2C2_20px)]" />
47+
) : (
48+
<div
2249
className={twMerge(
23-
'body-m from-white px-1',
24-
isClosed
25-
? 'bg-[repeating-linear-gradient(#D9D9D9,#D9D9D9_17px,#C2C2C2_17px,#C2C2C2_23px)]'
26-
: 'bg-linear-to-b',
27-
isChecked ? 'to-[#FFF5ED]' : 'to-[#FFF4F2]',
50+
'flex grow flex-col bg-linear-to-b',
51+
isChecked ? 'from-[#FFF7E3] to-[#FFE197]' : 'from-[#FFF4F2] to-[#FFE6E3]',
2852
)}
2953
>
30-
{zipCode}
31-
</p>
32-
{isClosed ? (
33-
<div className="flex grow flex-col bg-[repeating-linear-gradient(#D9D9D9,#D9D9D9_15px,#C2C2C2_15px,#C2C2C2_20px)]" />
34-
) : (
35-
<div
36-
className={twMerge(
37-
'flex grow flex-col bg-linear-to-b',
38-
isChecked ? 'from-[#FFF7E3] to-[#FFE197]' : 'from-[#FFF4F2] to-[#FFE6E3]',
39-
)}
40-
>
41-
<p className="body-r mt-auto mr-[1px] text-right">{letterCount}</p>
42-
</div>
43-
)}
44-
</div>
45-
<div className="flex flex-col items-center">
46-
<div className="h-[7px] w-23 bg-[#D7A877]" />
47-
<div className="h-[3px] w-20 bg-[#A88156]" />
48-
<div className="h-1 w-18 bg-[#917B63]" />
49-
</div>
50-
</article>
51-
</Link>
54+
<p className="body-r mt-auto mr-[1px] text-right">{letterCount}</p>
55+
</div>
56+
)}
57+
</div>
58+
<div className="flex flex-col items-center">
59+
<div className="h-[7px] w-23 bg-[#D7A877]" />
60+
<div className="h-[3px] w-20 bg-[#A88156]" />
61+
<div className="h-1 w-18 bg-[#917B63]" />
62+
</div>
63+
</article>
5264
);
5365
};
5466

src/pages/LetterBox/index.tsx

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,81 @@
1+
import { useEffect, useState } from 'react';
2+
3+
import { getMailbox } from '@/apis/mailBox';
14
import DoorImg from '@/assets/images/door.png';
5+
import ClosedWindowImg from '@/assets/images/window-disabled.png';
26
import PageTitle from '@/components/PageTitle';
37
import { chunkBox } from '@/utils/chunkBox';
48

59
import LetterBoxItem from './components/LetterBoxItem';
610

7-
const DUMMY_COUNT = 200;
8-
11+
interface LetterBoxData {
12+
letterMatchingId: number;
13+
oppositeZipCode: string;
14+
active: boolean;
15+
oppositeRead: boolean;
16+
// totalLetters: number;
17+
}
918
const LetterBoxPage = () => {
19+
const [letterBox, setLetterBox] = useState<LetterBoxData[]>([]);
20+
21+
const fetchMailLists = async () => {
22+
try {
23+
const response = await getMailbox();
24+
if (!response) throw new Error();
25+
const data: LetterBoxData[] = response.data;
26+
// 정렬?
27+
setLetterBox(data);
28+
} catch (error) {
29+
console.error(error);
30+
}
31+
};
32+
useEffect(() => {
33+
fetchMailLists();
34+
}, []);
35+
1036
return (
1137
<main className="flex grow flex-col items-center px-5 pt-20">
1238
<PageTitle>내 편지함</PageTitle>
1339
<div className="w-full max-w-94">
1440
<p className="body-sb mt-16 mb-[7px] place-self-start text-gray-50">
15-
나와 연락한 사람들 {DUMMY_COUNT}
41+
나와 연락한 사람들 {letterBox?.length}
1642
</p>
1743
<section className="letter-box-bg flex grow flex-col items-center px-4 pt-5">
1844
<div className="flex w-full flex-col gap-5">
19-
{chunkBox(
20-
Array.from({ length: 12 }).map((_, index) => (
21-
<LetterBoxItem
22-
key={index}
23-
zipCode="12E12"
24-
letterCount={90}
25-
isChecked={index % 2 === 0}
26-
/>
27-
)),
28-
).map((row, index) => (
29-
<div key={index} className="flex justify-between">
30-
{row}
31-
</div>
32-
))}
45+
{letterBox.length > 0 ? (
46+
chunkBox(
47+
letterBox.map((data: LetterBoxData, index) => (
48+
<LetterBoxItem
49+
boxId={data.letterMatchingId}
50+
key={index}
51+
zipCode={data.oppositeZipCode}
52+
letterCount={90}
53+
isChecked={data.oppositeRead}
54+
isClosed={data.active}
55+
/>
56+
)),
57+
).map((row, index) =>
58+
row.length === 3 ? (
59+
<div key={index} className="flex justify-between">
60+
{row}
61+
</div>
62+
) : (
63+
<div key={index} className="flex justify-between">
64+
{row}
65+
<img src={ClosedWindowImg} alt="닫힌 문 이미지" className="h-28 w-23" />
66+
{row.length === 1 && (
67+
<img src={ClosedWindowImg} alt="닫힌 문 이미지" className="h-28 w-23" />
68+
)}
69+
</div>
70+
),
71+
)
72+
) : (
73+
<p className="body-m text-gray-60 text-center">아직 주고 받은 편지가 없어요</p>
74+
)}
3375
<div className="flex justify-between">
34-
<LetterBoxItem zipCode="12E12" letterCount={90} isClosed />
76+
<img src={ClosedWindowImg} alt="닫힌 문 이미지" className="h-28 w-23" />
3577
<img src={DoorImg} alt="출입문 이미지" />
36-
<LetterBoxItem zipCode="12E12" letterCount={90} isClosed />
78+
<img src={ClosedWindowImg} alt="닫힌 문 이미지" className="h-28 w-23" />
3779
</div>
3880
</div>
3981
</section>

0 commit comments

Comments
 (0)