293 lines
6.9 KiB
TypeScript
293 lines
6.9 KiB
TypeScript
'use client'
|
|
|
|
import { useTranslations } from 'next-intl';
|
|
import { IconCheck, IconArrowLeft, IconArrowRight, IconDoubleArrowLeft, IconDoubleArrowRight } from '@/app/ui/icons/icons';
|
|
import { useEffect, useState } from 'react';
|
|
import { useAllNotifications } from '@/app/hooks/react-query/useAllNotificationsList';
|
|
import { notificationsMarkAsRead } from '@/app/actions/notificationActions';
|
|
import { useQueryClient } from '@tanstack/react-query';
|
|
|
|
export function NotificationsList() {
|
|
const t = useTranslations('Global');
|
|
const queryClient = useQueryClient();
|
|
|
|
const [selectedFiles, setSelectedFiles] = useState<Set<number>>(new Set());
|
|
const [loadingIds, setLoadingIds] = useState<Set<number>>(new Set());
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [currentPage, setCurrentPage] = useState(0);
|
|
const [pageSize] = useState(10);
|
|
const { data: allNotifications, isLoading } = useAllNotifications(currentPage, pageSize);
|
|
|
|
|
|
const totalPages = allNotifications?.totalPages || 0;
|
|
const currentPageNum = allNotifications?.currentPage || 0;
|
|
|
|
const goToFirstPage = () => setCurrentPage(0);
|
|
const goToPrevPage = () => setCurrentPage(prev => Math.max(0, prev - 1));
|
|
const goToNextPage = () => setCurrentPage(prev => Math.min(totalPages - 1, prev + 1));
|
|
const goToLastPage = () => setCurrentPage(totalPages - 1);
|
|
const goToPage = (page: number) => setCurrentPage(page);
|
|
|
|
const getPageNumbers = (): (number | string)[] => {
|
|
const delta: number = 2;
|
|
const range: number[] = [];
|
|
const rangeWithDots: (number | string)[] = [];
|
|
let l: number | undefined;
|
|
|
|
for (let i = 0; i < totalPages; i++) {
|
|
if (i === 0 || i === totalPages - 1 || (i >= currentPageNum - delta && i <= currentPageNum + delta)) {
|
|
range.push(i);
|
|
}
|
|
}
|
|
|
|
range.forEach((i: number) => {
|
|
if (l !== undefined) {
|
|
if (i - l === 2) {
|
|
rangeWithDots.push(l + 1);
|
|
} else if (i - l !== 1) {
|
|
rangeWithDots.push('...');
|
|
}
|
|
}
|
|
rangeWithDots.push(i);
|
|
l = i;
|
|
});
|
|
|
|
return rangeWithDots;
|
|
};
|
|
|
|
useEffect(() => {
|
|
console.log(allNotifications);
|
|
}, [allNotifications])
|
|
|
|
function selectHandler(fileId: number) {
|
|
setSelectedFiles((prev) => {
|
|
const newSet = new Set(prev);
|
|
|
|
if (newSet.has(fileId)) {
|
|
newSet.delete(fileId)
|
|
} else {
|
|
newSet.add(fileId)
|
|
}
|
|
return newSet;
|
|
});
|
|
}
|
|
|
|
function clearHandler() {
|
|
setSelectedFiles(new Set());
|
|
}
|
|
|
|
function selectAllHandler() {
|
|
setSelectedFiles(new Set(allNotifications?.notifications.map(item => item.id)));
|
|
}
|
|
|
|
async function markAsReadHandler(ids: number[]) {
|
|
setLoadingIds(prev => {
|
|
const newSet = new Set(prev);
|
|
ids.forEach(id => newSet.add(id));
|
|
return newSet;
|
|
});
|
|
|
|
try {
|
|
/* const response = await notificationsMarkAsRead(ids);
|
|
|
|
if (response.success) {
|
|
await queryClient.invalidateQueries({ queryKey: ['activeNotifications'] });
|
|
await queryClient.invalidateQueries({ queryKey: ['allNotifications'] });
|
|
} */
|
|
} catch (error) {
|
|
setError(error instanceof Error ? error.message : 'Failed to mark as read');
|
|
} finally {
|
|
setLoadingIds(prev => {
|
|
const newSet = new Set(prev);
|
|
ids.forEach(id => newSet.delete(id));
|
|
return newSet;
|
|
});
|
|
|
|
setSelectedFiles(prev => {
|
|
const newSet = new Set(prev);
|
|
ids.forEach(id => newSet.delete(id));
|
|
return newSet;
|
|
});
|
|
}
|
|
}
|
|
|
|
function removeHandler(id: number) {
|
|
console.log(id);
|
|
|
|
setSelectedFiles(prev => {
|
|
prev.delete(id)
|
|
return new Set(prev);
|
|
});
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="notifications-list-wrapper"
|
|
>
|
|
<div
|
|
className="notifications-list-header"
|
|
>
|
|
<h4>
|
|
{t('all-notifications')}
|
|
</h4>
|
|
|
|
<div
|
|
className="notifications-list-action"
|
|
>
|
|
{(selectedFiles.size !== 0) && (
|
|
<>
|
|
<button
|
|
className="btn btn-primary"
|
|
onClick={() => {
|
|
clearHandler();
|
|
}}
|
|
>
|
|
{t('deselect')}
|
|
</button>
|
|
|
|
<button
|
|
className="btn btn-primary"
|
|
onClick={() => {
|
|
const array = Array.from(selectedFiles);
|
|
markAsReadHandler(array);
|
|
}}
|
|
>
|
|
{t('mark-all-as-read')}
|
|
</button>
|
|
</>
|
|
)}
|
|
<button
|
|
className="btn btn-primary"
|
|
onClick={() => {
|
|
selectAllHandler();
|
|
}}
|
|
>
|
|
{t('select-all')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div
|
|
className="notifications-list-body"
|
|
>
|
|
{(allNotifications?.notifications.length !== 0) && (
|
|
allNotifications?.notifications.map(item => {
|
|
return (
|
|
<div
|
|
className="notification-item"
|
|
key={item.id}
|
|
>
|
|
<div
|
|
className="notification-check"
|
|
>
|
|
<button
|
|
onClick={() => {
|
|
selectHandler(item.id);
|
|
}}
|
|
>
|
|
{selectedFiles.has(item.id) && (
|
|
<IconCheck />
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
<div
|
|
className="notification-body"
|
|
>
|
|
<div
|
|
className="notification-header"
|
|
>
|
|
<div
|
|
className="notification-title"
|
|
>
|
|
{item.type}
|
|
</div>
|
|
<div
|
|
className="notification-status"
|
|
>
|
|
{item.status}
|
|
</div>
|
|
</div>
|
|
<div
|
|
className="notification-text"
|
|
>
|
|
{item.message}
|
|
</div>
|
|
<div
|
|
className="notification-footer"
|
|
>
|
|
<div
|
|
className="notification-date"
|
|
>
|
|
{item.createdAt}
|
|
</div>
|
|
|
|
<button
|
|
className="btn btn-remove"
|
|
onClick={() => {
|
|
removeHandler(item.id);
|
|
}}
|
|
disabled={false}
|
|
>
|
|
{t('remove')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
})
|
|
)}
|
|
</div>
|
|
|
|
<div
|
|
className="notifications-list-footer"
|
|
>
|
|
{totalPages > 0 && (
|
|
<div className="pagination-controls">
|
|
<button
|
|
className="arrow"
|
|
onClick={goToFirstPage}
|
|
disabled={currentPageNum === 0}
|
|
>
|
|
<IconDoubleArrowLeft />
|
|
</button>
|
|
<button
|
|
onClick={goToPrevPage}
|
|
className="arrow"
|
|
disabled={currentPageNum === 0}
|
|
>
|
|
<IconArrowLeft />
|
|
</button>
|
|
|
|
<div className="pagination-controls-pages">
|
|
{getPageNumbers().map((pageNum, index) => (
|
|
<button
|
|
key={index}
|
|
onClick={() => typeof pageNum === 'number' && goToPage(pageNum)}
|
|
className={currentPageNum === pageNum ? 'current' : 'other'}
|
|
disabled={pageNum === '...'}
|
|
>
|
|
{pageNum === '...' ? '...' : (pageNum as number) + 1}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<button
|
|
onClick={goToNextPage}
|
|
className="arrow"
|
|
disabled={currentPageNum === totalPages - 1}
|
|
>
|
|
<IconArrowRight />
|
|
</button>
|
|
<button
|
|
className="arrow"
|
|
onClick={goToLastPage}
|
|
disabled={currentPageNum === totalPages - 1}
|
|
>
|
|
<IconDoubleArrowRight />
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
} |