Skip to content

Commit

Permalink
Merge pull request #110 from Senity-Waved/feature/#102
Browse files Browse the repository at this point in the history
[#102][FEATURE] 특정 알림 삭제 기능 구현 및 실시간 알림 테스트
  • Loading branch information
eeeyooon authored Apr 11, 2024
2 parents 71718c3 + 83fe3fc commit 70bfd75
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/components/common/EmptyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ interface IEmptyView {
| '내후기'
| '예치금내역'
| '인증내역'
| '커밋인증';
| '커밋인증'
| '알림내역';
}

export default function EmptyView({ pageType }: IEmptyView) {
Expand Down
1 change: 0 additions & 1 deletion src/components/home/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export default function Notification({ updateKey }: { updateKey: boolean }) {
['hasNewEvent', updateKey],
async () => {
const response = await newNotificationApi();
console.log('새 알림 있나요?', response.data.newEvent);
return response.data;
},
{ refetchOnWindowFocus: false },
Expand Down
42 changes: 42 additions & 0 deletions src/components/notification/NotificationBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import styled from '@emotion/styled';
import Image from 'next/image';
import INotify from '@/types/notify';

interface INotificationBox {
notification: INotify;
openDeleteModal: (notificationId: number) => void;
}
function NotificationBox({ notification, openDeleteModal }: INotificationBox) {
return (
<SNotificationBox>
<button
type="button"
onClick={() => openDeleteModal(notification.notificationId)}
>
<SDeleteIcon
src="/icons/icon-trash.svg"
alt="삭제 아이콘"
width={16}
height={16}
priority
/>
</button>
<p>{notification.title}</p>
<p>{notification.message}</p>
<p>{notification.createDate}</p>
</SNotificationBox>
);
}

const SNotificationBox = styled.div`
border: 1px solid ${({ theme }) => theme.color.gray_3c};
border-radius: 10px;
margin: 0.625rem;
padding: 0.625rem 0.3125rem;
`;

const SDeleteIcon = styled(Image)`
cursor: pointer;
`;

export default NotificationBox;
71 changes: 71 additions & 0 deletions src/components/notification/NotificationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import styled from '@emotion/styled';
import Portal from '../modal/ModalPortal';

interface INotificationModal {
isOpen: boolean;
onClose: () => void;
onDelete: () => void;
}

export default function NotificationModal({
isOpen,
onClose,
onDelete,
}: INotificationModal) {
const handleBackgroundClick = (event: React.MouseEvent<HTMLElement>) => {
if (event.target === event.currentTarget) {
onClose();
}
};

return (
isOpen && (
<Portal>
<SModalWrapper onClick={handleBackgroundClick}>
<SModalContent>
<SModalBtn type="button" onClick={onDelete} deleteBtn>
삭제하기
</SModalBtn>
<SModalBtn type="button" onClick={onClose} deleteBtn={false}>
취소하기
</SModalBtn>
</SModalContent>
</SModalWrapper>
</Portal>
)
);
}

export const SModalWrapper = styled.div`
z-index: 20;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-end;
background-color: rgba(0, 0, 0, 0.6);
`;

const SModalContent = styled.div`
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
margin-bottom: 2.5rem;
`;

const SModalBtn = styled.button<{ deleteBtn: boolean }>`
width: 19.5rem;
height: 48px;
background-color: ${({ theme }) => theme.color.white};
margin-top: 1rem;
border-radius: 8px;
text-align: center;
font-size: ${({ theme }) => theme.fontSize.subtitle1};
font-weight: ${({ theme }) => theme.fontWeight.subtitle1};
color: ${({ theme, deleteBtn }) =>
deleteBtn ? theme.color.error : theme.color.normal};
`;
4 changes: 4 additions & 0 deletions src/constants/emptyText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const emptyText = {
mainText: '나만의 커밋 인증',
subText: '1일 1커밋 챌린지는 내 인증 내역만 볼 수 있습니다.',
},
알림내역: {
mainText: '알림 목록이 비어 있어요',
subText: '최근 2주 동안 받은 알림을 확인할 수 있어요.',
},
};

export default emptyText;
11 changes: 10 additions & 1 deletion src/lib/axios/notification/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,13 @@ const notifyApi = () => {
return axiosInstance.get<INotify[]>('/notify');
};

export { subscribeApi, newNotificationApi, notifyApi };
/**
* 알림 내역 삭제 DELETE
* @param notificationId
* @returns status, message
*/
const deleteNotificationApi = (notificationId: number) => {
return axiosInstance.delete(`/notify/${notificationId}`);
};

export { subscribeApi, newNotificationApi, notifyApi, deleteNotificationApi };
4 changes: 1 addition & 3 deletions src/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,9 @@ export default function Home({
withCredentials: true,
});

eventSource.addEventListener('event', (event) => {
eventSource.addEventListener('event', () => {
openSnackBar('새로운 알림이 있습니다.');
setNotificationUpdate(true);
console.log(event);
});
};

Expand Down Expand Up @@ -142,7 +141,6 @@ export default function Home({
// eslint-disable-next-line @typescript-eslint/no-misused-promises
timeoutId = setTimeout(refreshTokenAndReconnect, 60 * 1000 * 9);
} else if (readyReconnect) {
console.log('토큰 만료 시간 전 재발급 및 재연동 시도');
refreshTokenAndReconnect().catch(console.error);
}

Expand Down
50 changes: 41 additions & 9 deletions src/pages/notification/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import styled from '@emotion/styled';
import { useQuery } from '@tanstack/react-query';
import { v4 as uuidv4 } from 'uuid';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import Layout from '@/components/common/Layout';
import EmptyView from '@/components/common/EmptyView';
import INotify from '@/types/notify';
import { notifyApi } from '@/lib/axios/notification/api';
import { deleteNotificationApi, notifyApi } from '@/lib/axios/notification/api';
import NotificationBox from '@/components/notification/NotificationBox';
import NotificationModal from '@/components/notification/NotificationModal';

export default function Notification() {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [selectedNotificationId, setSelectedNotificationId] = useState<
number | null
>(null);
const queryClient = useQueryClient();
const { data, error } = useQuery<INotify[]>(
['notifyList'],
async () => {
Expand All @@ -15,9 +22,29 @@ export default function Notification() {
},
{ refetchOnWindowFocus: false },
);

const deleteMutation = useMutation(deleteNotificationApi, {
onSuccess: () => {
queryClient.invalidateQueries(['notifyList']).catch(console.error);
setIsModalOpen(false);
},
});

const openDeleteModal = (notificationId: number) => {
setSelectedNotificationId(notificationId);
setIsModalOpen(true);
};

const handleDelete = () => {
if (selectedNotificationId !== null) {
deleteMutation.mutate(selectedNotificationId);
}
};

if (error) {
console.error('새로운 알림 유무 불러오기 실패', error);
}

return (
<Layout
noFooter
Expand All @@ -30,17 +57,22 @@ export default function Notification() {
{data && data.length > 0 ? (
<div>
{data.map((notify) => (
<div key={uuidv4()}>
<p>{notify.title}</p>
<p>{notify.message}</p>
<p>{notify.createDate}</p>
</div>
<NotificationBox
key={notify.notificationId}
notification={notify}
openDeleteModal={() => openDeleteModal(notify.notificationId)}
/>
))}
</div>
) : (
<EmptyView pageType="예치금내역" />
<EmptyView pageType="알림내역" />
)}
</SNotificationWrapper>
<NotificationModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onDelete={handleDelete}
/>
</Layout>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/types/notify.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
interface INotify {
notificationId: number;
title: string;
message: string;
createDate: string;
Expand Down

0 comments on commit 70bfd75

Please sign in to comment.