Merge branch 'fe/refactor/notification-popover' into 'fe/develop'
Refactor: 알림 컴포넌트에서 하위 컴포넌트 분리, 알림 컴포넌트 스크롤 처리 See merge request s11-s-project/S11P21S002!235
This commit is contained in:
commit
f5de5a9c48
74
frontend/src/components/Header/AlarmItem.tsx
Normal file
74
frontend/src/components/Header/AlarmItem.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { AlarmResponse } from '@/types';
|
||||||
|
import { Mail, MailOpen, Trash2 } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function AlarmItem({
|
||||||
|
alarm,
|
||||||
|
onRead,
|
||||||
|
onDelete,
|
||||||
|
}: {
|
||||||
|
alarm: AlarmResponse;
|
||||||
|
onRead: (alarmId: number) => void;
|
||||||
|
onDelete: (alarmId: number) => void;
|
||||||
|
}) {
|
||||||
|
const timeAgo = (date: string | Date) => {
|
||||||
|
const now = new Date();
|
||||||
|
const past = new Date(date);
|
||||||
|
const diffInSeconds = Math.floor((now.getTime() - past.getTime()) / 1000);
|
||||||
|
|
||||||
|
if (diffInSeconds < 60) return `${Math.max(diffInSeconds, 0)}초 전`;
|
||||||
|
const diffInMinutes = Math.floor(diffInSeconds / 60);
|
||||||
|
if (diffInMinutes < 60) return `${diffInMinutes}분 전`;
|
||||||
|
const diffInHours = Math.floor(diffInMinutes / 60);
|
||||||
|
if (diffInHours < 24) return `${diffInHours}시간 전`;
|
||||||
|
const diffInDays = Math.floor(diffInHours / 24);
|
||||||
|
return `${diffInDays}일 전`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRead = () => {
|
||||||
|
onRead(alarm.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
onDelete(alarm.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex w-full items-center bg-white py-2 pr-[18px] duration-150 hover:bg-gray-200">
|
||||||
|
<div className={cn('mx-1.5 h-1.5 w-1.5 rounded-full', alarm.isRead ? 'bg-transparent' : 'bg-blue-500')}></div>
|
||||||
|
<div className="flex flex-1 flex-col">
|
||||||
|
<p className={cn('body-small', alarm.isRead ? 'text-gray-400' : 'text-black')}>
|
||||||
|
[{alarm.id}] {alarm.type} 알림입니다.
|
||||||
|
</p>
|
||||||
|
<p className="caption text-gray-500">{timeAgo(alarm.createdAt)}</p>
|
||||||
|
</div>
|
||||||
|
{alarm.isRead ? (
|
||||||
|
<button
|
||||||
|
className="p-1"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<MailOpen
|
||||||
|
size={16}
|
||||||
|
className="stroke-gray-400"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className="p-1"
|
||||||
|
onClick={handleRead}
|
||||||
|
>
|
||||||
|
<Mail size={16} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
className="p-1"
|
||||||
|
onClick={handleDelete}
|
||||||
|
>
|
||||||
|
<Trash2
|
||||||
|
size={16}
|
||||||
|
className="stroke-red-500"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { Bell } from 'lucide-react';
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
||||||
import { onMessage } from 'firebase/messaging';
|
import { onMessage } from 'firebase/messaging';
|
||||||
import { messaging } from '@/api/firebaseConfig';
|
import { messaging } from '@/api/firebaseConfig';
|
||||||
|
import AlarmItem from './AlarmItem';
|
||||||
import useFcmTokenQuery from '@/queries/auth/useFcmTokenQuery';
|
import useFcmTokenQuery from '@/queries/auth/useFcmTokenQuery';
|
||||||
import useGetAlarmListQuery from '@/queries/alarms/useGetAlarmListQuery';
|
import useGetAlarmListQuery from '@/queries/alarms/useGetAlarmListQuery';
|
||||||
import useResetAlarmListQuery from '@/queries/alarms/useResetAlarmListQuery';
|
import useResetAlarmListQuery from '@/queries/alarms/useResetAlarmListQuery';
|
||||||
@ -9,26 +12,10 @@ import useCreateAlarmTestQuery from '@/queries/alarms/useCreateAlarmTestQuery';
|
|||||||
import useReadAlarmQuery from '@/queries/alarms/useReadAlarmQuery';
|
import useReadAlarmQuery from '@/queries/alarms/useReadAlarmQuery';
|
||||||
import useDeleteAlarmQuery from '@/queries/alarms/useDeleteAlarmQuery';
|
import useDeleteAlarmQuery from '@/queries/alarms/useDeleteAlarmQuery';
|
||||||
import useDeleteAllAlarmQuery from '@/queries/alarms/useDeleteAllAlarmQuery';
|
import useDeleteAllAlarmQuery from '@/queries/alarms/useDeleteAllAlarmQuery';
|
||||||
import { Bell, Mail, MailOpen, Trash2 } from 'lucide-react';
|
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
|
||||||
|
|
||||||
export default function AlarmPopover() {
|
export default function AlarmPopover() {
|
||||||
const [unread, setUnread] = useState<boolean>(false);
|
const [unread, setUnread] = useState<boolean>(false);
|
||||||
|
|
||||||
const timeAgo = (date: string | Date) => {
|
|
||||||
const now = new Date();
|
|
||||||
const past = new Date(date);
|
|
||||||
const diffInSeconds = Math.floor((now.getTime() - past.getTime()) / 1000);
|
|
||||||
|
|
||||||
if (diffInSeconds < 60) return `${Math.max(diffInSeconds, 0)}초 전`;
|
|
||||||
const diffInMinutes = Math.floor(diffInSeconds / 60);
|
|
||||||
if (diffInMinutes < 60) return `${diffInMinutes}분 전`;
|
|
||||||
const diffInHours = Math.floor(diffInMinutes / 60);
|
|
||||||
if (diffInHours < 24) return `${diffInHours}시간 전`;
|
|
||||||
const diffInDays = Math.floor(diffInHours / 24);
|
|
||||||
return `${diffInDays}일 전`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetAlarmList = useResetAlarmListQuery();
|
const resetAlarmList = useResetAlarmListQuery();
|
||||||
const createAlarmTest = useCreateAlarmTestQuery();
|
const createAlarmTest = useCreateAlarmTestQuery();
|
||||||
const readAlarm = useReadAlarmQuery();
|
const readAlarm = useReadAlarmQuery();
|
||||||
@ -101,7 +88,7 @@ export default function AlarmPopover() {
|
|||||||
>
|
>
|
||||||
테스트
|
테스트
|
||||||
</button>
|
</button>
|
||||||
{unread ? (
|
{/* {unread ? (
|
||||||
<button
|
<button
|
||||||
className="body-small p-1"
|
className="body-small p-1"
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
@ -115,7 +102,7 @@ export default function AlarmPopover() {
|
|||||||
>
|
>
|
||||||
모두 읽지 않음
|
모두 읽지 않음
|
||||||
</button>
|
</button>
|
||||||
)}
|
)} */}
|
||||||
<button
|
<button
|
||||||
className="body-small p-1 text-red-500"
|
className="body-small p-1 text-red-500"
|
||||||
onClick={handleDeleteAllAlarm}
|
onClick={handleDeleteAllAlarm}
|
||||||
@ -125,62 +112,25 @@ export default function AlarmPopover() {
|
|||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
{alarms.length == 0 && (
|
{alarms.length === 0 ? (
|
||||||
<div className="flex w-full items-center px-[18px] py-3 duration-150">
|
<div className="flex w-full items-center px-[18px] py-3 duration-150">
|
||||||
<p className="body-small text-gray-500">알림이 없습니다.</p>
|
<p className="body-small text-gray-500">알림이 없습니다.</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
|
<div className="flex max-h-[500px] w-full flex-col items-center overflow-y-auto">
|
||||||
{alarms
|
{alarms
|
||||||
.slice()
|
.slice()
|
||||||
.reverse()
|
.reverse()
|
||||||
.map((alarm) => (
|
.map((alarm) => (
|
||||||
<div
|
<AlarmItem
|
||||||
key={alarm.id}
|
key={alarm.id}
|
||||||
className="flex w-full items-center bg-white py-2 pr-[18px] duration-150 hover:bg-gray-200"
|
alarm={alarm}
|
||||||
>
|
onRead={handleReadAlarm}
|
||||||
<div
|
onDelete={handleDeleteAlarm}
|
||||||
className={cn('mx-1.5 h-1.5 w-1.5 rounded-full', alarm.isRead ? 'bg-transparent' : 'bg-blue-500')}
|
|
||||||
></div>
|
|
||||||
<div className="flex flex-1 flex-col">
|
|
||||||
<p className="body-small">
|
|
||||||
[{alarm.id}] {alarm.type} 알림입니다.
|
|
||||||
</p>
|
|
||||||
<p className="caption text-gray-500">{timeAgo(alarm.createdAt)}</p>
|
|
||||||
</div>
|
|
||||||
{alarm.isRead ? (
|
|
||||||
<button
|
|
||||||
className="p-1"
|
|
||||||
onClick={() => {}}
|
|
||||||
>
|
|
||||||
<MailOpen
|
|
||||||
size={16}
|
|
||||||
className="stroke-gray-400"
|
|
||||||
/>
|
/>
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
className="p-1"
|
|
||||||
onClick={() => {
|
|
||||||
handleReadAlarm(alarm.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Mail size={16} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
className="p-1"
|
|
||||||
onClick={() => {
|
|
||||||
handleDeleteAlarm(alarm.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Trash2
|
|
||||||
size={16}
|
|
||||||
className="stroke-red-500"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user