Skip to content

Commit

Permalink
메일 읽음 api 연동 추가 (#30)
Browse files Browse the repository at this point in the history
* feat: mainListTap 하단 border set Width as screen

* feat: header height값 수정

* feat: Digest탭의 빈 페이지 구현

* feat: 메일 읽기 api 연동 추가

* feat: 메일 삭제 UI 및 API 연결

---------

Co-authored-by: moonki <[email protected]>
  • Loading branch information
dladncks1217 and moong23 authored Sep 8, 2024
1 parent c789f26 commit 8b1026b
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 21 deletions.
27 changes: 27 additions & 0 deletions src/api/hooks/useMailReadMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useMutation } from '@tanstack/react-query';
import { axiosInstance } from '@/api/axiosInstance';
import { AxiosError, AxiosResponse } from 'axios';

interface patchParam {
mailId: string;
}

export const patchFn = ({ mailId }: patchParam) => {
return axiosInstance.patch(`/inbox/mails/${mailId}`, { action: 'read' });
};

export const deleteFn = ({ mailId }: patchParam) => {
return axiosInstance.delete(`/inbox/mails/${mailId}`);
};

export const useMailReadMutation = () => {
return useMutation<AxiosResponse, AxiosError, patchParam>({
mutationFn: patchFn,
});
};

export const useMailDeleteMutation = () => {
return useMutation<AxiosResponse, AxiosError, patchParam>({
mutationFn: deleteFn,
});
};
33 changes: 33 additions & 0 deletions src/app/article/[id]/ArticleFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useMailDeleteMutation } from '@/api/hooks/useMailReadMutation';
import DeleteIcon from '@/assets/icons/DeleteIcon.svg';
import ListIcon from '@/assets/icons/ListIcon.svg';
import Image from 'next/image';

interface ArticleFooterProps {
mailId: string;
}

const ArticleFooter = ({ mailId }: ArticleFooterProps) => {
const deleteMutation = useMailDeleteMutation();

const handleDeleteMail = (mailId: string) => {
deleteMutation.mutate({ mailId });
};
return (
<div className='fixed bottom-0 flex flex-row items-center justify-center w-full h-12 bg-white border-t border-lightgrey'>
<div className='flex flex-row justify-end gap-6 px-6 w-content'>
<span
className='flex items-center justify-center w-6 h-6 cursor-pointer'
onClick={() => handleDeleteMail(mailId)}
>
<Image src={DeleteIcon} alt='delete' width={16} height={24} />
</span>
<span className='flex items-center justify-center w-6 h-6 cursor-pointer'>
<Image src={ListIcon} alt='list' width={24} height={24} />
</span>
</div>
</div>
);
};

export default ArticleFooter;
13 changes: 9 additions & 4 deletions src/app/article/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ import type { pageProps } from '@/types/page';
import ArticleContent from '@/app/article/[id]/ArticleContent';
import MainPageHeader from '@/components/Header/MainPageHeader';
import { useMailByIdQuery } from '@/api/hooks/useFetchMailQuery';
import ArticleFooter from './ArticleFooter';

interface ArticlePageProps extends pageProps {
interface ArticlePageProps {
params: { id: string };
}

const ArticlePage = ({ searchParams, params }: ArticlePageProps) => {
const ArticlePage = ({ params }: ArticlePageProps) => {
const { data } = useMailByIdQuery(params.id);

return (
<main className='flex flex-col items-center w-full bg-white'>
<MainPageHeader />
{/* TODO: 개별 mail 받아와서 데이터 넘겨줘야함~~ */}
{data && <ArticleContent mailData={data} />}
{data && (
<>
<ArticleContent mailData={data} />
<ArticleFooter mailId={data.mailId} />
</>
)}
</main>
);
};
Expand Down
21 changes: 19 additions & 2 deletions src/app/main/DigestTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,34 @@ import { useEffect, useState } from 'react';
import ArticleCard from '@/components/Article/ArticleCard';
import RecommendArea from '../TodayTab/RecommendArea';
import { useUnreadQuery } from '@/api/hooks/useFetchMailQuery';
import EmptyMailView from '@/components/EmptyMailView';
import { useMailReadMutation } from '@/api/hooks/useMailReadMutation';

const DigestTab = () => {
const [selectedTab, setSelectedTab] = useState<'all' | 'unread'>('unread');

const { data, isFetched } = useUnreadQuery({});
const readMutation = useMailReadMutation();

const handleReadMail = (mailId: string) => {
readMutation.mutate({ mailId });
};

return isFetched ? (
<div className='flex flex-row w-full h-full gap-16'>
<div className='flex flex-col gap-3 pt-3'>
<div className='flex flex-col h-full gap-3 pt-3'>
<TopSection selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
{data?.map(article => <ArticleCard key={article.mailId} {...article} />)}
{data?.length === 0 ? (
<div className='h-[calc(100vh-8.5rem-94px)] overflow-visible w-articleCard'>
<EmptyMailView />
</div>
) : (
data?.map(article => (
<div onClick={() => handleReadMail(article.mailId)}>
<ArticleCard key={article.mailId} {...article} />
</div>
))
)}
</div>
<div className='sticky top-0 pt-9 h-fit'>
<RecommendArea />
Expand Down
2 changes: 1 addition & 1 deletion src/app/main/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function MainPageLayout({
children: React.ReactNode;
}>) {
return (
<main className='flex flex-col bg-white'>
<main className='flex flex-col items-center gap-4 bg-white'>
<MainPageHeader />
<div className='flex flex-col items-center w-full'>
<Suspense fallback={<div></div>}>
Expand Down
9 changes: 9 additions & 0 deletions src/assets/icons/DeleteIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/ListIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 1 addition & 11 deletions src/components/Article/ArticleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@ interface ArticleCardProps extends MailDataType {
currentTab?: string;
}

const ArticleCard = ({
subject,
mailId,
snippet,
date,
// thumbnail,
isRead,
payload,
from,
isToday = false,
}: ArticleCardProps) => {
const ArticleCard = ({ subject, mailId, snippet, date, isRead, payload, from, isToday = false }: ArticleCardProps) => {
return (
<Link
// https://stackoverflow.com/questions/66821351/nextjs-error-message-failed-prop-type-the-prop-href-expects-a-string-or-o
Expand Down
30 changes: 30 additions & 0 deletions src/components/EmptyMailView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Image from 'next/image';
import Link from 'next/link';
import EmptyView from '@/assets/images/EmptyView.png';

const EmptyMailView = () => {
return (
<div className='flex flex-col items-center justify-start w-full h-full bg-background_grey rounded-xl pt-25'>
<div className='flex flex-col items-center gap-3'>
<Image src={EmptyView} alt='EmptyView' width={120} height={106} />
<div className='flex flex-col items-center gap-1'>
<span className='text-h2 text-darkgrey'>뉴스레터를 모두 읽었어요</span>
<span className='flex flex-row gap-1 text-btn1'>
<span className='text-darkgrey'>더 많은 뉴스레터를 읽고 싶다면</span>
<Link
className='underline text-blue underline-offset-2'
href={{
pathname: '/main',
query: { tab: 'search' },
}}
>
탐색 탭으로 이동
</Link>
</span>
</div>
</div>
</div>
);
};

export default EmptyMailView;
4 changes: 2 additions & 2 deletions src/components/Header/MainPageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import Image from 'next/image';

const MainPageHeader = () => {
return (
<div className={`py-8 justify-between flex items-center w-content bg-white`}>
<div className={`justify-between flex h-16 items-center w-content bg-white`}>
<Link href='/main'>
<Image src={ServiceIcon} alt='ServiceIcon' width={153} height={64} />
</Link>

<Link href='/mypage' className='flex flex-row items-center cursor-pointer gap-1 text-blue'>
<Link href='/mypage' className='flex flex-row items-center gap-1 cursor-pointer text-blue'>
<HomeIcon width={24} fill='#168FD0' />
<span className='text-body3'>마이 페이지</span>
</Link>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ListTap/MainListTap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const MainListTap = () => {
}, [searchParams]);

return (
<div className='flex justify-center w-full h-12 border-b border-lightgrey'>
<div className='flex justify-center w-screen h-12 border-b border-lightgrey'>
<div className='flex flex-row h-full gap-4 w-content'>
<ListItem
onClick={() => handleClickListItem('오늘의 인사이트')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface DomainInteractionAreaProps {

const DomainInteractionArea = ({ domainArticleData }: DomainInteractionAreaProps) => {
const [currentTab, setCurrentTab] = useState('unread');

return (
<div className='flex flex-col gap-3'>
<div className='flex flex-row items-center justify-between w-full'>
Expand Down
8 changes: 8 additions & 0 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ export const handlers = [
});
}),

http.patch('/inbox/mails/:id', () => {
return HttpResponse.json({}, { status: 204 });
}),

http.delete('/inbox/mails/:id', () => {
return HttpResponse.json({ status: 204 });
}),

http.get('/users', () => {
return HttpResponse.json({
user_id: 'RandomString',
Expand Down

0 comments on commit 8b1026b

Please sign in to comment.