recive email + save draft and list draft + skeleton email detail
This commit is contained in:
+98
-43
@@ -5,42 +5,55 @@ import Table from '../../components/Table';
|
||||
import { ColumnType } from '../../components/types/TableTypes';
|
||||
import { InfoCircle, More, Refresh2, Trash, Edit } from 'iconsax-react';
|
||||
import { RowActionItem } from '../../components/RowActionsDropdown';
|
||||
|
||||
interface Message extends Record<string, unknown> {
|
||||
id: string;
|
||||
title: string;
|
||||
sender: string;
|
||||
date: string;
|
||||
read: boolean;
|
||||
}
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useGetDrafts, useDeleteDraft } from './hooks/useDraftData';
|
||||
import { DraftMessage } from './types/DraftTypes';
|
||||
import { formatDate } from '@/config/func';
|
||||
|
||||
const List: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const [isLoading] = useState(false);
|
||||
const [selectedMessages, setSelectedMessages] = useState<Message[]>([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [filters, setFilters] = useState<FilterValues>({});
|
||||
|
||||
const messageData: Message[] = [
|
||||
{ id: '1', title: 'اولین پیام', sender: 'علی محمدی', date: '1402/05/12', read: true },
|
||||
{ id: '2', title: 'دومین پیام', sender: 'زهرا احمدی', date: '1402/05/13', read: true },
|
||||
{ id: '3', title: 'جلسه هفتگی', sender: 'مدیریت', date: '1402/05/14', read: true },
|
||||
];
|
||||
const { data: draftData, isLoading, refetch, isFetching } = useGetDrafts({
|
||||
page: currentPage,
|
||||
limit: 10,
|
||||
...filters
|
||||
});
|
||||
|
||||
const columns: ColumnType<Message>[] = [
|
||||
const deleteMutation = useDeleteDraft();
|
||||
const [selectedMessages, setSelectedMessages] = useState<DraftMessage[]>([]);
|
||||
|
||||
const columns: ColumnType<DraftMessage>[] = [
|
||||
{
|
||||
key: 'title',
|
||||
title: 'عنوان پیام',
|
||||
render: (item) => (
|
||||
<div className="flex items-center">
|
||||
{!item.read && <div className="w-1.5 h-1.5 md:w-2 md:h-2 rounded-full bg-blue-500 mr-2" />}
|
||||
<span className="truncate">{item.title}</span>
|
||||
title: 'title',
|
||||
render: () => (
|
||||
<div className="text-[#0038FF]">
|
||||
پیش نویس
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'sender',
|
||||
title: 'فرستنده',
|
||||
key: 'subject',
|
||||
title: 'عنوان پیام',
|
||||
render: (item) => (
|
||||
<span className="truncate">{item.sender}</span>
|
||||
<div className="flex items-center">
|
||||
<span className="truncate">{item.subject || 'بدون موضوع'}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'to',
|
||||
title: 'گیرنده',
|
||||
render: (item) => (
|
||||
<span className="truncate">
|
||||
{item.to && item.to.length > 0
|
||||
? (item.to[0].name || item.to[0].address)
|
||||
: 'بدون گیرنده'
|
||||
}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -48,87 +61,129 @@ const List: FC = () => {
|
||||
title: 'تاریخ',
|
||||
align: 'center',
|
||||
render: (item) => (
|
||||
<span className="text-xs md:text-sm">{item.date}</span>
|
||||
<span>{formatDate(item.date)}</span>
|
||||
)
|
||||
},
|
||||
];
|
||||
|
||||
const tableActions = (
|
||||
<div className='flex items-center gap-2 md:gap-4'>
|
||||
<Refresh2 size={18} color='black' className="cursor-pointer" />
|
||||
<Refresh2
|
||||
size={18}
|
||||
color='black'
|
||||
className={`cursor-pointer ${isFetching ? 'animate-spin-reverse' : ''}`}
|
||||
onClick={() => refetch()}
|
||||
/>
|
||||
<More size={18} color='black' className='rotate-90 cursor-pointer' />
|
||||
</div>
|
||||
);
|
||||
|
||||
const selectedActions = (
|
||||
<>
|
||||
<Trash size={18} color='black' onClick={() => handleDeleteSelected()} className="cursor-pointer" />
|
||||
<Edit size={18} color='black' onClick={() => handleEditSelected()} className="cursor-pointer" />
|
||||
<Trash
|
||||
size={18}
|
||||
color='black'
|
||||
onClick={() => handleDeleteSelected()}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
<Edit
|
||||
size={18}
|
||||
color='black'
|
||||
onClick={() => handleEditSelected()}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
const handleFilterChange = (newFilters: FilterValues) => {
|
||||
console.log('Applied filters:', newFilters);
|
||||
setFilters(newFilters);
|
||||
setCurrentPage(1); // Reset to first page when filters change
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selectedRows: Message[]) => {
|
||||
const handleSelectionChange = (selectedRows: DraftMessage[]) => {
|
||||
setSelectedMessages(selectedRows);
|
||||
};
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
console.log('حذف پیامهای انتخاب شده:', selectedMessages.map(m => m.id));
|
||||
// اینجا منطق حذف را پیادهسازی کنید
|
||||
selectedMessages.forEach(message => {
|
||||
deleteMutation.mutate(message.id.toString());
|
||||
});
|
||||
setSelectedMessages([]);
|
||||
};
|
||||
|
||||
const handleEditSelected = () => {
|
||||
console.log('ویرایش پیامهای انتخاب شده:', selectedMessages.map(m => m.id));
|
||||
// اینجا منطق ویرایش را پیادهسازی کنید
|
||||
if (selectedMessages.length === 1) {
|
||||
// Navigate to edit page for single draft
|
||||
navigate(`/draft/edit/${selectedMessages[0].id}`);
|
||||
} else {
|
||||
console.log('ویرایش چندین پیشنویس انتخاب شده:', selectedMessages.map(m => m.id));
|
||||
}
|
||||
};
|
||||
|
||||
const getRowActions = (message: Message): RowActionItem[] => [
|
||||
const handleDeleteDraft = (messageId: number) => {
|
||||
deleteMutation.mutate(messageId.toString());
|
||||
};
|
||||
|
||||
const handleEditDraft = (messageId: number) => {
|
||||
navigate(`/draft/edit/${messageId}`);
|
||||
};
|
||||
|
||||
const getRowActions = (message: DraftMessage): RowActionItem[] => [
|
||||
{
|
||||
label: 'ویرایش',
|
||||
icon: <Edit size={16} color="black" />,
|
||||
onClick: () => console.log('ویرایش پیام', message.id),
|
||||
onClick: () => handleEditDraft(message.id),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
icon: <Trash size={16} color="red" />,
|
||||
onClick: () => console.log('حذف پیام', message.id),
|
||||
onClick: () => handleDeleteDraft(message.id),
|
||||
},
|
||||
];
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
setCurrentPage(page);
|
||||
};
|
||||
|
||||
const messages = draftData?.data?.draftsMail || [];
|
||||
const pager = draftData?.data?.pager;
|
||||
|
||||
return (
|
||||
<div className='mt-2 md:mt-4 px-2 md:px-0'>
|
||||
<h1 className="text-lg mb-4 md:mb-0">{t('draft.title')}</h1>
|
||||
|
||||
<Filters
|
||||
fields={[
|
||||
{ type: 'date', name: 'from_date', placeholder: t('draft.from_date') },
|
||||
{ type: 'date', name: 'to_date', placeholder: t('draft.to_date') },
|
||||
{ type: 'date', name: 'dateFrom', placeholder: t('draft.from_date') },
|
||||
{ type: 'date', name: 'dateTo', placeholder: t('draft.to_date') },
|
||||
{ type: 'input', name: 'search', placeholder: t('draft.search') }
|
||||
]}
|
||||
onChange={handleFilterChange}
|
||||
searchField="search"
|
||||
/>
|
||||
|
||||
<Table<Message>
|
||||
<Table<DraftMessage>
|
||||
columns={columns}
|
||||
data={messageData}
|
||||
data={messages}
|
||||
isLoading={isLoading}
|
||||
showHeader={false}
|
||||
actions={tableActions}
|
||||
selectedActions={selectedActions}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
onRowClick={(id) => console.log(`کلیک روی پیام با شناسه ${id}`)}
|
||||
onRowClick={(id) => navigate(`/draft/edit/${id}`)}
|
||||
noDataMessage={
|
||||
<div className="flex flex-col items-center py-6">
|
||||
<div className="flex flex-col items-center ">
|
||||
<InfoCircle size={32} className="text-gray-300 mb-2" />
|
||||
<div className="text-sm">هیچ پیشنویسی یافت نشد</div>
|
||||
</div>
|
||||
}
|
||||
selectable={true}
|
||||
rowActions={getRowActions}
|
||||
pagination={pager ? {
|
||||
totalPages: pager.totalPages,
|
||||
currentPage: pager.page,
|
||||
onPageChange: handlePageChange
|
||||
} : undefined}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import * as api from '../service/DraftService';
|
||||
import { MessageListQueryDto, DraftUpdateDto } from '../types/DraftTypes';
|
||||
|
||||
export const useGetDrafts = (query: MessageListQueryDto) => {
|
||||
return useQuery({
|
||||
queryKey: ['drafts', query],
|
||||
queryFn: () => api.getDrafts(query),
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetDraftDetail = (messageId: string, enabled: boolean = true) => {
|
||||
return useQuery({
|
||||
queryKey: ['draft', messageId],
|
||||
queryFn: () => api.getDraftDetail(messageId),
|
||||
enabled: !!messageId && enabled,
|
||||
staleTime: 1000 * 60 * 10, // 10 minutes
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteDraft = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (messageId: string) => api.deleteDraft(messageId),
|
||||
onSuccess: () => {
|
||||
// Invalidate drafts queries to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ['drafts'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useEditDraft = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ messageId, draftData }: { messageId: string; draftData: DraftUpdateDto }) =>
|
||||
api.editDraft(messageId, draftData),
|
||||
onSuccess: () => {
|
||||
// Invalidate drafts queries to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ['drafts'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
import axios from "../../../config/axios";
|
||||
import {
|
||||
MessageListQueryDto,
|
||||
InboxResponse,
|
||||
InboxMessage,
|
||||
DraftUpdateDto,
|
||||
} from "../types/DraftTypes";
|
||||
|
||||
export const getDrafts = async (
|
||||
query: MessageListQueryDto
|
||||
): Promise<InboxResponse> => {
|
||||
const { data } = await axios.get(`/email/messages/drafts`, { params: query });
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteDraft = async (messageId: string): Promise<void> => {
|
||||
const { data } = await axios.delete(`/email/messages/drafts/${messageId}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const editDraft = async (
|
||||
messageId: string,
|
||||
draftData: DraftUpdateDto
|
||||
): Promise<void> => {
|
||||
const { data } = await axios.put(
|
||||
`/email/messages/drafts/${messageId}`,
|
||||
draftData
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getDraftDetail = async (
|
||||
messageId: string
|
||||
): Promise<InboxMessage> => {
|
||||
const { data } = await axios.get(`/email/messages/drafts/${messageId}`);
|
||||
return data.data.message;
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
export interface EmailRecipientDto {
|
||||
name?: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
export interface EmailHeaderDto {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface EmailAttachmentDto {
|
||||
filename?: string;
|
||||
contentType?: string;
|
||||
encoding?: string;
|
||||
contentTransferEncoding?: string;
|
||||
contentDisposition?: "inline" | "attachment";
|
||||
content: string;
|
||||
cid?: string;
|
||||
}
|
||||
|
||||
export interface MessageListQueryDto {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
order?: string;
|
||||
search?: string;
|
||||
from?: string;
|
||||
subject?: string;
|
||||
dateFrom?: string;
|
||||
dateTo?: string;
|
||||
hasAttachment?: boolean;
|
||||
isRead?: boolean;
|
||||
isFlagged?: boolean;
|
||||
}
|
||||
|
||||
export interface DraftMessage extends Record<string, unknown> {
|
||||
id: number;
|
||||
mailbox: string;
|
||||
thread: string;
|
||||
from: {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
to: Array<{
|
||||
address: string;
|
||||
name: string;
|
||||
}>;
|
||||
cc: Array<{
|
||||
address: string;
|
||||
name: string;
|
||||
}>;
|
||||
bcc: Array<{
|
||||
address: string;
|
||||
name: string;
|
||||
}>;
|
||||
messageId: string;
|
||||
subject: string;
|
||||
date: string;
|
||||
idate: string;
|
||||
intro: string;
|
||||
attachments: boolean;
|
||||
attachmentsList: EmailAttachmentDto[];
|
||||
size: number;
|
||||
seen: boolean;
|
||||
deleted: boolean;
|
||||
flagged: boolean;
|
||||
draft: boolean;
|
||||
answered: boolean;
|
||||
forwarded: boolean;
|
||||
references: string[];
|
||||
contentType: {
|
||||
value: string;
|
||||
params: {
|
||||
boundary: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export type InboxMessage = DraftMessage;
|
||||
|
||||
export interface InboxPager {
|
||||
page: number;
|
||||
limit: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
prevPage: boolean;
|
||||
nextPage: boolean;
|
||||
}
|
||||
|
||||
export interface InboxResponse {
|
||||
statusCode: number;
|
||||
success: boolean;
|
||||
data: {
|
||||
pager: InboxPager;
|
||||
draftsMail: DraftMessage[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface DraftUpdateDto {
|
||||
from?: EmailRecipientDto;
|
||||
to?: EmailRecipientDto[];
|
||||
cc?: EmailRecipientDto[];
|
||||
bcc?: EmailRecipientDto[];
|
||||
subject?: string;
|
||||
text?: string;
|
||||
html?: string;
|
||||
attachments?: EmailAttachmentDto[];
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { FC } from 'react'
|
||||
|
||||
const SkeletonDetail: FC = () => {
|
||||
return (
|
||||
<div className='bg-white rounded-4xl p-8'>
|
||||
<div className='animate-pulse'>
|
||||
{/* Header Skeleton */}
|
||||
<div className='h-6 bg-gray-200 rounded w-48 mb-6'></div>
|
||||
|
||||
{/* Subject and Tags Section */}
|
||||
<div className='mt-6 flex xl:flex-row flex-col justify-between xl:items-center'>
|
||||
<div className='flex xl:flex-row flex-col-reverse gap-4 xl:items-center'>
|
||||
<div className='flex gap-1 items-center'>
|
||||
<div className='h-4 bg-gray-200 rounded w-12 hidden xl:block'></div>
|
||||
<div className='h-5 bg-gray-200 rounded w-40'></div>
|
||||
</div>
|
||||
<div className='flex gap-2'>
|
||||
<div className='h-6 xl:h-10 bg-gray-200 rounded-full w-20'></div>
|
||||
<div className='h-6 xl:h-10 bg-gray-200 rounded-full w-24'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-4 bg-gray-200 rounded w-24'></div>
|
||||
</div>
|
||||
|
||||
{/* Sender Info */}
|
||||
<div className='mt-6 flex gap-4 items-center'>
|
||||
<div className='size-10 bg-gray-200 rounded-full'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-32'></div>
|
||||
</div>
|
||||
|
||||
{/* Email Content */}
|
||||
<div className='xl:mt-8 mt-3 space-y-3'>
|
||||
<div className='h-4 bg-gray-200 rounded w-full'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-full'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-3/4'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-full'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-2/3'></div>
|
||||
</div>
|
||||
|
||||
{/* Attachments Section */}
|
||||
<div className='mt-10'>
|
||||
<div className='h-4 bg-gray-200 rounded w-20 mb-4'></div>
|
||||
<div className='flex border-b border-gray-200 pb-10 mt-4 flex-wrap gap-2.5 items-center'>
|
||||
<div className='h-10 bg-gray-200 rounded-full w-36'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className='flex mt-9 justify-end'>
|
||||
<div className='flex gap-5'>
|
||||
<div className='size-6 bg-gray-200 rounded'></div>
|
||||
<div className='flex gap-2 items-center border-r border-gray-200 pr-5'>
|
||||
<div className='w-[17px] h-[17px] bg-gray-200 rounded'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-12'></div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center border-r border-gray-200 pr-5'>
|
||||
<div className='w-[17px] h-[17px] bg-gray-200 rounded'></div>
|
||||
<div className='h-4 bg-gray-200 rounded w-16'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SkeletonDetail
|
||||
@@ -9,11 +9,12 @@ import AnswerIcon from '@/assets/images/answer.svg'
|
||||
import Header from './Components/Header'
|
||||
import ReactQuill from 'react-quill-new';
|
||||
import Select from '@/components/Select'
|
||||
import { useGetMessageDetail, useSendEmail, useSaveDraft } from './hooks/useEmailData'
|
||||
import { useGetMessageDetail, useSendEmail } from './hooks/useEmailData'
|
||||
import { useAuthStore } from '../auth/store/AuthStore'
|
||||
import { SendEmailDto } from './types/Types'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { formatDate } from '@/config/func'
|
||||
import SkeletonDetail from './Components/SkeletonDetail'
|
||||
|
||||
const DetailEmail: FC = () => {
|
||||
|
||||
@@ -27,7 +28,7 @@ const DetailEmail: FC = () => {
|
||||
// API hooks
|
||||
const { data: messageDetail, isLoading, error } = useGetMessageDetail(id || '', !!id)
|
||||
const sendEmailMutation = useSendEmail()
|
||||
const saveDraftMutation = useSaveDraft()
|
||||
// const saveDraftMutation = useSaveDraft()
|
||||
|
||||
const priorityOptions = [
|
||||
{ value: 'high', label: 'بالا' },
|
||||
@@ -80,21 +81,21 @@ const DetailEmail: FC = () => {
|
||||
return
|
||||
}
|
||||
|
||||
const draftData: SendEmailDto = {
|
||||
from: { address: userEmail || 'sender@example.com' },
|
||||
to: [{ address: messageDetail.from.address, name: messageDetail.from.name }],
|
||||
subject: `Re: ${messageDetail.subject}`,
|
||||
html: value,
|
||||
text: value.replace(/<[^>]*>/g, ''),
|
||||
isDraft: true,
|
||||
reference: {
|
||||
inReplyTo: messageDetail.messageId,
|
||||
originalMessageId: messageDetail.id.toString()
|
||||
}
|
||||
}
|
||||
// const draftData: SendEmailDto = {
|
||||
// from: { address: userEmail || 'sender@example.com' },
|
||||
// to: [{ address: messageDetail.from.address, name: messageDetail.from.name }],
|
||||
// subject: `Re: ${messageDetail.subject}`,
|
||||
// html: value,
|
||||
// text: value.replace(/<[^>]*>/g, ''),
|
||||
// isDraft: true,
|
||||
// reference: {
|
||||
// inReplyTo: messageDetail.messageId,
|
||||
// originalMessageId: messageDetail.id.toString()
|
||||
// }
|
||||
// }
|
||||
|
||||
try {
|
||||
await saveDraftMutation.mutateAsync(draftData)
|
||||
// await saveDraftMutation.mutateAsync(draftData)
|
||||
toast('پیشنویس ذخیره شد', 'success')
|
||||
} catch {
|
||||
toast('خطا در ذخیره پیشنویس', 'error')
|
||||
@@ -108,14 +109,7 @@ const DetailEmail: FC = () => {
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className='bg-white rounded-4xl p-8'>
|
||||
<div className='animate-pulse'>
|
||||
<div className='h-6 bg-gray-200 rounded mb-4'></div>
|
||||
<div className='h-4 bg-gray-200 rounded mb-2'></div>
|
||||
<div className='h-4 bg-gray-200 rounded mb-2'></div>
|
||||
<div className='h-20 bg-gray-200 rounded'></div>
|
||||
</div>
|
||||
</div>
|
||||
<SkeletonDetail />
|
||||
)
|
||||
}
|
||||
|
||||
@@ -247,7 +241,7 @@ const DetailEmail: FC = () => {
|
||||
className='!w-full sm:!w-fit px-6 md:px-10 bg-white text-black border border-primary order-2 sm:order-1'
|
||||
label={t('new_message.draft')}
|
||||
onClick={handleSaveDraft}
|
||||
loading={saveDraftMutation.isPending}
|
||||
// loading={saveDraftMutation.isPending}
|
||||
/>
|
||||
<Button
|
||||
className='w-full sm:w-fit px-6 md:px-10 order-1 sm:order-2'
|
||||
|
||||
@@ -16,7 +16,7 @@ const List: FC = () => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [filters, setFilters] = useState<FilterValues>({});
|
||||
|
||||
const { data: inboxData, isLoading, refetch } = useGetInbox({
|
||||
const { data: inboxData, isLoading, refetch, isFetching } = useGetInbox({
|
||||
page: currentPage,
|
||||
limit: 10,
|
||||
...filters
|
||||
@@ -57,7 +57,7 @@ const List: FC = () => {
|
||||
<Refresh2
|
||||
size={18}
|
||||
color='black'
|
||||
className="cursor-pointer"
|
||||
className={`cursor-pointer ${isFetching ? 'animate-spin-reverse' : ''}`}
|
||||
onClick={() => refetch()}
|
||||
/>
|
||||
<More size={18} color='black' className='rotate-90 cursor-pointer' />
|
||||
|
||||
@@ -14,6 +14,14 @@ export const useSaveDraft = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetDraft = (query: MessageListQueryDto) => {
|
||||
return useQuery({
|
||||
queryKey: ['draft', query],
|
||||
queryFn: () => api.getDraft(query),
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetInbox = (query: MessageListQueryDto) => {
|
||||
return useQuery({
|
||||
queryKey: ['inbox', query],
|
||||
|
||||
@@ -13,10 +13,14 @@ export const sendEmail = async (params: SendEmailDto) => {
|
||||
};
|
||||
|
||||
export const saveDraft = async (params: SendEmailDto) => {
|
||||
const { data } = await axios.post(`/email/draft`, {
|
||||
...params,
|
||||
isDraft: true,
|
||||
});
|
||||
const { data } = await axios.post(`/email/messages/drafts`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getDraft = async (
|
||||
query: MessageListQueryDto
|
||||
): Promise<InboxResponse> => {
|
||||
const { data } = await axios.get(`/email/messages/drafts`, { params: query });
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user