send , receive , detail email
This commit is contained in:
+145
-14
@@ -1,6 +1,7 @@
|
||||
import Button from '@/components/Button'
|
||||
import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import AvatarImage from '@/assets/images/avatar.svg'
|
||||
import { DocumentDownload, EmojiHappy } from 'iconsax-react'
|
||||
import ForwardIcon from '@/assets/images/forward.svg'
|
||||
@@ -8,12 +9,125 @@ 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 { useAuthStore } from '../auth/store/AuthStore'
|
||||
import { SendEmailDto } from './types/Types'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { formatDate } from '@/config/func'
|
||||
|
||||
const DetailEmail: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { id } = useParams<{ id: 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 sendEmailMutation = useSendEmail()
|
||||
const saveDraftMutation = useSaveDraft()
|
||||
|
||||
const priorityOptions = [
|
||||
{ value: 'high', label: 'بالا' },
|
||||
{ value: 'medium', label: 'متوسط' },
|
||||
{ value: 'low', label: 'پایین' },
|
||||
]
|
||||
|
||||
const handleSendReply = async () => {
|
||||
if (!value.trim()) {
|
||||
toast('لطفا متن پیام را وارد کنید', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
if (!messageDetail) {
|
||||
toast('اطلاعات پیام یافت نشد', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
const replyData: 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, ''),
|
||||
reference: {
|
||||
inReplyTo: messageDetail.messageId,
|
||||
originalMessageId: messageDetail.id.toString()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await sendEmailMutation.mutateAsync(replyData)
|
||||
toast('پاسخ با موفقیت ارسال شد', 'success')
|
||||
setShowAnswer(false)
|
||||
setValue('')
|
||||
setPriority('')
|
||||
} catch {
|
||||
toast('خطا در ارسال پاسخ', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveDraft = async () => {
|
||||
if (!value.trim()) {
|
||||
toast('متن پیام خالی است', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
if (!messageDetail) {
|
||||
toast('اطلاعات پیام یافت نشد', 'error')
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await saveDraftMutation.mutateAsync(draftData)
|
||||
toast('پیشنویس ذخیره شد', 'success')
|
||||
} catch {
|
||||
toast('خطا در ذخیره پیشنویس', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
const handleForward = () => {
|
||||
// TODO: Implement forward functionality
|
||||
toast('قابلیت ارسال به دیگران به زودی اضافه خواهد شد', 'info')
|
||||
}
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
if (error || !messageDetail) {
|
||||
return (
|
||||
<div className='bg-white rounded-4xl p-8'>
|
||||
<div className='text-center text-red-500'>
|
||||
خطا در بارگذاری پیام
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='bg-white rounded-4xl p-8'>
|
||||
@@ -23,7 +137,7 @@ const DetailEmail: FC = () => {
|
||||
<div className='flex xl:flex-row flex-col-reverse gap-4 xl:items-center'>
|
||||
<div className='flex gap-1 items-center'>
|
||||
<div className='font-extralight hidden xl:block'>{t('mail.subject')}</div>
|
||||
<div className='leading-7 text-sm'>لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ</div>
|
||||
<div className='leading-7 text-sm'>{messageDetail.subject || 'بدون موضوع'}</div>
|
||||
</div>
|
||||
<div className='flex gap-2'>
|
||||
<Button
|
||||
@@ -38,28 +152,41 @@ const DetailEmail: FC = () => {
|
||||
</div>
|
||||
|
||||
<div className='flex justify-end text-description xl:text-sm text-[10px]'>
|
||||
۵ اسفندماه ۱۴۰۳، ساعت ۱۲:۰۰
|
||||
{formatDate(messageDetail.date)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex gap-4 items-center'>
|
||||
<img src={AvatarImage} className='size-10' />
|
||||
<div className='text-sm'>مهرداد مظفری</div>
|
||||
<div className='text-sm'>{messageDetail.from.name || messageDetail.from.address}</div>
|
||||
</div>
|
||||
|
||||
<p className='xl:mt-8 mt-3 text-[13px] leading-7 font-light'>
|
||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد کتابهای زیادی در شصت و سه درصد گذشته حال و آیندهلورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد کتابهای زیادی در شصت و سه درصد گذشته حال و آینده
|
||||
</p>
|
||||
<div className='xl:mt-8 mt-3 text-[13px] leading-7 font-light'>
|
||||
{messageDetail.html && messageDetail.html.length > 0 ? (
|
||||
<div dangerouslySetInnerHTML={{ __html: messageDetail.html.join('') }} />
|
||||
) : (
|
||||
<p>{messageDetail.text || 'محتوای پیام'}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='mt-10 text-sm font-bold'>
|
||||
{t('mail.attachments')}
|
||||
</div>
|
||||
|
||||
<div className='flex border-b border-border pb-10 mt-4 flex-wrap gap-2.5 items-center'>
|
||||
<div className='bg-[#EBEDF5] text-sm flex gap-2 h-10 rounded-full items-center px-4'>
|
||||
<span>Lorem Ipsum.pdf</span>
|
||||
<DocumentDownload size={20} color='#0038FF' />
|
||||
</div>
|
||||
{messageDetail.attachments && messageDetail.attachments.length > 0 ? (
|
||||
messageDetail.attachments.map((attachment, index) => (
|
||||
<div key={index} className='bg-[#EBEDF5] text-sm flex gap-2 h-10 rounded-full items-center px-4'>
|
||||
<span>{attachment.filename || `attachment-${index + 1}`}</span>
|
||||
<DocumentDownload size={20} color='#0038FF' className='cursor-pointer' />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className='bg-[#EBEDF5] text-sm flex gap-2 h-10 rounded-full items-center px-4'>
|
||||
<span>Lorem Ipsum.pdf</span>
|
||||
<DocumentDownload size={20} color='#0038FF' />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{
|
||||
@@ -73,7 +200,7 @@ const DetailEmail: FC = () => {
|
||||
<div>{t('mail.answer')}</div>
|
||||
</div>
|
||||
|
||||
<div className='flex gap-2 cursor-pointer items-center border-r border-border pr-5'>
|
||||
<div onClick={handleForward} className='flex gap-2 cursor-pointer items-center border-r border-border pr-5'>
|
||||
<img src={ForwardIcon} className='w-[17px]' />
|
||||
<div>{t('mail.forward')}</div>
|
||||
</div>
|
||||
@@ -108,19 +235,25 @@ const DetailEmail: FC = () => {
|
||||
<div className='flex flex-col gap-4 sm:flex-row pt-4'>
|
||||
<div>
|
||||
<Select
|
||||
items={[]}
|
||||
items={priorityOptions}
|
||||
placeholder={t('new_message.select_priority')}
|
||||
className='xl:w-[190px]'
|
||||
value={priority}
|
||||
onChange={(e) => setPriority(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex-1 justify-end flex gap-3'>
|
||||
<Button
|
||||
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}
|
||||
/>
|
||||
<Button
|
||||
className='w-full sm:w-fit px-6 md:px-10 order-1 sm:order-2'
|
||||
label={t('new_message.send')}
|
||||
onClick={handleSendReply}
|
||||
loading={sendEmailMutation.isPending}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,8 +261,6 @@ const DetailEmail: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+56
-46
@@ -3,46 +3,43 @@ import { FC, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Table from '../../components/Table';
|
||||
import { ColumnType } from '../../components/types/TableTypes';
|
||||
import { InfoCircle, More, Refresh2, Trash, Edit, Archive, ArchiveSlash } from 'iconsax-react';
|
||||
import { InfoCircle, More, Refresh2, Trash, Edit, Archive } from 'iconsax-react';
|
||||
import { RowActionItem } from '../../components/RowActionsDropdown';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
interface Message extends Record<string, unknown> {
|
||||
id: string;
|
||||
title: string;
|
||||
sender: string;
|
||||
date: string;
|
||||
read: boolean;
|
||||
}
|
||||
import { useGetInbox } from './hooks/useEmailData';
|
||||
import { InboxMessage } from './types/Types';
|
||||
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: inboxData, isLoading, refetch } = useGetInbox({
|
||||
page: currentPage,
|
||||
limit: 10,
|
||||
...filters
|
||||
});
|
||||
|
||||
const columns: ColumnType<Message>[] = [
|
||||
const [selectedMessages, setSelectedMessages] = useState<InboxMessage[]>([]);
|
||||
|
||||
const columns: ColumnType<InboxMessage>[] = [
|
||||
{
|
||||
key: 'title',
|
||||
key: 'subject',
|
||||
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>
|
||||
{/* {!item.seen && <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.subject || 'بدون موضوع'}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'sender',
|
||||
key: 'from',
|
||||
title: 'فرستنده',
|
||||
render: (item) => (
|
||||
<span className="truncate">{item.sender}</span>
|
||||
<span className="truncate">{item.from.name || item.from.address}</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -50,14 +47,19 @@ 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"
|
||||
onClick={() => refetch()}
|
||||
/>
|
||||
<More size={18} color='black' className='rotate-90 cursor-pointer' />
|
||||
</div>
|
||||
);
|
||||
@@ -71,10 +73,11 @@ const List: FC = () => {
|
||||
);
|
||||
|
||||
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: InboxMessage[]) => {
|
||||
setSelectedMessages(selectedRows);
|
||||
};
|
||||
|
||||
@@ -93,16 +96,16 @@ const List: FC = () => {
|
||||
// اینجا منطق علامتگذاری را پیادهسازی کنید
|
||||
};
|
||||
|
||||
const getRowActions = (message: Message): RowActionItem[] => [
|
||||
const getRowActions = (message: InboxMessage): RowActionItem[] => [
|
||||
{
|
||||
label: 'خروج از آرشیو',
|
||||
icon: <ArchiveSlash size={16} color="black" />,
|
||||
onClick: () => console.log('خروج از آرشیو', message.id),
|
||||
label: message.seen ? 'علامتگذاری به عنوان خوانده نشده' : 'علامتگذاری به عنوان خوانده شده',
|
||||
icon: <Edit size={16} color="black" />,
|
||||
onClick: () => console.log('تغییر وضعیت خوانده شده', message.id),
|
||||
},
|
||||
{
|
||||
label: 'خوانده شده',
|
||||
icon: <Edit size={16} color="black" />,
|
||||
onClick: () => console.log('علامتگذاری به عنوان خوانده شده', message.id),
|
||||
label: 'بایگانی',
|
||||
icon: <Archive size={16} color="black" />,
|
||||
onClick: () => console.log('بایگانی پیام', message.id),
|
||||
},
|
||||
{
|
||||
label: 'حذف',
|
||||
@@ -111,22 +114,29 @@ const List: FC = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
setCurrentPage(page);
|
||||
};
|
||||
|
||||
const messages = inboxData?.data?.results || [];
|
||||
const pager = inboxData?.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('received.title')}</h1>
|
||||
|
||||
<Filters
|
||||
fields={[
|
||||
{ type: 'date', name: 'from_date', placeholder: t('received.from_date') },
|
||||
{ type: 'date', name: 'to_date', placeholder: t('received.to_date') },
|
||||
{ type: 'date', name: 'dateFrom', placeholder: t('received.from_date') },
|
||||
{ type: 'date', name: 'dateTo', placeholder: t('received.to_date') },
|
||||
{
|
||||
type: 'select',
|
||||
name: 'status',
|
||||
name: 'isRead',
|
||||
placeholder: t('received.all'),
|
||||
options: [
|
||||
{ value: 'all', label: t('received.all') },
|
||||
{ value: 'read', label: t('received.read') },
|
||||
{ value: 'unread', label: t('received.unread') }
|
||||
{ value: '', label: t('received.all') },
|
||||
{ value: 'true', label: t('received.read') },
|
||||
{ value: 'false', label: t('received.unread') }
|
||||
]
|
||||
},
|
||||
{ type: 'input', name: 'search', placeholder: t('received.search') }
|
||||
@@ -135,9 +145,9 @@ const List: FC = () => {
|
||||
searchField="search"
|
||||
/>
|
||||
|
||||
<Table<Message>
|
||||
<Table<InboxMessage>
|
||||
columns={columns}
|
||||
data={messageData}
|
||||
data={messages}
|
||||
isLoading={isLoading}
|
||||
showHeader={false}
|
||||
actions={tableActions}
|
||||
@@ -152,11 +162,11 @@ const List: FC = () => {
|
||||
}
|
||||
selectable={true}
|
||||
rowActions={getRowActions}
|
||||
pagination={{
|
||||
totalPages: 10,
|
||||
currentPage: 1,
|
||||
onPageChange: () => { }
|
||||
}}
|
||||
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/EmailService';
|
||||
import { SendEmailDto, MessageListQueryDto } from '../types/Types';
|
||||
|
||||
export const useSendEmail = () => {
|
||||
return useMutation({
|
||||
mutationFn: (variables: SendEmailDto) => api.sendEmail(variables),
|
||||
});
|
||||
};
|
||||
|
||||
export const useSaveDraft = () => {
|
||||
return useMutation({
|
||||
mutationFn: (variables: SendEmailDto) => api.saveDraft(variables),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetInbox = (query: MessageListQueryDto) => {
|
||||
return useQuery({
|
||||
queryKey: ['inbox', query],
|
||||
queryFn: () => api.getInbox(query),
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetMessageDetail = (messageId: string, enabled: boolean = true) => {
|
||||
return useQuery({
|
||||
queryKey: ['message', messageId],
|
||||
queryFn: () => api.getMessageDetail(messageId),
|
||||
enabled: !!messageId && enabled,
|
||||
staleTime: 1000 * 60 * 10, // 10 minutes
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteMessage = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (messageId: string) => api.deleteMessage(messageId),
|
||||
onSuccess: () => {
|
||||
// Invalidate inbox queries to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ['inbox'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import axios from "../../../config/axios";
|
||||
import {
|
||||
SendEmailDto,
|
||||
MessageListQueryDto,
|
||||
InboxResponse,
|
||||
MessageDetailResponse,
|
||||
MessageDetail,
|
||||
} from "../types/Types";
|
||||
|
||||
export const sendEmail = async (params: SendEmailDto) => {
|
||||
const { data } = await axios.post(`/email/send`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const saveDraft = async (params: SendEmailDto) => {
|
||||
const { data } = await axios.post(`/email/draft`, {
|
||||
...params,
|
||||
isDraft: true,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getInbox = async (
|
||||
query: MessageListQueryDto
|
||||
): Promise<InboxResponse> => {
|
||||
const { data } = await axios.get(`/email/messages/inbox`, { params: query });
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getMessageDetail = async (
|
||||
messageId: string
|
||||
): Promise<MessageDetail> => {
|
||||
const { data }: { data: MessageDetailResponse } = await axios.get(
|
||||
`/email/messages/inbox/${messageId}`
|
||||
);
|
||||
return data.data.message;
|
||||
};
|
||||
|
||||
export const deleteMessage = async (messageId: string): Promise<void> => {
|
||||
const { data } = await axios.delete(`/email/messages/inbox/${messageId}`);
|
||||
return data;
|
||||
};
|
||||
@@ -0,0 +1,288 @@
|
||||
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 DraftReferenceDto {
|
||||
mailbox: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface EmailEnvelopeDto {
|
||||
from: EmailRecipientDto;
|
||||
to: EmailRecipientDto[];
|
||||
}
|
||||
|
||||
export interface SendEmailDto {
|
||||
mailbox?: string;
|
||||
from: EmailRecipientDto;
|
||||
replyTo?: EmailRecipientDto;
|
||||
to: EmailRecipientDto[];
|
||||
cc?: EmailRecipientDto[];
|
||||
bcc?: EmailRecipientDto[];
|
||||
headers?: EmailHeaderDto[];
|
||||
subject?: string;
|
||||
text?: string;
|
||||
html?: string;
|
||||
attachments?: EmailAttachmentDto[];
|
||||
meta?: Record<string, unknown>;
|
||||
sess?: string;
|
||||
ip?: string;
|
||||
reference?: Record<string, unknown>;
|
||||
isDraft?: boolean;
|
||||
draft?: DraftReferenceDto;
|
||||
sendTime?: string;
|
||||
uploadOnly?: boolean;
|
||||
envelope?: EmailEnvelopeDto;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Updated types based on actual API response
|
||||
export interface InboxMessage 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 interface InboxPager {
|
||||
page: number;
|
||||
limit: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
prevPage: boolean;
|
||||
nextPage: boolean;
|
||||
}
|
||||
|
||||
export interface InboxResponse {
|
||||
statusCode: number;
|
||||
success: boolean;
|
||||
data: {
|
||||
pager: InboxPager;
|
||||
message: string;
|
||||
results: InboxMessage[];
|
||||
};
|
||||
}
|
||||
|
||||
// Legacy types (keeping for backward compatibility)
|
||||
export interface MessageDto {
|
||||
id: string;
|
||||
mailbox: string;
|
||||
uid: number;
|
||||
flags: string[];
|
||||
envelope: {
|
||||
date: string;
|
||||
subject: string;
|
||||
from: EmailRecipientDto[];
|
||||
to: EmailRecipientDto[];
|
||||
cc?: EmailRecipientDto[];
|
||||
bcc?: EmailRecipientDto[];
|
||||
messageId: string;
|
||||
inReplyTo?: string;
|
||||
references?: string[];
|
||||
};
|
||||
bodyStructure: Record<string, unknown>;
|
||||
source?: string;
|
||||
text?: string;
|
||||
html?: string;
|
||||
attachments?: EmailAttachmentDto[];
|
||||
headers?: EmailHeaderDto[];
|
||||
size: number;
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
export interface MessageListResponse {
|
||||
messages: MessageDto[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export interface UserMailboxMessageParamDto {
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
// New interface based on actual API response
|
||||
export interface MessageDetailResponse {
|
||||
statusCode: number;
|
||||
success: boolean;
|
||||
data: {
|
||||
message: {
|
||||
success: boolean;
|
||||
id: number;
|
||||
mailbox: string;
|
||||
thread: string;
|
||||
user: string;
|
||||
envelope: {
|
||||
from: string;
|
||||
rcpt: Array<{
|
||||
value: string;
|
||||
formatted: string;
|
||||
}>;
|
||||
};
|
||||
from: {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
to: Array<{
|
||||
address: string;
|
||||
name: string;
|
||||
}>;
|
||||
subject: string;
|
||||
messageId: string;
|
||||
date: string;
|
||||
idate: string;
|
||||
size: number;
|
||||
seen: boolean;
|
||||
deleted: boolean;
|
||||
flagged: boolean;
|
||||
draft: boolean;
|
||||
answered: boolean;
|
||||
forwarded: boolean;
|
||||
html: string[];
|
||||
text: string;
|
||||
attachments: EmailAttachmentDto[];
|
||||
references: string[];
|
||||
metaData: Record<string, unknown>;
|
||||
verificationResults: {
|
||||
tls: {
|
||||
name: string;
|
||||
standardName: string;
|
||||
version: string;
|
||||
};
|
||||
spf: string;
|
||||
dkim: string;
|
||||
arc: boolean;
|
||||
bimi: boolean;
|
||||
};
|
||||
contentType: {
|
||||
value: string;
|
||||
params: {
|
||||
boundary: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageDetail {
|
||||
success: boolean;
|
||||
id: number;
|
||||
mailbox: string;
|
||||
thread: string;
|
||||
user: string;
|
||||
envelope: {
|
||||
from: string;
|
||||
rcpt: Array<{
|
||||
value: string;
|
||||
formatted: string;
|
||||
}>;
|
||||
};
|
||||
from: {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
to: Array<{
|
||||
address: string;
|
||||
name: string;
|
||||
}>;
|
||||
subject: string;
|
||||
messageId: string;
|
||||
date: string;
|
||||
idate: string;
|
||||
size: number;
|
||||
seen: boolean;
|
||||
deleted: boolean;
|
||||
flagged: boolean;
|
||||
draft: boolean;
|
||||
answered: boolean;
|
||||
forwarded: boolean;
|
||||
html: string[];
|
||||
text: string;
|
||||
attachments: EmailAttachmentDto[];
|
||||
references: string[];
|
||||
metaData: Record<string, unknown>;
|
||||
verificationResults: {
|
||||
tls: {
|
||||
name: string;
|
||||
standardName: string;
|
||||
version: string;
|
||||
};
|
||||
spf: string;
|
||||
dkim: string;
|
||||
arc: boolean;
|
||||
bimi: boolean;
|
||||
};
|
||||
contentType: {
|
||||
value: string;
|
||||
params: {
|
||||
boundary: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user