Skip to content

Commit

Permalink
UI: Notification
Browse files Browse the repository at this point in the history
  • Loading branch information
godmmt committed Dec 25, 2024
1 parent c4d9fe4 commit be21e37
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 24 deletions.
124 changes: 103 additions & 21 deletions src/components/beta/layout/notification.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 (
Expand All @@ -29,23 +101,33 @@ const Notification = ({

{/* // Info: (20241011 - Liz) 通知訊息面板 */}
{isPanelOpen && (
<div className="absolute right-0 top-full z-10 mt-10px w-400px rounded-lg bg-surface-neutral-surface-lv2 px-24px py-12px shadow-Dropshadow_M">
<p className="p-16px font-medium text-text-neutral-primary" onClick={closePanel}>
This is a test notification, in order to test whether the notification message panel is
successfully displayed.
</p>
<p className="p-16px font-medium text-text-neutral-tertiary" onClick={closePanel}>
This is a test notification, in order to test whether the notification message panel is
successfully displayed.
</p>
<p className="p-16px font-medium text-text-neutral-tertiary" onClick={closePanel}>
This is a test notification, in order to test whether the notification message panel is
successfully displayed.
</p>
<p className="p-16px font-medium text-text-neutral-tertiary" onClick={closePanel}>
This is a test notification, in order to test whether the notification message panel is
successfully displayed.
</p>
<div className="absolute right-0 top-full z-10 mt-10px flex w-400px flex-col rounded-lg bg-surface-neutral-surface-lv2 px-24px py-12px shadow-Dropshadow_M">
<button
type="button"
className="flex items-center gap-4px self-end rounded-xs px-16px py-8px text-button-text-secondary hover:bg-button-surface-soft-secondary-hover disabled:text-button-text-disable"
>
<FiCheckCircle size={16} />
<span className="text-sm font-medium">{t('dashboard:HEADER.MARK_AS_ALL_READ')}</span>
</button>

{!isNoData &&
notifications.map((notification) => (
<NotificationItem
key={notification.id}
notification={notification}
onMarkAsRead={onMarkAsRead}
/>
))}

{isNoData && (
<p className="p-12px text-center text-base font-medium text-text-neutral-tertiary">
{t('dashboard:HEADER.NO_NEW_NOTIFICATIONS')}
</p>
)}

<button type="button" className="self-end text-sm font-semibold text-link-text-primary">
{t('dashboard:HEADER.READ_MORE')}
</button>
</div>
)}
</section>
Expand Down
52 changes: 52 additions & 0 deletions src/components/beta/layout/notification_item.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<button
type="button"
onMouseEnter={() => onMarkAsRead(notification.id)}
className={`bg-surface-neutral-surface-lv2 p-12px text-left font-medium text-text-neutral-primary hover:bg-surface-neutral-surface-lv1 hover:text-text-neutral-link ${notification.isRead ? 'text-text-neutral-tertiary' : ''}`}
>
{notification.content}
</button>
);
}

if (notification.type === 'button') {
return (
<div
className={`flex flex-col gap-16px bg-surface-neutral-surface-lv2 p-12px font-medium text-text-neutral-primary hover:bg-surface-neutral-surface-lv1`}
>
<p>{`${t('dashboard:HEADER.YOU_HAVE_A_TEAM_INVITATION_FROM')}${notification.content} ”`}</p>

<div className="flex items-center justify-center gap-15px">
<button
type="button"
className="rounded-xs bg-button-surface-strong-secondary px-16px py-8px text-button-text-invert hover:bg-button-surface-strong-secondary-hover disabled:bg-button-surface-strong-disable disabled:text-button-text-disable"
>
{t('dashboard:HEADER.ACCEPT')}
</button>
<button
type="button"
className="rounded-xs border border-button-stroke-secondary px-16px py-8px text-button-text-secondary hover:border-button-stroke-primary-hover hover:text-button-text-primary-hover disabled:text-button-text-disable"
>
{t('dashboard:HEADER.DECLINE')}
</button>
</div>
</div>
);
}

return null;
};

export default NotificationItem;
6 changes: 6 additions & 0 deletions src/constants/notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface NotificationType {
id: string;
content: string | JSX.Element;
isRead: boolean;
type: 'text' | 'button';
}
8 changes: 7 additions & 1 deletion src/locales/cn/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
8 changes: 7 additions & 1 deletion src/locales/en/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
8 changes: 7 additions & 1 deletion src/locales/tw/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down

0 comments on commit be21e37

Please sign in to comment.