From be21e377562ac8c760f249f3b399a2811bf9a21f Mon Sep 17 00:00:00 2001 From: Liz Date: Wed, 25 Dec 2024 18:34:11 +0800 Subject: [PATCH] UI: Notification --- src/components/beta/layout/notification.tsx | 124 +++++++++++++++--- .../beta/layout/notification_item.tsx | 52 ++++++++ src/constants/notification.ts | 6 + src/locales/cn/dashboard.json | 8 +- src/locales/en/dashboard.json | 8 +- src/locales/tw/dashboard.json | 8 +- 6 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 src/components/beta/layout/notification_item.tsx create mode 100644 src/constants/notification.ts diff --git a/src/components/beta/layout/notification.tsx b/src/components/beta/layout/notification.tsx index ebf86a946..106de3c02 100644 --- a/src/components/beta/layout/notification.tsx +++ b/src/components/beta/layout/notification.tsx @@ -1,5 +1,43 @@ -import { Dispatch, SetStateAction } from 'react'; -import { FiBell } from 'react-icons/fi'; +import { Dispatch, SetStateAction, useState } from 'react'; +import { FiBell, FiCheckCircle } from 'react-icons/fi'; +import NotificationItem from '@/components/beta/layout/notification_item'; +import { NotificationType } from '@/constants/notification'; +import { useTranslation } from 'next-i18next'; + +const FAKE_NOTIFICATIONS: NotificationType[] = [ + { + id: '1', + content: + 'This is a test notification, in order to test whether the notification message panel is successfully displayed.', + isRead: false, + type: 'text', + }, + { + id: '2', + content: 'Hello! Welcome to iSunFA!', + isRead: false, + type: 'text', + }, + { + id: '3', + content: 'This is a test notification which is already read. So its color is gray.', + isRead: true, + type: 'text', + }, + { + id: '4', + content: 'Example Team', + isRead: false, + type: 'button', + }, + { + id: '5', + content: + 'This is a test notification, in order to test whether the notification message panel is successfully displayed.', + isRead: false, + type: 'text', + }, +]; interface NotificationProps { isPanelOpen: boolean; @@ -12,8 +50,42 @@ const Notification = ({ setIsPanelOpen, toggleNotificationPanel = () => setIsPanelOpen((prev) => !prev), }: NotificationProps) => { - const closePanel = () => { - setIsPanelOpen(false); + const { t } = useTranslation(['dashboard']); + const [notifications, setNotifications] = useState(FAKE_NOTIFICATIONS); + // ToDo: (20241225 - Liz) 等 API 可以使用後就改用 notifications 來判斷 + // const isNoData = notifications.length === 0; + const isNoData = false; + + // ToDo: (20241225 - Liz) 打開面板時打 API 取得通知 (搭配 useEffect) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const fetchNotifications = () => { + // setNotifications(); // 將取得的通知資料設定到 state + }; + + // ToDo: (20241225 - Liz) 打 API 更新通知為已讀 + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const readNotificationAPI = () => {}; + + // Info: (20241225 - Liz) 標記通知為已讀 + const onMarkAsRead = async (notificationId: string) => { + const notificationIndex = notifications.findIndex((n) => n.id === notificationId); + // Info: (20241225 - Liz) 如果通知不存在或已讀,則不執行任何操作 + if (notificationIndex === -1 || notifications[notificationIndex].isRead) { + return; + } + + try { + // ToDo: (20241225 - Liz) 呼叫 API 標記為已讀 + // await readNotificationAPI(notificationId); + + // ToDo: (20241225 - Liz) 更新本地狀態 + setNotifications((prev) => + prev.map((n) => (n.id === notificationId ? { ...n, isRead: true } : n)) + ); + } catch (error) { + // ToDo: (20241225 - Liz) 處理錯誤 + // console.error(`Failed to mark notification ${notificationId} as read`, error); + } }; return ( @@ -29,23 +101,33 @@ const Notification = ({ {/* // Info: (20241011 - Liz) 通知訊息面板 */} {isPanelOpen && ( -
-

- This is a test notification, in order to test whether the notification message panel is - successfully displayed. -

-

- This is a test notification, in order to test whether the notification message panel is - successfully displayed. -

-

- This is a test notification, in order to test whether the notification message panel is - successfully displayed. -

-

- This is a test notification, in order to test whether the notification message panel is - successfully displayed. -

+
+ + + {!isNoData && + notifications.map((notification) => ( + + ))} + + {isNoData && ( +

+ {t('dashboard:HEADER.NO_NEW_NOTIFICATIONS')} +

+ )} + +
)} diff --git a/src/components/beta/layout/notification_item.tsx b/src/components/beta/layout/notification_item.tsx new file mode 100644 index 000000000..205937d56 --- /dev/null +++ b/src/components/beta/layout/notification_item.tsx @@ -0,0 +1,52 @@ +import { NotificationType } from '@/constants/notification'; +import { useTranslation } from 'next-i18next'; + +type NotificationItemProps = { + notification: NotificationType; + onMarkAsRead: (id: string) => void; +}; + +const NotificationItem = ({ notification, onMarkAsRead }: NotificationItemProps) => { + const { t } = useTranslation(['dashboard']); + + if (notification.type === 'text') { + return ( + + ); + } + + if (notification.type === 'button') { + return ( +
+

{`${t('dashboard:HEADER.YOU_HAVE_A_TEAM_INVITATION_FROM')} “ ${notification.content} ”`}

+ +
+ + +
+
+ ); + } + + return null; +}; + +export default NotificationItem; diff --git a/src/constants/notification.ts b/src/constants/notification.ts new file mode 100644 index 000000000..524bb2f1a --- /dev/null +++ b/src/constants/notification.ts @@ -0,0 +1,6 @@ +export interface NotificationType { + id: string; + content: string | JSX.Element; + isRead: boolean; + type: 'text' | 'button'; +} diff --git a/src/locales/cn/dashboard.json b/src/locales/cn/dashboard.json index 8d77a64bb..30baa2109 100644 --- a/src/locales/cn/dashboard.json +++ b/src/locales/cn/dashboard.json @@ -51,7 +51,13 @@ "LOGOUT": "登出", "LOGIN": "登录", "LANGUAGE": "语言", - "SWITCH_ROLE": "切换角色" + "SWITCH_ROLE": "切换角色", + "NO_NEW_NOTIFICATIONS": "没有新通知", + "MARK_AS_ALL_READ": "全部标记为已读", + "READ_MORE": "载入更多通知", + "YOU_HAVE_A_TEAM_INVITATION_FROM": "您有一个团队邀请来自", + "ACCEPT": "接受", + "DECLINE": "拒绝" }, "ROLE": { diff --git a/src/locales/en/dashboard.json b/src/locales/en/dashboard.json index d651158fc..becd9764b 100644 --- a/src/locales/en/dashboard.json +++ b/src/locales/en/dashboard.json @@ -51,7 +51,13 @@ "LOGOUT": "Logout", "LOGIN": "Login", "LANGUAGE": "Language", - "SWITCH_ROLE": "Switch Role" + "SWITCH_ROLE": "Switch Role", + "NO_NEW_NOTIFICATIONS": "No New Notifications", + "MARK_AS_ALL_READ": "Mark as all read", + "READ_MORE": "Read more", + "YOU_HAVE_A_TEAM_INVITATION_FROM": "You have a team invitation from", + "ACCEPT": "Accept", + "DECLINE": "Decline" }, "ROLE": { diff --git a/src/locales/tw/dashboard.json b/src/locales/tw/dashboard.json index 4386ee1bf..03b56f1d8 100644 --- a/src/locales/tw/dashboard.json +++ b/src/locales/tw/dashboard.json @@ -51,7 +51,13 @@ "LOGOUT": "登出", "LOGIN": "登入", "LANGUAGE": "語言", - "SWITCH_ROLE": "切換角色" + "SWITCH_ROLE": "切換角色", + "NO_NEW_NOTIFICATIONS": "沒有新通知", + "MARK_AS_ALL_READ": "全部標記為已讀", + "READ_MORE": "載入更多通知", + "YOU_HAVE_A_TEAM_INVITATION_FROM": "您有一個團隊邀請來自", + "ACCEPT": "接受", + "DECLINE": "拒絕" }, "ROLE": {