- {!item.read &&
}
-
{item.title}
+ title: 'title',
+ render: () => (
+
+ پیش نویس
)
},
{
- key: 'sender',
- title: 'فرستنده',
+ key: 'subject',
+ title: 'عنوان پیام',
render: (item) => (
-
{item.sender}
+
+ {item.subject || 'بدون موضوع'}
+
+ )
+ },
+ {
+ key: 'to',
+ title: 'گیرنده',
+ render: (item) => (
+
+ {item.to && item.to.length > 0
+ ? (item.to[0].name || item.to[0].address)
+ : 'بدون گیرنده'
+ }
+
)
},
{
@@ -48,87 +61,129 @@ const List: FC = () => {
title: 'تاریخ',
align: 'center',
render: (item) => (
-
{item.date}
+
{formatDate(item.date)}
)
},
];
const tableActions = (
-
+ refetch()}
+ />
);
const selectedActions = (
<>
-
handleDeleteSelected()} className="cursor-pointer" />
- handleEditSelected()} className="cursor-pointer" />
+ handleDeleteSelected()}
+ className="cursor-pointer"
+ />
+ 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: ,
- onClick: () => console.log('ویرایش پیام', message.id),
+ onClick: () => handleEditDraft(message.id),
},
{
label: 'حذف',
icon: ,
- 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 (
{t('draft.title')}
-
+
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={
-
+
}
selectable={true}
rowActions={getRowActions}
+ pagination={pager ? {
+ totalPages: pager.totalPages,
+ currentPage: pager.page,
+ onPageChange: handlePageChange
+ } : undefined}
/>
)
diff --git a/src/pages/draft/hooks/useDraftData.tsx b/src/pages/draft/hooks/useDraftData.tsx
new file mode 100644
index 0000000..36a3eac
--- /dev/null
+++ b/src/pages/draft/hooks/useDraftData.tsx
@@ -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'] });
+ },
+ });
+};
\ No newline at end of file
diff --git a/src/pages/draft/service/DraftService.ts b/src/pages/draft/service/DraftService.ts
new file mode 100644
index 0000000..31a1612
--- /dev/null
+++ b/src/pages/draft/service/DraftService.ts
@@ -0,0 +1,37 @@
+import axios from "../../../config/axios";
+import {
+ MessageListQueryDto,
+ InboxResponse,
+ InboxMessage,
+ DraftUpdateDto,
+} from "../types/DraftTypes";
+
+export const getDrafts = async (
+ query: MessageListQueryDto
+): Promise => {
+ const { data } = await axios.get(`/email/messages/drafts`, { params: query });
+ return data;
+};
+
+export const deleteDraft = async (messageId: string): Promise => {
+ const { data } = await axios.delete(`/email/messages/drafts/${messageId}`);
+ return data;
+};
+
+export const editDraft = async (
+ messageId: string,
+ draftData: DraftUpdateDto
+): Promise => {
+ const { data } = await axios.put(
+ `/email/messages/drafts/${messageId}`,
+ draftData
+ );
+ return data;
+};
+
+export const getDraftDetail = async (
+ messageId: string
+): Promise => {
+ const { data } = await axios.get(`/email/messages/drafts/${messageId}`);
+ return data.data.message;
+};
diff --git a/src/pages/draft/types/DraftTypes.ts b/src/pages/draft/types/DraftTypes.ts
new file mode 100644
index 0000000..b18b5a0
--- /dev/null
+++ b/src/pages/draft/types/DraftTypes.ts
@@ -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 {
+ 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[];
+}
diff --git a/src/pages/received/Components/SkeletonDetail.tsx b/src/pages/received/Components/SkeletonDetail.tsx
new file mode 100644
index 0000000..3c5e1e5
--- /dev/null
+++ b/src/pages/received/Components/SkeletonDetail.tsx
@@ -0,0 +1,67 @@
+import { FC } from 'react'
+
+const SkeletonDetail: FC = () => {
+ return (
+
+
+ {/* Header Skeleton */}
+
+
+ {/* Subject and Tags Section */}
+
+
+ {/* Sender Info */}
+
+
+ {/* Email Content */}
+
+
+ {/* Attachments Section */}
+
+
+ {/* Action Buttons */}
+
+
+
+ )
+}
+
+export default SkeletonDetail
\ No newline at end of file
diff --git a/src/pages/received/Detail.tsx b/src/pages/received/Detail.tsx
index e520ad8..bf11148 100644
--- a/src/pages/received/Detail.tsx
+++ b/src/pages/received/Detail.tsx
@@ -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 (
-
+
)
}
@@ -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}
/>