Files
dmail-front/src/pages/favorite/List.tsx
T
2025-07-30 09:47:21 +03:30

273 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Filters, { FilterValues } from '../../components/Filters';
import { FC, useState } from 'react'
import Table from '../../components/Table';
import { ColumnType } from '../../components/types/TableTypes';
import { InfoCircle, Refresh2, Trash, Archive, Star1 } from 'iconsax-react';
import { RowActionItem } from '../../components/RowActionsDropdown';
import { useNavigate } from 'react-router-dom';
import { useGetFavoriteMessages } from './hooks/useFavoriteData';
import { FavoriteMessage } from './types/FavoriteTypes';
import { useEmailActions } from '@/hooks/useEmailActions';
import Favorite from '../received/Components/Favorite';
import { Checkbox } from '@/components/ui/checkbox';
import React from 'react';
const List: FC = () => {
const navigate = useNavigate();
const [nextCursor, setNextCursor] = useState<string | undefined>(undefined);
const [previousCursor, setPreviousCursor] = useState<string | undefined>(undefined);
const [filters, setFilters] = useState<FilterValues>({});
const emailActions = useEmailActions();
const { data: favoriteData, isLoading, refetch, isFetching } = useGetFavoriteMessages({
next: nextCursor,
previous: previousCursor,
limit: 10,
...filters
});
const [selectedMessages, setSelectedMessages] = useState<FavoriteMessage[]>([]);
const [selectAll, setSelectAll] = useState(false);
// تابع برای گرفتن فقط ساعت
const formatTime = (dateString: string) => {
try {
if (!dateString) return '--:--';
const date = new Date(dateString);
if (isNaN(date.getTime())) return '--:--';
return new Intl.DateTimeFormat("fa-IR", {
hour: "2-digit",
minute: "2-digit",
}).format(date);
} catch (error) {
console.error('خطا در فرمت زمان:', error);
return '--:--';
}
};
// ستون‌های دسکتاپ
const desktopColumns: ColumnType<FavoriteMessage>[] = [
{
key: 'subject',
title: 'عنوان پیام',
render: (item) => (
<span className="truncate">{item.subject || 'بدون موضوع'}</span>
)
},
{
key: 'from',
title: 'فرستنده',
render: (item) => (
<div className="flex items-center">
{!item.seen && <div className="w-1.5 h-1.5 md:w-2 md:h-2 rounded-full bg-blue-500 ml-2" />}
<span className="truncate">{item.from.name || item.from.address}</span>
</div>
)
},
{
key: 'date',
title: 'تاریخ',
align: 'center',
render: (item) => (
<span>{formatTime(item.date)}</span>
)
},
];
// ستون‌های موبایل (سه خطی)
const mobileColumns: ColumnType<FavoriteMessage>[] = [
{
key: 'content',
title: 'محتوا',
render: (item) => (
<div className="flex flex-col gap-1 w-full">
<div className="flex items-center gap-2 w-full">
<span className="truncate font-medium text-sm flex-1 min-w-0">
{item.from.name || item.from.address}
</span>
<span className="text-xs text-gray-500 whitespace-nowrap">
{formatTime(item.date)}
</span>
</div>
<div className="truncate w-full text-sm font-medium">
{item.subject || 'بدون موضوع'}
</div>
<div className="truncate w-full text-xs text-gray-600">
{item.intro || 'بدون متن پیش‌نمایش'}
</div>
</div>
)
}
];
// انتخاب ستون‌ها بر اساس سایز صفحه
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
React.useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
const columns = isMobile ? mobileColumns : desktopColumns;
const handleSelectAll = (checked: boolean) => {
setSelectAll(checked);
if (checked) {
const messages = favoriteData?.data?.favoriteMails || [];
setSelectedMessages(messages);
} else {
setSelectedMessages([]);
}
};
const tableActions = (
<div className='flex items-center gap-4 md:gap-4'>
<div className="flex items-center gap-2">
<Checkbox
checked={selectAll}
onCheckedChange={handleSelectAll}
className="w-4 h-4"
/>
</div>
<Refresh2
size={18}
color='black'
className={`cursor-pointer ${isFetching ? 'animate-spin-reverse' : ''}`}
onClick={() => refetch()}
/>
</div>
);
const selectedActions = (
<>
<Star1 variant='Bold' size={18} color="#FFC107" onClick={() => handleUnfavoriteSelected()} className="cursor-pointer" />
<Archive size={18} color='black' onClick={() => handleArchiveSelected()} className="cursor-pointer" />
<Trash size={18} color='black' onClick={() => handleDeleteSelected()} className="cursor-pointer" />
</>
);
const handleFilterChange = (newFilters: FilterValues) => {
setFilters(newFilters);
setNextCursor(undefined);
setPreviousCursor(undefined);
};
const handleSelectionChange = (selectedRows: FavoriteMessage[]) => {
setSelectedMessages(selectedRows);
// تنظیم وضعیت select all بر اساس انتخاب شده‌ها
const messages = favoriteData?.data?.favoriteMails || [];
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
};
const handleDeleteSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
setSelectedMessages([]);
setSelectAll(false);
};
const handleArchiveSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
setSelectedMessages([]);
setSelectAll(false);
};
const handleUnfavoriteSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkUnfavorite(messageIds, selectedMessages[0].mailbox);
setSelectedMessages([]);
setSelectAll(false);
};
const getInlineActions = (message: FavoriteMessage) => [
{
icon: <Favorite flagged={message.flagged} id={message.id.toString()} mailbox={message.mailbox} />,
onClick: () => { },
},
];
const getRowActions = (message: FavoriteMessage): RowActionItem[] => [
{
label: 'حذف از علاقه‌مندی‌ها',
icon: <Star1 variant='Bold' size={16} color="#FFC107" />,
onClick: () => emailActions.unfavorite({ messageId: message.id, mailbox: message.mailbox }),
},
{
label: 'بایگانی',
icon: <Archive size={16} color="black" />,
onClick: () => emailActions.archive({ messageId: message.id, mailbox: message.mailbox }),
},
{
label: 'حذف',
icon: <Trash size={16} color="red" />,
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
},
];
const handleNext = (cursor?: string) => {
setNextCursor(cursor);
setPreviousCursor(undefined);
};
const handlePrevious = (cursor?: string) => {
setPreviousCursor(cursor);
setNextCursor(undefined);
};
const messages = favoriteData?.data?.favoriteMails || [];
const pager = favoriteData?.data?.pager;
return (
<div className='mt-2 md:mt-4 px-2 md:px-0'>
<h1 className="text-lg mb-4 md:mb-0">نشان شده ها</h1>
<Filters
fields={[
{ type: 'date', name: 'datestart', placeholder: 'از تاریخ' },
{ type: 'date', name: 'dateend', placeholder: 'تا تاریخ' },
{ type: 'input', name: 'search', placeholder: 'جستجو' }
]}
onChange={handleFilterChange}
searchField="search"
/>
<Table<FavoriteMessage>
columns={columns}
data={messages}
isLoading={isLoading || emailActions.isLoading}
showHeader={false}
actions={tableActions}
selectedActions={selectedActions}
onSelectionChange={handleSelectionChange}
selectedRows={selectedMessages}
onRowClick={(id, item) => navigate(`/mail/${id}/${item.mailbox}`)}
noDataMessage={
<div className="flex flex-col items-center">
<InfoCircle size={32} className="text-gray-300 mb-2" />
<div className="text-sm">هیچ پیامی یافت نشد.</div>
</div>
}
selectable={true}
rowActions={getRowActions}
pagination={pager ? {
hasNext: typeof pager.nextCursor === 'string',
nextCursor: typeof pager.nextCursor === 'string' ? pager.nextCursor : undefined,
previousCursor: typeof pager.previousCursor === 'string' ? pager.previousCursor : undefined,
onNext: handleNext,
onPrevious: handlePrevious
} : undefined}
inlineActions={getInlineActions}
/>
</div>
)
}
export default List