-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
410 additions
and
27 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
components/NotificationModal/NotificationModal.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// NotificationModal.module.scss | ||
|
||
.wrapper { | ||
position: absolute; | ||
top: 35px; | ||
right: 0px; | ||
|
||
display: flex; | ||
padding: 14px 20px; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
width: 368px; | ||
gap: 16px; | ||
|
||
border-radius: 10px; | ||
border: 1px solid var(--gray30); | ||
background-color: #f9f9fb; | ||
box-shadow: 0px 2px 8px 0px rgba(60, 59, 62, 0.26); | ||
|
||
z-index: 10; | ||
|
||
@media only screen and (max-width: 768px) { | ||
top: 0px; | ||
position: fixed; | ||
box-shadow: none; | ||
width: 100%; | ||
height: 100vh; | ||
border: none; | ||
border-radius: 0; | ||
} | ||
} | ||
|
||
.title { | ||
color: var(--black); | ||
font-family: "Spoqa Han Sans Neo"; | ||
font-size: 18px; | ||
font-style: normal; | ||
font-weight: 700; | ||
line-height: normal; | ||
} | ||
|
||
.alert-div { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
width: 100%; | ||
height: 300px; | ||
font-family: "Spoqa Han Sans Neo"; | ||
font-size: 14px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 22px; | ||
|
||
@media only screen and (max-width: 768px) { | ||
height: 100%; | ||
} | ||
} | ||
|
||
.styled-close-icon { | ||
display: block; | ||
|
||
@media (max-width: 375px) { | ||
cursor: pointer; | ||
display: block; | ||
} | ||
} | ||
|
||
.container { | ||
width: 100%; | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
} |
44 changes: 44 additions & 0 deletions
44
components/NotificationModal/components/Notification.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
.wrapper { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
gap: 6px; | ||
width: 100%; | ||
padding: 10px 12px; | ||
border-radius: 5px; | ||
border: 1px solid var(--gray20); | ||
background: var(--white); | ||
|
||
.container { | ||
display: flex; | ||
align-items: flex-start; | ||
gap: 4px; | ||
} | ||
|
||
.circle { | ||
display: block; | ||
min-width: 4px; | ||
height: 4px; | ||
border-radius: 50%; | ||
margin-top: 10px; | ||
} | ||
|
||
.result { | ||
font-weight: 700; | ||
} | ||
|
||
.notifi-text { | ||
color: var(---black); | ||
text-align: left; | ||
font-family: "Spoqa Han Sans Neo"; | ||
font-size: 16px; | ||
font-style: normal; | ||
font-weight: 700; | ||
line-height: 20px; | ||
} | ||
|
||
.elapsed-time { | ||
color: var(--gray40); | ||
font-size: 12px; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React from "react"; | ||
import styles from "./Notification.module.scss"; | ||
import type { Notification } from "../types/types"; | ||
import useCookie from "@/hooks/useCookies"; | ||
import { useClearNotification } from "../hooks/useUserQuery"; | ||
|
||
export default function Notification({ | ||
alertId, | ||
name, | ||
result, | ||
elapsedTime, | ||
formattedTime, | ||
}: Notification) { | ||
const { id, jwt } = useCookie(); | ||
const mutation = useClearNotification(id, alertId, jwt); | ||
|
||
const handleDeleteNotification = () => { | ||
mutation.mutate(); | ||
}; | ||
|
||
return ( | ||
<div className={styles.wrapper} onClick={handleDeleteNotification}> | ||
<div className={styles.container}> | ||
<div | ||
className={styles.circle} | ||
style={{ | ||
background: | ||
result === "accepted" | ||
? "var(--blue20, #0080FF)" | ||
: "var(--red30, #EC5A46)", | ||
}} | ||
></div> | ||
<div className={styles.notifiText}> | ||
{name} ({formattedTime}) 공고 지원이{" "} | ||
<span | ||
className={styles.result} | ||
style={{ | ||
color: result === "accepted" ? "var(--blue20)" : "var(--red30)", | ||
}} | ||
> | ||
{result === "accepted" ? "승인" : "거절"} | ||
</span>{" "} | ||
되었어요. | ||
</div> | ||
</div> | ||
<span className={styles.elapsedTime}>{elapsedTime}</span> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { useMutation } from "react-query"; | ||
import { ClearNotification } from "./userRequest"; | ||
|
||
export function useClearNotification(id: string, alertId: string, jwt: string) { | ||
return useMutation(() => ClearNotification(id, alertId, jwt)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import axios from "axios"; | ||
import { BASE_URL } from "@/constants/constants"; | ||
|
||
export const ClearNotification = async ( | ||
id: string, | ||
alertId: string, | ||
jwt: string | ||
) => { | ||
try { | ||
await axios.put( | ||
`${BASE_URL}/users/${id}/alerts/${alertId}`, | ||
{}, | ||
{ | ||
headers: { | ||
Authorization: `${jwt}`, | ||
}, | ||
} | ||
); | ||
|
||
return { success: true }; | ||
} catch (error) { | ||
if (axios.isAxiosError(error)) { | ||
const status = error.response ? error.response.status : null; | ||
switch (status) { | ||
case 400: | ||
throw new Error("잘못된 요청입니다. 요청 형식을 확인해 주세요."); | ||
case 403: | ||
throw new Error("접근이 거부되었습니다. 권한을 확인해 주세요."); | ||
case 404: | ||
throw new Error( | ||
"요청한 리소스를 찾을 수 없습니다. URL을 확인해 주세요." | ||
); | ||
default: | ||
throw new Error("알 수 없는 에러가 발생했습니다."); | ||
} | ||
} else { | ||
throw new Error("네트워크 오류가 발생했습니다."); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import React from "react"; | ||
import styles from "./NotificationModal.module.scss"; | ||
import Image from "next/image"; | ||
import Notification from "./components/Notification"; | ||
import extractNotificationInfo from "./utils/extractNotificationInfo"; | ||
import { NotificationItem } from "./types/types"; | ||
import closeIcon from "@/public/image/close_icon.svg"; | ||
|
||
interface NotificationModalProps { | ||
handleClickNoti: () => void; | ||
isModalOpen: boolean; | ||
notificationList: NotificationItem[]; | ||
} | ||
|
||
export default function NotificationModal({ | ||
handleClickNoti, | ||
isModalOpen, | ||
notificationList, | ||
}: NotificationModalProps) { | ||
const notifications = extractNotificationInfo(notificationList); | ||
|
||
return ( | ||
isModalOpen && ( | ||
<div className={styles.wrapper}> | ||
<div className={styles.container}> | ||
<span | ||
className={styles.title} | ||
>{`알림 ${notificationList.length}개`}</span> | ||
<Image | ||
className={styles.styledCloseIcon} | ||
src={closeIcon} | ||
alt="close_icon" | ||
onClick={handleClickNoti} | ||
/> | ||
</div> | ||
{notificationList.length ? ( | ||
notifications.map((notification, index) => ( | ||
<Notification key={index} {...notification} /> | ||
)) | ||
) : ( | ||
<div className={styles.alertDiv}>알림이 없습니다.</div> | ||
)} | ||
</div> | ||
) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
export interface Notification { | ||
alertId: string; | ||
name: string; | ||
result: string; | ||
elapsedTime: string; | ||
formattedTime: string; | ||
} | ||
|
||
export interface NotificationItem { | ||
item: { | ||
id: string; | ||
createdAt: string; | ||
result: string; | ||
shop: { | ||
item: { | ||
name: string; | ||
}; | ||
}; | ||
notice: { | ||
item: { | ||
startsAt: string; | ||
workhour: number; | ||
}; | ||
}; | ||
}; | ||
} |
22 changes: 22 additions & 0 deletions
22
components/NotificationModal/utils/extractNotificationInfo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import getElapsedTime from "./getElapsedTime"; | ||
import { NotificationItem } from "../types/types"; | ||
import formatTimeRange from "./formatTimeRange"; | ||
|
||
export default function extractNotificationInfo( | ||
notificationList: NotificationItem[] | ||
) { | ||
const notifications = notificationList.map(({ item }) => { | ||
const { id, createdAt, result, shop, notice } = item; | ||
const { name } = shop.item; | ||
const { startsAt, workhour } = notice.item; | ||
|
||
const elapsedTime = getElapsedTime(createdAt); | ||
const formattedTime = formatTimeRange(startsAt, workhour); | ||
|
||
const alertId = id; | ||
|
||
return { alertId, name, result, elapsedTime, formattedTime }; | ||
}); | ||
|
||
return notifications; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
export default function formatTimeRange(startsAt: string, workhour: number) { | ||
const startsTime = new Date(startsAt); | ||
const endsTime = new Date(startsTime.getTime() + workhour * 60 * 60 * 1000); | ||
|
||
const formattedStartsAt = formatDate(startsTime, true); | ||
const formattedEndsAt = formatDate(endsTime, false); | ||
|
||
return `${formattedStartsAt} ~ ${formattedEndsAt}`; | ||
} | ||
|
||
function formatDate(date: Date, isStartTime: boolean): string { | ||
const newDate = date.toLocaleString("ko-KR", { timeZone: "Asia/Seoul" }); | ||
const year = date.getFullYear(); | ||
const month = (date.getMonth() + 1).toString().padStart(2, "0"); | ||
const day = date.getDate().toString().padStart(2, "0"); | ||
const hours = date.getHours().toString().padStart(2, "0"); | ||
const minutes = date.getMinutes().toString().padStart(2, "0"); | ||
|
||
return isStartTime | ||
? `${year}-${month}-${day} ${hours}:${minutes}` | ||
: `${hours}:${minutes}`; | ||
} | ||
|
||
export const utilFormatDuration = (duration: string, workhour: number) => { | ||
const date = duration.slice(0, 10).replace(/-/g, "."); | ||
const hours = parseInt(duration.slice(11, 13)); | ||
const minutes = duration.slice(14, 16); | ||
|
||
let endHours = hours + workhour; | ||
|
||
const startTime = `${hours.toString().padStart(2, "0")}:${minutes}`; | ||
const endTime = `${endHours}:${minutes}`; | ||
|
||
return `${date} ${startTime}~${endTime}`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export default function getElapsedTime(timeString: string) { | ||
const currentTime = new Date(); | ||
const givenTime = new Date(timeString); | ||
const elapsedMilliseconds = currentTime.getTime() - givenTime.getTime(); | ||
const elapsedMinutes = Math.floor(elapsedMilliseconds / (1000 * 60)); | ||
|
||
if (elapsedMinutes < 1) { | ||
return "방금 전"; | ||
} else if (elapsedMinutes < 60) { | ||
return `${elapsedMinutes}분 전`; | ||
} else if (elapsedMinutes < 60 * 24) { | ||
const elapsedHours = Math.floor(elapsedMinutes / 60); | ||
return `${elapsedHours}시간 전`; | ||
} else { | ||
const elapsedDays = Math.floor(elapsedMinutes / (60 * 24)); | ||
return `${elapsedDays}일 전`; | ||
} | ||
} |
Oops, something went wrong.