203 lines
7.9 KiB
TypeScript
203 lines
7.9 KiB
TypeScript
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 [nextCursor, setNextCursor] = useState<string | undefined>(undefined);
|
||
const [previousCursor, setPreviousCursor] = useState<string | undefined>(undefined);
|
||
const [filters, setFilters] = useState<FilterValues>({});
|
||
const emailActions = useEmailActions();
|
||
|
||
const { data: searchData, isLoading, refetch, isFetching } = useSearchMessages({
|
||
next: nextCursor,
|
||
previous: previousCursor,
|
||
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);
|
||
setNextCursor(undefined);
|
||
setPreviousCursor(undefined);
|
||
};
|
||
|
||
const handleSelectionChange = (selectedRows: SearchMessage[]) => {
|
||
setSelectedMessages(selectedRows);
|
||
};
|
||
|
||
const handleDeleteSelected = () => {
|
||
const messageIds = selectedMessages.map(message => message.id);
|
||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||
setSelectedMessages([]);
|
||
};
|
||
|
||
const handleArchiveSelected = () => {
|
||
const messageIds = selectedMessages.map(message => message.id);
|
||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||
setSelectedMessages([]);
|
||
};
|
||
|
||
const handleFavoriteSelected = () => {
|
||
const messageIds = selectedMessages.map(message => message.id);
|
||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||
setSelectedMessages([]);
|
||
};
|
||
|
||
const getRowActions = (message: SearchMessage): RowActionItem[] => [
|
||
{
|
||
label: 'اضافه به علاقهمندیها',
|
||
icon: <Star size={16} color="black" />,
|
||
onClick: () => emailActions.favorite({ 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 = 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 ? {
|
||
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}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default List
|