change all actions
This commit is contained in:
@@ -3,8 +3,9 @@ import { CloseCircle } from 'iconsax-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSharedStore } from '@/shared/store/sharedStore'
|
||||
import { useAuthStore } from '../../pages/auth/store/AuthStore'
|
||||
import { useSendEmail } from '../../pages/received/hooks/useEmailData'
|
||||
import { useGetMessageDetail, useSendEmail } from '../../pages/received/hooks/useEmailData'
|
||||
import { SendEmailDto } from '../../pages/received/types/Types'
|
||||
import { useUpdateDraft, useSendDraft } from '../../pages/draft/hooks/useDraftData'
|
||||
import Input from '../Input'
|
||||
import ReactQuill from 'react-quill-new';
|
||||
import Button from '../Button'
|
||||
@@ -16,8 +17,8 @@ import { toast } from '../Toast'
|
||||
|
||||
const NewMessage: FC = () => {
|
||||
const { t } = useTranslation('global')
|
||||
const [value, setValue] = useState('');
|
||||
const { setOpenNewMessage, openNewMessage } = useSharedStore()
|
||||
const [value, setValue] = useState<string>('');
|
||||
const { setOpenNewMessage, openNewMessage, draftData, setDraftData, editingDraftId, setEditingDraftId } = useSharedStore()
|
||||
const { email: userEmail } = useAuthStore()
|
||||
const [isClosing, setIsClosing] = useState(false)
|
||||
const [shouldRender, setShouldRender] = useState(false)
|
||||
@@ -38,6 +39,33 @@ const NewMessage: FC = () => {
|
||||
|
||||
// API hooks
|
||||
const sendEmailMutation = useSendEmail()
|
||||
const updateDraftMutation = useUpdateDraft()
|
||||
const sendDraftMutation = useSendDraft()
|
||||
|
||||
// Get draft detail if draftData exists
|
||||
const { data: draftDetail } = useGetMessageDetail(
|
||||
draftData?.id.toString() || '',
|
||||
draftData?.mailbox || '',
|
||||
!!draftData?.id
|
||||
)
|
||||
|
||||
// Load draft data into form when draft detail is available
|
||||
useEffect(() => {
|
||||
if (draftDetail) {
|
||||
// Extract emails from to array
|
||||
const toEmailsList = draftDetail.to?.map(recipient => recipient.address) || []
|
||||
setToEmails(toEmailsList)
|
||||
setSubject(draftDetail.subject || '')
|
||||
|
||||
// Try to load HTML content if available, fallback to text or intro
|
||||
const draftWithContent = draftDetail as unknown as { html?: string; text?: string; intro: string }
|
||||
const content = ensureString(draftWithContent.html || draftWithContent.text || draftWithContent.intro)
|
||||
setValue(content)
|
||||
|
||||
// Clear draft data after loading
|
||||
setDraftData(null)
|
||||
}
|
||||
}, [draftDetail, setDraftData])
|
||||
|
||||
useEffect(() => {
|
||||
if (openNewMessage) {
|
||||
@@ -62,6 +90,9 @@ const NewMessage: FC = () => {
|
||||
setIsClosing(true)
|
||||
setTimeout(() => {
|
||||
setOpenNewMessage(false)
|
||||
resetForm()
|
||||
setDraftData(null)
|
||||
setEditingDraftId(null)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
@@ -76,6 +107,12 @@ const NewMessage: FC = () => {
|
||||
return emailRegex.test(email)
|
||||
}
|
||||
|
||||
const ensureString = (val: unknown): string => {
|
||||
if (typeof val === 'string') return val
|
||||
if (val === null || val === undefined) return ''
|
||||
return String(val)
|
||||
}
|
||||
|
||||
const addEmailToList = (email: string) => {
|
||||
if (!isValidEmail(email)) {
|
||||
return
|
||||
@@ -156,25 +193,18 @@ const NewMessage: FC = () => {
|
||||
}
|
||||
|
||||
const handleEmailAction = async (isDraft: boolean = false) => {
|
||||
const isEditingDraft = !!editingDraftId
|
||||
|
||||
if (!isDraft && (toEmails.length === 0 || !subject)) {
|
||||
toast('لطفا تمام فیلدهای مورد نیاز را پر کنید', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
if (isDraft && toEmails.length === 0 && !subject && !value) {
|
||||
if (isDraft && toEmails.length === 0 && !subject && ensureString(value).trim() === '') {
|
||||
toast('حداقل یکی از فیلدها باید پر باشد', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
const emailData: SendEmailDto = {
|
||||
from: { address: userEmail || 'sender@example.com' },
|
||||
to: parseEmailAddresses(toEmails),
|
||||
subject,
|
||||
html: value,
|
||||
text: value.replace(/<[^>]*>/g, ''), // Strip HTML for text version
|
||||
...(isDraft && { isDraft: true, uploadOnly: true }),
|
||||
}
|
||||
|
||||
// Set appropriate loading state
|
||||
if (isDraft) {
|
||||
setIsSavingDraft(true)
|
||||
@@ -182,18 +212,73 @@ const NewMessage: FC = () => {
|
||||
setIsSending(true)
|
||||
}
|
||||
|
||||
await sendEmailMutation.mutateAsync(emailData, {
|
||||
onSuccess: (data) => {
|
||||
toast(data.message, 'success')
|
||||
try {
|
||||
let messageId = ''
|
||||
if (isEditingDraft) {
|
||||
// We're editing an existing draft
|
||||
const draftUpdateData = {
|
||||
to: parseEmailAddresses(toEmails),
|
||||
subject,
|
||||
html: ensureString(value),
|
||||
text: ensureString(value).replace(/<[^>]*>/g, ''),
|
||||
}
|
||||
|
||||
if (isDraft) {
|
||||
// Just update the draft
|
||||
await updateDraftMutation.mutateAsync({
|
||||
messageId: editingDraftId.toString(),
|
||||
draftData: draftUpdateData
|
||||
}, {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onSuccess: (data: any) => {
|
||||
messageId = data.data?.messageId
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Update first, then send
|
||||
await updateDraftMutation.mutateAsync({
|
||||
messageId: editingDraftId.toString(),
|
||||
draftData: {
|
||||
...draftUpdateData,
|
||||
isDraft: true,
|
||||
uploadOnly: true
|
||||
}
|
||||
}, {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onSuccess: (data: any) => {
|
||||
messageId = data.data?.messageId
|
||||
}
|
||||
})
|
||||
await sendDraftMutation.mutateAsync(messageId || editingDraftId.toString())
|
||||
toast('پیام با موفقیت ارسال شد', 'success')
|
||||
}
|
||||
handleClose()
|
||||
resetForm()
|
||||
},
|
||||
onSettled: () => {
|
||||
// Reset loading states
|
||||
setIsSending(false)
|
||||
setIsSavingDraft(false)
|
||||
} else {
|
||||
// Creating new email/draft
|
||||
const emailData: SendEmailDto = {
|
||||
from: { address: userEmail || 'sender@example.com' },
|
||||
to: parseEmailAddresses(toEmails),
|
||||
subject,
|
||||
html: ensureString(value),
|
||||
text: ensureString(value).replace(/<[^>]*>/g, ''),
|
||||
...(isDraft && { isDraft: true, uploadOnly: true }),
|
||||
}
|
||||
|
||||
await sendEmailMutation.mutateAsync(emailData, {
|
||||
onSuccess: (data) => {
|
||||
toast(data.message, 'success')
|
||||
handleClose()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in email action:', error)
|
||||
toast('خطا در انجام عملیات', 'error')
|
||||
} finally {
|
||||
// Reset loading states
|
||||
setIsSending(false)
|
||||
setIsSavingDraft(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSend = () => handleEmailAction(false)
|
||||
|
||||
@@ -50,7 +50,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const markAsSeenMutation = useMutation({
|
||||
mutationFn: markMessageAsSeen,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => markMessageAsSeen(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام به عنوان خوانده شده علامتگذاری شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -58,7 +58,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const archiveMutation = useMutation({
|
||||
mutationFn: moveMessageToArchive,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => moveMessageToArchive(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام به آرشیو منتقل شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -66,7 +66,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const favoriteMutation = useMutation({
|
||||
mutationFn: moveMessageToFavorite,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => moveMessageToFavorite(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام به علاقهمندیها اضافه شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -74,7 +74,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const moveToTrashMutation = useMutation({
|
||||
mutationFn: moveMessageToTrash,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => moveMessageToTrash(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام به سطل زباله منتقل شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -82,7 +82,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const deletePermanentlyMutation = useMutation({
|
||||
mutationFn: deleteMessagePermanently,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => deleteMessagePermanently(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام به طور کامل حذف شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -90,7 +90,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const sendEmailMutation = useMutation({
|
||||
mutationFn: sendEmail,
|
||||
mutationFn: ({ messageId }: { messageId: number }) => sendEmail(messageId),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'ایمیل با موفقیت ارسال شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -107,7 +107,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const deleteDraftMutation = useMutation({
|
||||
mutationFn: deleteDraft,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => deleteDraft(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیشنویس حذف شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -115,7 +115,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const sendDraftMutation = useMutation({
|
||||
mutationFn: sendDraft,
|
||||
mutationFn: ({ messageId }: { messageId: number }) => sendDraft(messageId),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیشنویس ارسال شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -123,7 +123,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const unfavoriteMutation = useMutation({
|
||||
mutationFn: unfavoriteMessage,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => unfavoriteMessage(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام از علاقهمندیها حذف شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -131,7 +131,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const unarchiveMutation = useMutation({
|
||||
mutationFn: unarchiveMessage,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => unarchiveMessage(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام از آرشیو خارج شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -139,7 +139,7 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
});
|
||||
|
||||
const restoreMutation = useMutation({
|
||||
mutationFn: restoreMessage,
|
||||
mutationFn: ({ messageId, mailbox }: { messageId: number; mailbox: string }) => restoreMessage(messageId, mailbox),
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'پیام بازگردانی شد', 'success');
|
||||
invalidateAllQueries();
|
||||
@@ -164,24 +164,24 @@ export const useEmailActions = (customRefetch?: () => void) => {
|
||||
return {
|
||||
// Bulk actions
|
||||
bulkAction: bulkActionMutation.mutate,
|
||||
bulkMarkAsSeen: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.SEEN }),
|
||||
bulkArchive: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.ARCHIVE }),
|
||||
bulkFavorite: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.FAVORITE }),
|
||||
bulkMoveToTrash: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.TRASH }),
|
||||
bulkDelete: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.DELETE }),
|
||||
bulkJunk: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.JUNK }),
|
||||
bulkUnfavorite: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.UNFAVORITE }),
|
||||
bulkUnarchive: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.UNARCHIVE }),
|
||||
bulkRestore: (messageIds: number[]) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.RESTORE }),
|
||||
bulkMarkAsSeen: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.SEEN, mailbox: mailbox }),
|
||||
bulkArchive: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.ARCHIVE, mailbox: mailbox }),
|
||||
bulkFavorite: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.FAVORITE, mailbox: mailbox }),
|
||||
bulkMoveToTrash: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.TRASH, mailbox: mailbox }),
|
||||
bulkDelete: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.DELETE, mailbox: mailbox }),
|
||||
bulkJunk: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.JUNK, mailbox: mailbox }),
|
||||
bulkUnfavorite: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.UNFAVORITE, mailbox: mailbox }),
|
||||
bulkUnarchive: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.UNARCHIVE, mailbox: mailbox }),
|
||||
bulkRestore: (messageIds: number[], mailbox: string) =>
|
||||
bulkActionMutation.mutate({ messageIds, action: BulkActionType.RESTORE, mailbox: mailbox }),
|
||||
|
||||
// Single actions (keeping for backward compatibility)
|
||||
markAsSeen: markAsSeenMutation.mutate,
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
"NOTIFICATION": "اعلان",
|
||||
"FINANCE": "مالی"
|
||||
},
|
||||
"success": "عملیات با موفقیت انجام شد",
|
||||
"attachment_select": "اضافه کردن فایل ضمیمه",
|
||||
"domain": {
|
||||
"table": {
|
||||
|
||||
@@ -82,13 +82,13 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkDelete(messageIds);
|
||||
emailActions.bulkDelete(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleRestoreSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkRestore(messageIds);
|
||||
emailActions.bulkRestore(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -96,12 +96,12 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'بازگردانی',
|
||||
icon: <RecoveryConvert size={16} color="black" />,
|
||||
onClick: () => emailActions.restore(message.id),
|
||||
onClick: () => emailActions.restore({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف دائم',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.deletePermanently(message.id),
|
||||
onClick: () => emailActions.deletePermanently({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -82,13 +82,13 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleUnarchiveSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkUnarchive(messageIds);
|
||||
emailActions.bulkUnarchive(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -96,12 +96,12 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'خروج از آرشیو',
|
||||
icon: <ArchiveSlash size={16} color="black" />,
|
||||
onClick: () => emailActions.unarchive(message.id),
|
||||
onClick: () => emailActions.unarchive({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useGetDrafts } from './hooks/useDraftData';
|
||||
import { DraftMessage } from './types/DraftTypes';
|
||||
import { formatDate } from '@/config/func';
|
||||
import { useEmailActions } from '@/hooks/useEmailActions';
|
||||
import { useSharedStore } from '@/shared/store/sharedStore';
|
||||
|
||||
const List: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -17,6 +18,7 @@ const List: FC = () => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [filters, setFilters] = useState<FilterValues>({});
|
||||
const emailActions = useEmailActions();
|
||||
const { setDraftData, setOpenNewMessage, setEditingDraftId } = useSharedStore();
|
||||
|
||||
const { data: draftData, isLoading, refetch, isFetching } = useGetDrafts({
|
||||
page: currentPage,
|
||||
@@ -113,14 +115,14 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
selectedMessages.forEach(message => {
|
||||
emailActions.deleteDraft(message.id);
|
||||
emailActions.deleteDraft({ messageId: message.id, mailbox: message.mailbox });
|
||||
});
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleSendSelected = () => {
|
||||
selectedMessages.forEach(message => {
|
||||
emailActions.sendDraft(message.id);
|
||||
emailActions.sendDraft({ messageId: message.id });
|
||||
});
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
@@ -134,17 +136,23 @@ const List: FC = () => {
|
||||
};
|
||||
|
||||
const handleDeleteDraft = (messageId: number) => {
|
||||
emailActions.deleteDraft(messageId);
|
||||
emailActions.deleteDraft({ messageId: messageId, mailbox: '' });
|
||||
};
|
||||
|
||||
const handleSendDraft = (messageId: number) => {
|
||||
emailActions.sendDraft(messageId);
|
||||
emailActions.sendDraft({ messageId: messageId });
|
||||
};
|
||||
|
||||
const handleEditDraft = (messageId: number) => {
|
||||
navigate(`/draft/edit/${messageId}`);
|
||||
};
|
||||
|
||||
const handleRowClick = (messageId: number, item: DraftMessage) => {
|
||||
setDraftData(item);
|
||||
setEditingDraftId(messageId);
|
||||
setOpenNewMessage(true);
|
||||
};
|
||||
|
||||
const getRowActions = (message: DraftMessage): RowActionItem[] => [
|
||||
{
|
||||
label: 'ارسال',
|
||||
@@ -193,7 +201,7 @@ const List: FC = () => {
|
||||
selectedActions={selectedActions}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
selectedRows={selectedMessages}
|
||||
onRowClick={(id) => navigate(`/draft/edit/${id}`)}
|
||||
onRowClick={handleRowClick}
|
||||
noDataMessage={
|
||||
<div className="flex flex-col items-center ">
|
||||
<InfoCircle size={32} className="text-gray-300 mb-2" />
|
||||
|
||||
@@ -42,4 +42,29 @@ export const useEditDraft = () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['drafts'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateDraft = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ messageId, draftData }: { messageId: string; draftData: DraftUpdateDto }) =>
|
||||
api.updateDraft(messageId, draftData),
|
||||
onSuccess: () => {
|
||||
// Invalidate drafts queries to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ['drafts'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useSendDraft = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (messageId: string) => api.sendDraft(messageId),
|
||||
onSuccess: () => {
|
||||
// Invalidate drafts queries to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ['drafts'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -29,9 +29,25 @@ export const editDraft = async (
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateDraft = async (
|
||||
messageId: string,
|
||||
draftData: DraftUpdateDto
|
||||
): Promise<void> => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/drafts/${messageId}`,
|
||||
draftData
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const sendDraft = async (messageId: string): Promise<void> => {
|
||||
const { data } = await axios.post(`/email/messages/drafts/${messageId}/send`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getDraftDetail = async (
|
||||
messageId: string
|
||||
): Promise<InboxMessage> => {
|
||||
const { data } = await axios.get(`/email/messages/drafts/${messageId}`);
|
||||
const { data } = await axios.get(`/email/messages/${messageId}`);
|
||||
return data.data.message;
|
||||
};
|
||||
|
||||
@@ -104,4 +104,6 @@ export interface DraftUpdateDto {
|
||||
text?: string;
|
||||
html?: string;
|
||||
attachments?: EmailAttachmentDto[];
|
||||
isDraft?: boolean;
|
||||
uploadOnly?: boolean;
|
||||
}
|
||||
|
||||
@@ -83,19 +83,19 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleArchiveSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkArchive(messageIds);
|
||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleUnfavoriteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkUnfavorite(messageIds);
|
||||
emailActions.bulkUnfavorite(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -103,17 +103,17 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'حذف از علاقهمندیها',
|
||||
icon: <Star size={16} color="black" />,
|
||||
onClick: () => emailActions.unfavorite(message.id),
|
||||
onClick: () => emailActions.unfavorite({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'بایگانی',
|
||||
icon: <Archive size={16} color="black" />,
|
||||
onClick: () => emailActions.archive(message.id),
|
||||
onClick: () => emailActions.archive({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@ const DetailEmail: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const emailActions = useEmailActions()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const { id, mailbox } = useParams<{ id: string, mailbox: string }>()
|
||||
const { email: userEmail } = useAuthStore()
|
||||
const [showAnswer, setShowAnswer] = useState<boolean>(false)
|
||||
const [value, setValue] = useState<string>('')
|
||||
const [priority, setPriority] = useState<string>('')
|
||||
|
||||
// API hooks
|
||||
const { data: messageDetail, isLoading, error } = useGetMessageDetail(id || '', !!id)
|
||||
const { data: messageDetail, isLoading, error } = useGetMessageDetail(id || '', mailbox || '', !!id)
|
||||
const sendEmailMutation = useSendEmail()
|
||||
// const saveDraftMutation = useSaveDraft()
|
||||
|
||||
@@ -113,7 +113,7 @@ const DetailEmail: FC = () => {
|
||||
useEffect(() => {
|
||||
if (messageDetail && !messageDetail.seen && id) {
|
||||
console.log('Marking message as seen:', id, 'Current seen status:', messageDetail.seen)
|
||||
emailActions.markAsSeen(Number(id))
|
||||
emailActions.markAsSeen({ messageId: Number(id), mailbox: mailbox || '' })
|
||||
}
|
||||
}, [messageDetail, emailActions, id])
|
||||
|
||||
|
||||
@@ -144,25 +144,25 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleArchiveSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkArchive(messageIds);
|
||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleMarkAsReadSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMarkAsSeen(messageIds);
|
||||
emailActions.bulkMarkAsSeen(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleFavoriteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkFavorite(messageIds);
|
||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -170,22 +170,22 @@ const List: FC = () => {
|
||||
{
|
||||
label: message.seen ? 'علامتگذاری به عنوان خوانده نشده' : 'علامتگذاری به عنوان خوانده شده',
|
||||
icon: <Edit size={16} color="black" />,
|
||||
onClick: () => emailActions.markAsSeen(message.id),
|
||||
onClick: () => emailActions.markAsSeen({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'اضافه به علاقهمندیها',
|
||||
icon: <Star1 size={16} color="black" />,
|
||||
onClick: () => emailActions.favorite(message.id),
|
||||
onClick: () => emailActions.favorite({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'بایگانی',
|
||||
icon: <Archive size={16} color="black" />,
|
||||
onClick: () => emailActions.archive(message.id),
|
||||
onClick: () => emailActions.archive({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -229,7 +229,7 @@ const List: FC = () => {
|
||||
selectedActions={selectedActions}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
selectedRows={selectedMessages}
|
||||
onRowClick={(id) => navigate(`/mail/${id}`)}
|
||||
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" />
|
||||
|
||||
@@ -31,10 +31,10 @@ export const useGetInbox = (query: MessageListQueryDto) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetMessageDetail = (messageId: string, enabled: boolean = true) => {
|
||||
export const useGetMessageDetail = (messageId: string, mailbox: string, enabled: boolean = true) => {
|
||||
return useQuery({
|
||||
queryKey: ['message', messageId],
|
||||
queryFn: () => api.getMessageDetail(messageId),
|
||||
queryKey: ['message', messageId, mailbox],
|
||||
queryFn: () => api.getMessageDetail(messageId, mailbox),
|
||||
enabled: !!messageId && enabled,
|
||||
staleTime: 0, // Always fetch fresh data for message details
|
||||
});
|
||||
|
||||
@@ -32,10 +32,11 @@ export const getInbox = async (
|
||||
};
|
||||
|
||||
export const getMessageDetail = async (
|
||||
messageId: string
|
||||
messageId: string,
|
||||
mailbox: string
|
||||
): Promise<MessageDetail> => {
|
||||
const { data }: { data: MessageDetailResponse } = await axios.get(
|
||||
`/email/messages/${messageId}`
|
||||
`/email/messages/${messageId}?mailbox=${mailbox}`
|
||||
);
|
||||
return data.data.message;
|
||||
};
|
||||
|
||||
@@ -303,4 +303,5 @@ export enum BulkActionType {
|
||||
export interface BulkActionRequest {
|
||||
messageIds: number[];
|
||||
action: BulkActionType;
|
||||
mailbox: string;
|
||||
}
|
||||
|
||||
@@ -90,19 +90,19 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleArchiveSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkArchive(messageIds);
|
||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleFavoriteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkFavorite(messageIds);
|
||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -110,17 +110,17 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'اضافه به علاقهمندیها',
|
||||
icon: <Star size={16} color="black" />,
|
||||
onClick: () => emailActions.favorite(message.id),
|
||||
onClick: () => emailActions.favorite({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'بایگانی',
|
||||
icon: <Archive size={16} color="black" />,
|
||||
onClick: () => emailActions.archive(message.id),
|
||||
onClick: () => emailActions.archive({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@ const List: FC = () => {
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
const handleRowClick = (id: number) => {
|
||||
navigate(`${Paths.detailEmail}${id}`);
|
||||
const handleRowClick = (id: number, item: InboxMessage) => {
|
||||
navigate(`${Paths.detailEmail}${id}/${item.mailbox}`);
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selectedRows: InboxMessage[]) => {
|
||||
@@ -104,19 +104,19 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleArchiveSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkArchive(messageIds);
|
||||
emailActions.bulkArchive(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleFavoriteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkFavorite(messageIds);
|
||||
emailActions.bulkFavorite(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -124,17 +124,17 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'اضافه به علاقهمندیها',
|
||||
icon: <Star size={16} color="black" />,
|
||||
onClick: () => emailActions.favorite(message.id),
|
||||
onClick: () => emailActions.favorite({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'بایگانی',
|
||||
icon: <Archive size={16} color="black" />,
|
||||
onClick: () => emailActions.archive(message.id),
|
||||
onClick: () => emailActions.archive({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ const List: FC = () => {
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
const messageIds = selectedMessages.map(message => message.id);
|
||||
emailActions.bulkMoveToTrash(messageIds);
|
||||
emailActions.bulkMoveToTrash(messageIds, selectedMessages[0].mailbox);
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
@@ -100,7 +100,7 @@ const List: FC = () => {
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => emailActions.moveToTrash(message.id),
|
||||
onClick: () => emailActions.moveToTrash({ messageId: message.id, mailbox: message.mailbox }),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const AppRouter: FC = () => {
|
||||
<Route path={Paths.favorite} element={<FavoriteList />} />
|
||||
<Route path={Paths.spam} element={<SpamList />} />
|
||||
<Route path={Paths.search} element={<SearchList />} />
|
||||
<Route path={Paths.detailEmail + ':id'} element={<DetailEmail />} />
|
||||
<Route path={Paths.detailEmail + ':id/:mailbox'} element={<DetailEmail />} />
|
||||
<Route path={Paths.login} element={<Login />} />
|
||||
<Route path={Paths.setting} element={<Setting />} />
|
||||
</Routes>
|
||||
|
||||
@@ -3,43 +3,68 @@ import { BulkActionRequest } from "../pages/received/types/Types";
|
||||
|
||||
// Bulk action for multiple messages
|
||||
export const bulkAction = async (request: BulkActionRequest) => {
|
||||
const { data } = await axios.post(`/email/messages/bulk-action`, request);
|
||||
const { data } = await axios.post(
|
||||
`/email/messages/bulk-action?mailbox=${request.mailbox}`,
|
||||
request
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Mark message as seen
|
||||
export const markMessageAsSeen = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/seen`);
|
||||
export const markMessageAsSeen = async (messageId: number, mailbox: string) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/seen?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Move message to archive
|
||||
export const moveMessageToArchive = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/archive`);
|
||||
export const moveMessageToArchive = async (
|
||||
messageId: number,
|
||||
mailbox: string
|
||||
) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/archive?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Move message to favorite
|
||||
export const moveMessageToFavorite = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/favorite`);
|
||||
export const moveMessageToFavorite = async (
|
||||
messageId: number,
|
||||
mailbox: string
|
||||
) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/favorite?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Move message to trash
|
||||
export const moveMessageToTrash = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/trash`);
|
||||
export const moveMessageToTrash = async (
|
||||
messageId: number,
|
||||
mailbox: string
|
||||
) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/trash?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Delete message permanently (only for trash mailbox)
|
||||
export const deleteMessagePermanently = async (messageId: number) => {
|
||||
const { data } = await axios.delete(`/email/messages/${messageId}`);
|
||||
export const deleteMessagePermanently = async (
|
||||
messageId: number,
|
||||
mailbox: string
|
||||
) => {
|
||||
const { data } = await axios.delete(
|
||||
`/email/messages/${messageId}?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Send email
|
||||
export const sendEmail = async (emailData: unknown) => {
|
||||
const { data } = await axios.post(`/email/send`, emailData);
|
||||
export const sendEmail = async (messageId: number) => {
|
||||
const { data } = await axios.post(`/email/send?messageId=${messageId}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -53,8 +78,10 @@ export const updateDraft = async (messageId: number, draftData: unknown) => {
|
||||
};
|
||||
|
||||
// Delete draft
|
||||
export const deleteDraft = async (messageId: number) => {
|
||||
const { data } = await axios.delete(`/email/messages/drafts/${messageId}`);
|
||||
export const deleteDraft = async (messageId: number, mailbox: string) => {
|
||||
const { data } = await axios.delete(
|
||||
`/email/messages/drafts/${messageId}?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -65,19 +92,25 @@ export const sendDraft = async (messageId: number) => {
|
||||
};
|
||||
|
||||
// Unfavorite message
|
||||
export const unfavoriteMessage = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/unfavorite`);
|
||||
export const unfavoriteMessage = async (messageId: number, mailbox: string) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/unfavorite?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Unarchive message
|
||||
export const unarchiveMessage = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/unarchive`);
|
||||
export const unarchiveMessage = async (messageId: number, mailbox: string) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/unarchive?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
// Restore message from trash
|
||||
export const restoreMessage = async (messageId: number) => {
|
||||
const { data } = await axios.patch(`/email/messages/${messageId}/restore`);
|
||||
export const restoreMessage = async (messageId: number, mailbox: string) => {
|
||||
const { data } = await axios.patch(
|
||||
`/email/messages/${messageId}/restore?mailbox=${mailbox}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -6,4 +6,8 @@ export const useSharedStore = create<SharedStoreType>((set) => ({
|
||||
setOpenSidebar: (value) => set({ openSidebar: value }),
|
||||
openNewMessage: false,
|
||||
setOpenNewMessage: (value) => set({ openNewMessage: value }),
|
||||
draftData: null,
|
||||
setDraftData: (draft) => set({ draftData: draft }),
|
||||
editingDraftId: null,
|
||||
setEditingDraftId: (id) => set({ editingDraftId: id }),
|
||||
}));
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { DraftMessage } from "@/pages/draft/types/DraftTypes";
|
||||
|
||||
export type SharedStoreType = {
|
||||
openSidebar: boolean;
|
||||
setOpenSidebar: (value: boolean) => void;
|
||||
openNewMessage: boolean;
|
||||
setOpenNewMessage: (value: boolean) => void;
|
||||
draftData: DraftMessage | null;
|
||||
setDraftData: (draft: DraftMessage | null) => void;
|
||||
editingDraftId: number | null;
|
||||
setEditingDraftId: (id: number | null) => void;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user