select all + mobile table in all pages
This commit is contained in:
@@ -58,10 +58,12 @@ const Table = <T extends RowDataType>({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// خروج از حالت انتخاب اگر هیچ آیتمی انتخاب نشده
|
// خروج از حالت انتخاب اگر هیچ آیتمی انتخاب نشده، ورود اگر آیتمی انتخاب شده
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (selectedRows.length === 0 && mobileSelectionMode) {
|
if (selectedRows.length === 0 && mobileSelectionMode) {
|
||||||
setMobileSelectionMode(false);
|
setMobileSelectionMode(false);
|
||||||
|
} else if (selectedRows.length > 0 && !mobileSelectionMode) {
|
||||||
|
setMobileSelectionMode(true);
|
||||||
}
|
}
|
||||||
}, [selectedRows.length, mobileSelectionMode]);
|
}, [selectedRows.length, mobileSelectionMode]);
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useEmptyTrash, useGetTrashMessages } from './hooks/useTrashData';
|
import { useEmptyTrash, useGetTrashMessages } from './hooks/useTrashData';
|
||||||
import { TrashMessage } from './types/TrashTypes';
|
import { TrashMessage } from './types/TrashTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import ModalConfrim from '@/components/ModalConfrim';
|
import ModalConfrim from '@/components/ModalConfrim';
|
||||||
import { ErrorType } from '@/helpers/types';
|
import { ErrorType } from '@/helpers/types';
|
||||||
import { toast } from '@/components/Toast';
|
import { toast } from '@/components/Toast';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -30,8 +31,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<TrashMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<TrashMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<TrashMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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<TrashMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'subject',
|
key: 'subject',
|
||||||
title: 'عنوان پیام',
|
title: 'عنوان پیام',
|
||||||
@@ -54,13 +74,72 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<span>{formatTime(item.date)}</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ستونهای موبایل (سه خطی)
|
||||||
|
const mobileColumns: ColumnType<TrashMessage>[] = [
|
||||||
|
{
|
||||||
|
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 = trashData?.data?.trashMails || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -91,18 +170,23 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: TrashMessage[]) => {
|
const handleSelectionChange = (selectedRows: TrashMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = trashData?.data?.trashMails || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkDelete(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkDelete(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRestoreSelected = () => {
|
const handleRestoreSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkRestore(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkRestore(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTrash = () => {
|
const handleTrash = () => {
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useGetArchiveMessages } from './hooks/useArchiveData';
|
import { useGetArchiveMessages } from './hooks/useArchiveData';
|
||||||
import { ArchiveMessage } from './types/ArchiveTypes';
|
import { ArchiveMessage } from './types/ArchiveTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -25,8 +26,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<ArchiveMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<ArchiveMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<ArchiveMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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<ArchiveMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'subject',
|
key: 'subject',
|
||||||
title: 'عنوان پیام',
|
title: 'عنوان پیام',
|
||||||
@@ -49,13 +69,72 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<span>{formatTime(item.date)}</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ستونهای موبایل (سه خطی)
|
||||||
|
const mobileColumns: ColumnType<ArchiveMessage>[] = [
|
||||||
|
{
|
||||||
|
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 = archiveData?.data?.archiveMails || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -81,18 +160,23 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: ArchiveMessage[]) => {
|
const handleSelectionChange = (selectedRows: ArchiveMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = archiveData?.data?.archiveMails || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnarchiveSelected = () => {
|
const handleUnarchiveSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkUnarchive(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkUnarchive(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowActions = (message: ArchiveMessage): RowActionItem[] => [
|
const getRowActions = (message: ArchiveMessage): RowActionItem[] => [
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useGetDrafts } from './hooks/useDraftData';
|
import { useGetDrafts } from './hooks/useDraftData';
|
||||||
import { DraftMessage } from './types/DraftTypes';
|
import { DraftMessage } from './types/DraftTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
import { useSharedStore } from '@/shared/store/sharedStore';
|
import { useSharedStore } from '@/shared/store/sharedStore';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -29,8 +30,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<DraftMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<DraftMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<DraftMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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<DraftMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'title',
|
key: 'title',
|
||||||
title: 'title',
|
title: 'title',
|
||||||
@@ -66,13 +86,73 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<span>{formatTime(item.date)}</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ستونهای موبایل (سه خطی)
|
||||||
|
const mobileColumns: ColumnType<DraftMessage>[] = [
|
||||||
|
{
|
||||||
|
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="text-[#0038FF] text-sm font-medium">پیش نویس</span>
|
||||||
|
<span className="text-xs text-gray-500 whitespace-nowrap ml-auto">
|
||||||
|
{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.to && item.to.length > 0
|
||||||
|
? (item.to[0].name || item.to[0].address)
|
||||||
|
: 'بدون گیرنده'
|
||||||
|
}
|
||||||
|
</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 = draftData?.data?.draftsMail || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -114,6 +194,9 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: DraftMessage[]) => {
|
const handleSelectionChange = (selectedRows: DraftMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = draftData?.data?.draftsMail || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
@@ -121,6 +204,7 @@ const List: FC = () => {
|
|||||||
emailActions.deleteDraft({ messageId: message.id, mailbox: message.mailbox });
|
emailActions.deleteDraft({ messageId: message.id, mailbox: message.mailbox });
|
||||||
});
|
});
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendSelected = () => {
|
const handleSendSelected = () => {
|
||||||
@@ -128,6 +212,7 @@ const List: FC = () => {
|
|||||||
emailActions.sendDraft({ messageId: message.id });
|
emailActions.sendDraft({ messageId: message.id });
|
||||||
});
|
});
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditSelected = () => {
|
const handleEditSelected = () => {
|
||||||
@@ -136,6 +221,8 @@ const List: FC = () => {
|
|||||||
} else {
|
} else {
|
||||||
console.log('ویرایش چندین پیشنویس انتخاب شده:', selectedMessages.map(m => m.id));
|
console.log('ویرایش چندین پیشنویس انتخاب شده:', selectedMessages.map(m => m.id));
|
||||||
}
|
}
|
||||||
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteDraft = (messageId: number) => {
|
const handleDeleteDraft = (messageId: number) => {
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useGetFavoriteMessages } from './hooks/useFavoriteData';
|
import { useGetFavoriteMessages } from './hooks/useFavoriteData';
|
||||||
import { FavoriteMessage } from './types/FavoriteTypes';
|
import { FavoriteMessage } from './types/FavoriteTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
import Favorite from '../received/Components/Favorite';
|
import Favorite from '../received/Components/Favorite';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -26,8 +27,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<FavoriteMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<FavoriteMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<FavoriteMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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',
|
key: 'subject',
|
||||||
title: 'عنوان پیام',
|
title: 'عنوان پیام',
|
||||||
@@ -50,13 +70,72 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<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 = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -83,24 +162,30 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: FavoriteMessage[]) => {
|
const handleSelectionChange = (selectedRows: FavoriteMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = favoriteData?.data?.favoriteMails || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchiveSelected = () => {
|
const handleArchiveSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnfavoriteSelected = () => {
|
const handleUnfavoriteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkUnfavorite(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkUnfavorite(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getInlineActions = (message: FavoriteMessage) => [
|
const getInlineActions = (message: FavoriteMessage) => [
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import Button from '@/components/Button';
|
|||||||
import ModalConfrim from '@/components/ModalConfrim';
|
import ModalConfrim from '@/components/ModalConfrim';
|
||||||
import { ErrorType } from '@/helpers/types';
|
import { ErrorType } from '@/helpers/types';
|
||||||
import { toast } from '@/components/Toast';
|
import { toast } from '@/components/Toast';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<InboxMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<InboxMessage[]>([]);
|
||||||
const [selectedMessage, setSelectedMessage] = useState<InboxMessage | null>(null);
|
const [selectedMessage, setSelectedMessage] = useState<InboxMessage | null>(null);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
// ستونهای دسکتاپ (مثل اولیه)
|
// ستونهای دسکتاپ (مثل اولیه)
|
||||||
const desktopColumns: ColumnType<InboxMessage>[] = [
|
const desktopColumns: ColumnType<InboxMessage>[] = [
|
||||||
@@ -102,7 +104,6 @@ const List: FC = () => {
|
|||||||
title: 'محتوا',
|
title: 'محتوا',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<div className="flex flex-col gap-1 w-full">
|
<div className="flex flex-col gap-1 w-full">
|
||||||
{/* سطر اول: فرستنده + ساعت */}
|
|
||||||
<div className="flex items-center gap-2 w-full">
|
<div className="flex items-center gap-2 w-full">
|
||||||
<span className="truncate font-medium text-sm flex-1 min-w-0">
|
<span className="truncate font-medium text-sm flex-1 min-w-0">
|
||||||
{item.from.name || item.from.address}
|
{item.from.name || item.from.address}
|
||||||
@@ -112,12 +113,10 @@ const List: FC = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* سطر دوم: موضوع */}
|
|
||||||
<div className="truncate w-full text-sm font-medium">
|
<div className="truncate w-full text-sm font-medium">
|
||||||
{item.subject || 'بدون موضوع'}
|
{item.subject || 'بدون موضوع'}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* سطر سوم: خلاصه */}
|
|
||||||
<div className="truncate w-full text-xs text-gray-600">
|
<div className="truncate w-full text-xs text-gray-600">
|
||||||
{item.intro || 'بدون متن پیشنمایش'}
|
{item.intro || 'بدون متن پیشنمایش'}
|
||||||
</div>
|
</div>
|
||||||
@@ -140,8 +139,25 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const columns = isMobile ? mobileColumns : desktopColumns;
|
const columns = isMobile ? mobileColumns : desktopColumns;
|
||||||
|
|
||||||
|
const handleSelectAll = (checked: boolean) => {
|
||||||
|
setSelectAll(checked);
|
||||||
|
if (checked) {
|
||||||
|
const messages = inboxData?.data?.results || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -186,30 +202,37 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: InboxMessage[]) => {
|
const handleSelectionChange = (selectedRows: InboxMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = inboxData?.data?.results || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchiveSelected = () => {
|
const handleArchiveSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMarkAsReadSelected = () => {
|
const handleMarkAsReadSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMarkAsSeen(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMarkAsSeen(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFavoriteSelected = () => {
|
const handleFavoriteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMarkAll = () => {
|
const handleMarkAll = () => {
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useSearchMessages } from './hooks/useSearchData';
|
import { useSearchMessages } from './hooks/useSearchData';
|
||||||
import { SearchMessage } from './types/SearchTypes';
|
import { SearchMessage } from './types/SearchTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -25,8 +26,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<SearchMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<SearchMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<SearchMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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<SearchMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'subject',
|
key: 'subject',
|
||||||
title: 'عنوان پیام',
|
title: 'عنوان پیام',
|
||||||
@@ -56,13 +76,75 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<span>{formatTime(item.date)}</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ستونهای موبایل (سه خطی)
|
||||||
|
const mobileColumns: ColumnType<SearchMessage>[] = [
|
||||||
|
{
|
||||||
|
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 bg-gray-100 px-1 py-0.5 rounded">
|
||||||
|
{item.mailbox}
|
||||||
|
</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 = searchData?.data?.results || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -89,24 +171,30 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: SearchMessage[]) => {
|
const handleSelectionChange = (selectedRows: SearchMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = searchData?.data?.results || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchiveSelected = () => {
|
const handleArchiveSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFavoriteSelected = () => {
|
const handleFavoriteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowActions = (message: SearchMessage): RowActionItem[] => [
|
const getRowActions = (message: SearchMessage): RowActionItem[] => [
|
||||||
|
|||||||
+88
-5
@@ -9,7 +9,8 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { Paths } from '../../utils/Paths';
|
import { Paths } from '../../utils/Paths';
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
import { RowActionItem } from '../../components/RowActionsDropdown';
|
import { RowActionItem } from '../../components/RowActionsDropdown';
|
||||||
import { formatDate } from '@/config/func';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -26,8 +27,27 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<InboxMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<InboxMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<InboxMessage>[] = [
|
// تابع برای گرفتن فقط ساعت
|
||||||
|
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<InboxMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'subject',
|
key: 'subject',
|
||||||
title: 'موضوع پیام',
|
title: 'موضوع پیام',
|
||||||
@@ -64,15 +84,72 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ ارسال',
|
title: 'تاریخ ارسال',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span className="">
|
<span>{formatTime(item.date)}</span>
|
||||||
{formatDate(item.date)}
|
|
||||||
</span>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ستونهای موبایل (سه خطی)
|
||||||
|
const mobileColumns: ColumnType<InboxMessage>[] = [
|
||||||
|
{
|
||||||
|
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.to.map(recipient => recipient.address).join(', ')}
|
||||||
|
</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 = sentData?.data?.sentMails || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -103,24 +180,30 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: InboxMessage[]) => {
|
const handleSelectionChange = (selectedRows: InboxMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
// تنظیم وضعیت select all بر اساس انتخاب شدهها
|
||||||
|
const messages = sentData?.data?.sentMails || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchiveSelected = () => {
|
const handleArchiveSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFavoriteSelected = () => {
|
const handleFavoriteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowActions = (message: InboxMessage): RowActionItem[] => [
|
const getRowActions = (message: InboxMessage): RowActionItem[] => [
|
||||||
|
|||||||
+82
-3
@@ -7,12 +7,13 @@ import { RowActionItem } from '../../components/RowActionsDropdown';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useEmptySpam, useGetSpamMessages } from './hooks/useSpamData';
|
import { useEmptySpam, useGetSpamMessages } from './hooks/useSpamData';
|
||||||
import { SpamMessage } from './types/SpamTypes';
|
import { SpamMessage } from './types/SpamTypes';
|
||||||
import { formatDate } from '@/config/func';
|
|
||||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import ModalConfrim from '@/components/ModalConfrim';
|
import ModalConfrim from '@/components/ModalConfrim';
|
||||||
import { ErrorType } from '@/helpers/types';
|
import { ErrorType } from '@/helpers/types';
|
||||||
import { toast } from '@/components/Toast';
|
import { toast } from '@/components/Toast';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const List: FC = () => {
|
const List: FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -31,8 +32,25 @@ const List: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [selectedMessages, setSelectedMessages] = useState<SpamMessage[]>([]);
|
const [selectedMessages, setSelectedMessages] = useState<SpamMessage[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
||||||
const columns: ColumnType<SpamMessage>[] = [
|
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<SpamMessage>[] = [
|
||||||
{
|
{
|
||||||
key: 'subject',
|
key: 'subject',
|
||||||
title: 'عنوان پیام',
|
title: 'عنوان پیام',
|
||||||
@@ -54,13 +72,70 @@ const List: FC = () => {
|
|||||||
title: 'تاریخ',
|
title: 'تاریخ',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<span>{formatDate(item.date)}</span>
|
<span>{formatTime(item.date)}</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const mobileColumns: ColumnType<SpamMessage>[] = [
|
||||||
|
{
|
||||||
|
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 = spamData?.data?.junkMails || [];
|
||||||
|
setSelectedMessages(messages);
|
||||||
|
} else {
|
||||||
|
setSelectedMessages([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tableActions = (
|
const tableActions = (
|
||||||
<div className='flex items-center gap-2 md:gap-4'>
|
<div className='flex items-center gap-2 md:gap-4'>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Checkbox
|
||||||
|
checked={selectAll}
|
||||||
|
onCheckedChange={handleSelectAll}
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Refresh2
|
<Refresh2
|
||||||
size={18}
|
size={18}
|
||||||
color='black'
|
color='black'
|
||||||
@@ -91,18 +166,22 @@ const List: FC = () => {
|
|||||||
|
|
||||||
const handleSelectionChange = (selectedRows: SpamMessage[]) => {
|
const handleSelectionChange = (selectedRows: SpamMessage[]) => {
|
||||||
setSelectedMessages(selectedRows);
|
setSelectedMessages(selectedRows);
|
||||||
|
const messages = spamData?.data?.junkMails || [];
|
||||||
|
setSelectAll(selectedRows.length === messages.length && messages.length > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSelected = () => {
|
const handleDeleteSelected = () => {
|
||||||
const messageIds = selectedMessages.map(message => message.id);
|
const messageIds = selectedMessages.map(message => message.id);
|
||||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNotSpamSelected = () => {
|
const handleNotSpamSelected = () => {
|
||||||
// TODO: پیادهسازی علامتگذاری به عنوان غیر اسپم - نیاز به API endpoint جداگانه
|
// TODO: پیادهسازی علامتگذاری به عنوان غیر اسپم - نیاز به API endpoint جداگانه
|
||||||
console.log('علامتگذاری به عنوان غیر اسپم:', selectedMessages.map(m => m.id));
|
console.log('علامتگذاری به عنوان غیر اسپم:', selectedMessages.map(m => m.id));
|
||||||
setSelectedMessages([]);
|
setSelectedMessages([]);
|
||||||
|
setSelectAll(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpam = () => {
|
const handleSpam = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user