email actions + sent list + action list + archive list + trash list

This commit is contained in:
hamid zarghami
2025-07-12 16:01:17 +03:30
parent fac9159ec0
commit 663dd1a9db
45 changed files with 1947 additions and 326 deletions
+192
View File
@@ -0,0 +1,192 @@
import Filters, { FilterValues } from '../../components/Filters';
import { FC, useState } from 'react'
import Table from '../../components/Table';
import { ColumnType } from '../../components/types/TableTypes';
import { InfoCircle, More, Refresh2, Trash, Archive, Star } from 'iconsax-react';
import { RowActionItem } from '../../components/RowActionsDropdown';
import { useNavigate } from 'react-router-dom';
import { useSearchMessages } from './hooks/useSearchData';
import { SearchMessage } from './types/SearchTypes';
import { formatDate } from '@/config/func';
import { useEmailActions } from '@/hooks/useEmailActions';
const List: FC = () => {
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const [filters, setFilters] = useState<FilterValues>({});
const emailActions = useEmailActions();
const { data: searchData, isLoading, refetch, isFetching } = useSearchMessages({
page: currentPage,
limit: 10,
...filters
});
const [selectedMessages, setSelectedMessages] = useState<SearchMessage[]>([]);
const columns: ColumnType<SearchMessage>[] = [
{
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: 'mailbox',
title: 'پوشه',
render: (item) => (
<span className="text-xs bg-gray-100 px-2 py-1 rounded">{item.mailbox}</span>
)
},
{
key: 'date',
title: 'تاریخ',
align: 'center',
render: (item) => (
<span>{formatDate(item.date)}</span>
)
},
];
const tableActions = (
<div className='flex items-center gap-2 md:gap-4'>
<Refresh2
size={18}
color='black'
className={`cursor-pointer ${isFetching ? 'animate-spin-reverse' : ''}`}
onClick={() => refetch()}
/>
<More size={18} color='black' className='rotate-90 cursor-pointer' />
</div>
);
const selectedActions = (
<>
<Star size={18} color='black' onClick={() => handleFavoriteSelected()} 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);
setCurrentPage(1);
};
const handleSelectionChange = (selectedRows: SearchMessage[]) => {
setSelectedMessages(selectedRows);
};
const handleDeleteSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkMoveToTrash(messageIds);
setSelectedMessages([]);
};
const handleArchiveSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkArchive(messageIds);
setSelectedMessages([]);
};
const handleFavoriteSelected = () => {
const messageIds = selectedMessages.map(message => message.id);
emailActions.bulkFavorite(messageIds);
setSelectedMessages([]);
};
const getRowActions = (message: SearchMessage): RowActionItem[] => [
{
label: 'اضافه به علاقه‌مندی‌ها',
icon: <Star size={16} color="black" />,
onClick: () => emailActions.favorite(message.id),
},
{
label: 'بایگانی',
icon: <Archive size={16} color="black" />,
onClick: () => emailActions.archive(message.id),
},
{
label: 'حذف',
icon: <Trash size={16} color="red" />,
onClick: () => emailActions.moveToTrash(message.id),
},
];
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const messages = searchData?.data?.results || [];
const pager = searchData?.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: 'input', name: 'q', placeholder: 'جستجو در عنوان، متن یا فرستنده...' },
{ type: 'date', name: 'dateFrom', placeholder: 'از تاریخ' },
{ type: 'date', name: 'dateTo', placeholder: 'تا تاریخ' },
{
type: 'select',
name: 'mailbox',
placeholder: 'تمام پوشه‌ها',
options: [
{ value: '', label: 'تمام پوشه‌ها' },
{ value: 'INBOX', label: 'دریافتی' },
{ value: 'Sent', label: 'ارسال شده' },
{ value: 'Drafts', label: 'پیش‌نویس' },
{ value: 'Trash', label: 'سطل آشغال' },
{ value: 'Archive', label: 'بایگانی' },
{ value: 'Junk', label: 'اسپم' },
]
}
]}
onChange={handleFilterChange}
searchField="q"
/>
<Table<SearchMessage>
columns={columns}
data={messages}
isLoading={isLoading || emailActions.isLoading}
showHeader={false}
actions={tableActions}
selectedActions={selectedActions}
onSelectionChange={handleSelectionChange}
selectedRows={selectedMessages}
onRowClick={(id) => navigate(`/mail/${id}`)}
noDataMessage={
<div className="flex flex-col items-center">
<InfoCircle size={32} className="text-gray-300 mb-2" />
<div className="text-sm">
{filters.q ? 'هیچ نتیجه‌ای یافت نشد' : 'برای جستجو کلمه مورد نظر را وارد کنید'}
</div>
</div>
}
selectable={true}
rowActions={getRowActions}
pagination={pager ? {
totalPages: pager.totalPages,
currentPage: pager.page,
onPageChange: handlePageChange
} : undefined}
/>
</div>
)
}
export default List