Skip to content

Commit

Permalink
Merge pull request #221 from Strong-Potato/165-feat-connect-alarm-api
Browse files Browse the repository at this point in the history
#165 feat connect alarm api
  • Loading branch information
HOOOO98 authored Jan 27, 2024
2 parents 4b06530 + 16f3d57 commit 18f7682
Show file tree
Hide file tree
Showing 18 changed files with 382 additions and 143 deletions.
98 changes: 87 additions & 11 deletions public/firebase-messaging-sw.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,83 @@
function parseNestedJson(jsonString) {
try {
let formattedString = jsonString.trim().replace(/\n/g, '').replace(/ {2}/g, '');
let outerJson = JSON.parse(formattedString);
let innerJsonString = outerJson.body;
let correctedInnerJsonString = innerJsonString.replace(/\\"/g, '"');
let innerJson = JSON.parse(correctedInnerJsonString);
return innerJson;
} catch (e) {
return `Error parsing JSON: ${e.message}`;
}
}

function createNotificationBody(data) {
if (!data || !data.spaceEventInfo || !data.memberEventInfo) {
return '필요한 데이터가 누락되었습니다.';
}

const spaceTitle = data.spaceEventInfo.spaceTitle ? data.spaceEventInfo.spaceTitle : '여행지 미정';
const memberNickname = data.memberEventInfo.memberNickname;
let notificationBody = '';

switch (data.eventType) {
case 'VOTE_CREATED':
if (!data.voteEventInfo) {
return `[${spaceTitle}] ${memberNickname} 님이 새로운 투표를 생성했습니다.`;
}
// eslint-disable-next-line no-case-declarations
const voteTitle = data.voteEventInfo.voteTitle;
notificationBody = `[${spaceTitle}] ${memberNickname} 님이 새로운 투표 “${voteTitle}”를 생성했습니다.`;
break;
case 'VOTE_DONE':
if (!data.voteEventInfo) {
return `[${spaceTitle}] 투표가 최종 확정되었습니다.`;
}
// eslint-disable-next-line no-case-declarations
const voteTitleDone = data.voteEventInfo.voteTitle;
notificationBody = `[${spaceTitle}] “${voteTitleDone}” 투표가 최종 확정되었습니다.`;
break;
case 'VOTE_DELETED':
if (!data.voteEventInfo) {
return `[${spaceTitle}] ${memberNickname} 님이 투표를 삭제했습니다.`;
}
// eslint-disable-next-line no-case-declarations
const voteTitleDeleted = data.voteEventInfo.voteTitle;
notificationBody = `[${spaceTitle}] ${memberNickname} 님이 “${voteTitleDeleted}”의 투표를 삭제했습니다.`;
break;
case 'MEMBER_INVITED':
notificationBody = `[${spaceTitle}] 에 ${memberNickname} 님이 초대되었습니다.`;
break;
case 'MEMBER_EXIT':
notificationBody = `[${spaceTitle}] ${memberNickname} 님이 여행 스페이스를 나갔습니다.`;
break;
case 'NEW_JOURNEY_ADDED':
// eslint-disable-next-line no-case-declarations
const voteTitleCandidateAdd = data.voteEventInfo.voteTitle;
notificationBody = `[${spaceTitle}] ${voteTitleCandidateAdd} 의 후보가 일정에 추가 되었습니다.`;
break;
case 'CANDIDATE_ADDED':
// eslint-disable-next-line no-case-declarations
const voteTitleAdd = data.voteEventInfo.voteTitle;
notificationBody = `[${spaceTitle}] ${memberNickname} 님이 "${voteTitleAdd}"에 새로운 후보를 등록했습니다.`;
break;
case 'SPACE_LOCATION_CHANGED':
notificationBody = `여행지가 [${data.spaceEventInfo.oldTitle || '여행지 미정'}]에서 [${
data.spaceEventInfo.spaceTitle
}]으로 변경되었습니다.`;
break;
case 'SPACE_SCHEDULE_CHANGED':
notificationBody = `여행날짜가 [${data.spaceEventInfo.oldDates || '날짜 미정'}]에서 [${
data.spaceEventInfo.changeDate
}]으로 변경되었습니다.`;
break;
default:
notificationBody = '알 수 없는 이벤트입니다.';
}

return notificationBody;
}

self.addEventListener('install', function () {
console.log('[FCM SW] 설치중..');
self.skipWaiting();
Expand All @@ -9,20 +89,16 @@ self.addEventListener('activate', function () {

self.addEventListener('push', function (e) {
if (!e.data.json()) return;

const resultData = e.data.json().notification;
// 필수! 알람 제목
const notificationTitle = resultData.title;
const resultDataString = typeof resultData === 'string' ? resultData : JSON.stringify(resultData);
const parsedResultData = parseNestedJson(resultDataString);
console.log(parsedResultData);

const notificationTitle = 'TRIPVOTE';
const notificationOptions = {
//필수! 알람 설명
body: resultData.body,
//필수! 알람 이미지(프로필, 로고)
icon: resultData.image,
//필수! 알람 분류태그 (전체, 투표, 나가기...)
tag: resultData.tag,
...resultData,
body: createNotificationBody(parsedResultData),
...parsedResultData,
};
console.log('출력');

self.registration.showNotification(notificationTitle, notificationOptions);
});
24 changes: 24 additions & 0 deletions src/api/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,27 @@ export const GetNotification = async () => {
console.log('[notification]알림내용을 가져오지 못했습니다');
}
};

export const GetAlarm = async () => {
try {
const response = await axios.get('/api/notifications', {withCredentials: true});
return response;
} catch (error) {
if (axios.isAxiosError(error)) {
console.log(error);
return error.response;
}
}
};

export const PostReadAlarm = async (notiId: number) => {
try {
const response = await axios.patch(`/api/notifications/${notiId}/read`, {withCredentials: true});
return response;
} catch (error) {
if (axios.isAxiosError(error)) {
console.log(error);
return error.response;
}
}
};
4 changes: 2 additions & 2 deletions src/components/Alarm/Alarm.module.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
@use "@/sass" as *;
@use '@/sass' as *;

.page {
position: absolute;
top: 0;
width: 100%;
height: 100vh;
z-index: 9;
z-index: 11;

.slide {
position: absolute;
Expand Down
3 changes: 1 addition & 2 deletions src/components/Alarm/Alarm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ function Alarm({isAlarmOpen, alarmClose}: AlarmProps) {
useEffect(() => {
if (isAlarmOpen === true) {
localStorage.removeItem('news');
console.log('비움');
}
}, [isAlarmOpen]);

Expand All @@ -69,7 +68,7 @@ function Alarm({isAlarmOpen, alarmClose}: AlarmProps) {
}}
>
<Back alarmClose={alarmClose} />
<TabCapsule />
<TabCapsule isAlarmOpen={isAlarmOpen} />
</Slide>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@use "@/sass" as *;
@use '@/sass' as *;

.page {
height: calc(100vh - 86px);
Expand Down
19 changes: 11 additions & 8 deletions src/components/Alarm/TabCapsule/Content/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import styles from "./Content.module.scss";
import styles from './Content.module.scss';

import formatTimeAgo from "@/utils/formatTimeAgo";
import DefaultProfile from '@/assets/profile_default.svg?react';
import formatTimeAgo from '@/utils/formatTimeAgo';

import { ContentProps } from "@/types/alarm";
import {ContentProps} from '@/types/alarm';

function Content({ contents }: ContentProps) {
function Content({contents}: ContentProps) {
return (
<div className={styles.page}>
{contents.map((content, index) => (
<div key={index} className={styles.container}>
<img src={content.url} className={styles.container__thumbnail} />
{content.url ? (
<img src={content.url} className={styles.container__thumbnail} />
) : (
<DefaultProfile className={styles.container__thumbnail} />
)}
<div className={styles.container__wrapper}>
<p className={styles.container__wrapper__title}>{content.title}</p>
<p className={styles.container__wrapper__time}>
{formatTimeAgo(new Date(content.time))}
</p>
<p className={styles.container__wrapper__time}>{formatTimeAgo(new Date(content.time))}</p>
</div>
</div>
))}
Expand Down
64 changes: 19 additions & 45 deletions src/components/Alarm/TabCapsule/TabCapsule.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,30 @@
import {Tab, TabIndicator, TabList, TabPanel, TabPanels, Tabs} from '@chakra-ui/react';
import {useNavigate} from 'react-router-dom';

import styles from './TabCapsule.module.scss';

import {useGetAlarm} from '@/hooks/Notification/useNotification';

import {PostReadAlarm} from '@/api/notification';
import {parsingAlarmTravel} from '@/utils/parsingAlarm';

import Content from './Content/Content';

const AllContents = [
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "밥집 어디갈꺼야" 투표를 만들었어요.`,
time: '2024-01-11T23:09:00',
},
{
url: 'https://github.com/Strong-Potato/TripVote-FE/assets/120024673/089a8673-405e-4a06-b173-4cf3e985b466',
title: '개인정보 보호정책이 변경되었습니다.',
time: '2024-01-11T20:00:00',
},
{
url: 'https://github.com/Strong-Potato/TripVote-FE/assets/120024673/089a8673-405e-4a06-b173-4cf3e985b466',
title: '개인정보 보호정책이 변경되었습니다.',
time: '2024-01-10T10:00:00',
},
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "카페 어디갈꺼야" 투표를 만들었어요.`,
time: '2024-01-03T12:00:00',
},
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "숙소 어디갈꺼야" 투표를 만들었어요.`,
time: '2023-12-31T12:00:00',
},
];
function TabCapsule({isAlarmOpen}: {isAlarmOpen: boolean}) {
const navigate = useNavigate();
const {data: Alarm} = useGetAlarm(isAlarmOpen);
localStorage.removeItem('news');

Alarm && PostReadAlarm(Alarm?.data.data.notificationDetail[0].id);
if (Alarm?.status === 403 || Alarm?.status === 401) {
navigate('/auth/login', {
replace: true,
});
}

const SpaceTravelContents = [
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "밥집 어디갈꺼야" 투표를 만들었어요.`,
time: '2024-01-11T23:05:00',
},
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "카페 어디갈꺼야" 투표를 만들었어요.`,
time: '2024-01-03T12:00:00',
},
{
url: 'https://m.eejmall.com/web/product/big/201708/211_shop1_627935.jpg',
title: `[강릉 여행]강자밭님이 "숙소 어디갈꺼야" 투표를 만들었어요.`,
time: '2023-12-31T12:00:00',
},
];
const AllContents = parsingAlarmTravel(Alarm?.data.data.notificationDetail);
const SpaceTravelContents = parsingAlarmTravel(Alarm?.data.data.notificationDetail);

function TabCapsule() {
return (
<Tabs isFitted variant='unstyled'>
<TabList>
Expand Down
14 changes: 11 additions & 3 deletions src/components/Home/TabBar/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@ import {Link} from 'react-router-dom';

import styles from './TabBar.module.scss';

function TabBar() {
import {useGetAlarm} from '@/hooks/Notification/useNotification';

import {Alarmprop} from '@/types/alarm';

function TabBar({onAlarmOpen}: Alarmprop) {
const news = localStorage.getItem('news');
const {data: Alarm} = useGetAlarm(true);
if (Alarm?.data.data.notificationDetail[0].isRead === false) {
localStorage.setItem('news', 'true');
}

return (
<div className={styles.container}>
<div className={styles.icons}>
<Link to='/search'>
<IoSearchSharp />
</Link>
<Link to='/alarm' className={styles.icons__wrapper}>
<button onClick={onAlarmOpen} className={styles.icons__wrapper}>
<AiOutlineBell />
{news && <div className={styles.icons__wrapper__eclips} />}
</Link>
</button>
</div>
</div>
);
Expand Down
12 changes: 6 additions & 6 deletions src/components/Modal/Invitation/Invitation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {InvitationProps} from '@/types/Invitation';

function Invitation({inviteCode, modal}: InvitationProps) {
const [isFull, setIsFull] = useRecoilState(isFullMember);
const [, , removeCookie] = useCookies(['join_space_token']);
const [, setcookie] = useCookies(['join_space_token']);
const {data} = useGetMyInfo(true);
const navigate = useNavigate();
const parsedInviteCode = parseInviteCode(inviteCode);
Expand All @@ -33,10 +33,10 @@ function Invitation({inviteCode, modal}: InvitationProps) {
const handleJoin = async () => {
const response = await postJoin(parsedInviteCode!.space_id);
if (response.status === 200) {
removeCookie('join_space_token', {path: '/'});
setcookie('join_space_token', '');
navigate(`/trip/${parsedInviteCode!.space_id}`);
} else if (response.status === 400) {
removeCookie('join_space_token', {path: '/'});
setcookie('join_space_token', '');
modal(false);
setIsFull(true);
}
Expand All @@ -62,7 +62,7 @@ function Invitation({inviteCode, modal}: InvitationProps) {
className={styles.wrapperInvalidButton__confirm}
onClick={() => {
modal(false);
removeCookie('join_space_token', {path: '/'});
setcookie('join_space_token', '');
}}
>
확인
Expand All @@ -87,7 +87,7 @@ function Invitation({inviteCode, modal}: InvitationProps) {
className={styles.wrapperButton__cancel}
onClick={() => {
modal(false);
removeCookie('join_space_token', {path: '/'});
setcookie('join_space_token', '');
}}
>
취소
Expand All @@ -114,7 +114,7 @@ function Invitation({inviteCode, modal}: InvitationProps) {
className={styles.wrapperButton__cancel}
onClick={() => {
modal(false);
removeCookie('join_space_token', {path: '/'});
setcookie('join_space_token', '');
}}
>
취소
Expand Down
2 changes: 1 addition & 1 deletion src/components/SideBar/TravelList/TravelList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function TravelList({isSideOpen}: TravelListProp) {
{spaces.data.spaces.map((item, index) => (
<li key={index}>
<button className={styles.travelSpaceList__items__item} onClick={() => navigate(`/trip/${item.id}`)}>
<p className={styles.travelSpaceList__items__item__name}>{item.city}</p>
<p className={styles.travelSpaceList__items__item__name}>{item.city ? item.city : `여행지 미정`}</p>
<p className={styles.travelSpaceList__items__item__date}>
{item.startDate && item.endDate ? setSpaceDate(item.startDate, item.endDate) : '날짜 미정'}
</p>
Expand Down
Loading

0 comments on commit 18f7682

Please sign in to comment.