send , receive , detail email

This commit is contained in:
hamid zarghami
2025-07-09 17:00:21 +03:30
parent 72a6eaa156
commit 4258f57662
14 changed files with 926 additions and 97 deletions
+162 -4
View File
@@ -2,21 +2,37 @@ import { FC, useState, useEffect } from 'react'
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, useSaveDraft } from '../../pages/received/hooks/useEmailData'
import { SendEmailDto } from '../../pages/received/types/Types'
import Input from '../Input'
import ReactQuill from 'react-quill-new';
import Button from '../Button'
import Select from '../Select'
import UploadButton from '../UploadButton'
import { toast } from '../Toast'
const NewMessage: FC = () => {
const { t } = useTranslation('global')
const [value, setValue] = useState('');
const { setOpenNewMessage, openNewMessage } = useSharedStore()
const { email: userEmail } = useAuthStore()
const [isClosing, setIsClosing] = useState(false)
const [shouldRender, setShouldRender] = useState(false)
const [isOpening, setIsOpening] = useState(false)
// Form state
const [to, setTo] = useState('')
const [toEmails, setToEmails] = useState<string[]>([])
const [subject, setSubject] = useState('')
const [priority, setPriority] = useState('')
// API hooks
const sendEmailMutation = useSendEmail()
const saveDraftMutation = useSaveDraft()
useEffect(() => {
if (openNewMessage) {
setShouldRender(true)
@@ -42,6 +58,108 @@ const NewMessage: FC = () => {
setOpenNewMessage(false)
}, 300)
}
const parseEmailAddresses = (emails: string[]) => {
return emails
.filter(email => email.length > 0)
.map(email => ({ address: email }))
}
const isValidEmail = (email: string) => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
return emailRegex.test(email)
}
const handleToKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' && to.trim()) {
e.preventDefault()
const email = to.trim()
if (!isValidEmail(email)) {
toast('لطفا یک ایمیل معتبر وارد کنید', 'error')
return
}
if (toEmails.includes(email)) {
toast('این ایمیل قبلاً اضافه شده است', 'error')
return
}
setToEmails([...toEmails, email])
setTo('')
}
}
const removeEmail = (emailToRemove: string) => {
setToEmails(toEmails.filter(email => email !== emailToRemove))
}
const handleSend = async () => {
if (toEmails.length === 0 || !subject) {
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
}
try {
await sendEmailMutation.mutateAsync(emailData)
toast('ایمیل با موفقیت ارسال شد', 'success')
handleClose()
// Reset form
setTo('')
setToEmails([])
setSubject('')
setValue('')
setPriority('')
} catch {
toast('خطا در ارسال ایمیل', 'error')
}
}
const handleSaveDraft = async () => {
if (toEmails.length === 0 && !subject && !value) {
toast('حداقل یکی از فیلدها باید پر باشد', 'error')
return
}
const emailData: SendEmailDto = {
from: { address: userEmail || 'sender@example.com' },
to: parseEmailAddresses(toEmails),
subject,
html: value,
text: value.replace(/<[^>]*>/g, ''),
isDraft: true,
}
try {
await saveDraftMutation.mutateAsync(emailData)
toast('پیش‌نویس ذخیره شد', 'success')
handleClose()
// Reset form
setTo('')
setToEmails([])
setSubject('')
setValue('')
setPriority('')
} catch {
toast('خطا در ذخیره پیش‌نویس', 'error')
}
}
const priorityOptions = [
{ value: 'high', label: 'بالا' },
{ value: 'medium', label: 'متوسط' },
{ value: 'low', label: 'پایین' },
]
return (
<>
@@ -66,12 +184,44 @@ const NewMessage: FC = () => {
{/* Content */}
<div className='space-y-6 md:space-y-8'>
<Input
label={t('new_message.to')}
/>
<div>
<label className='text-sm'>
{t('new_message.to')}
</label>
<div className='w-full relative mt-1'>
<div className="w-full bg-white min-h-10 text-black flex flex-wrap items-center gap-1 px-4 py-2 text-xs rounded-xl border border-border">
{/* Email Tags */}
{toEmails.map((email, index) => (
<div
key={index}
className="flex items-center gap-1 bg-[#EBEDF5] text-xs h-7 rounded-full px-3"
>
<span>{email}</span>
<CloseCircle
size={16}
color='#D52903'
className='cursor-pointer'
onClick={() => removeEmail(email)}
/>
</div>
))}
{/* Input Field */}
<input
value={to}
onChange={(e) => setTo(e.target.value)}
onKeyDown={handleToKeyDown}
placeholder={toEmails.length === 0 ? "ایمیل را وارد کرده و Enter بزنید" : ""}
className="flex-1 min-w-32 bg-transparent outline-none"
/>
</div>
</div>
</div>
<Input
label={t('new_message.subject')}
value={subject}
onChange={(e) => setSubject(e.target.value)}
/>
<div>
@@ -101,19 +251,25 @@ const NewMessage: 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] min-w-[130px]'
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={handleSend}
loading={sendEmailMutation.isPending}
/>
</div>
</div>
@@ -121,6 +277,8 @@ const NewMessage: FC = () => {
</div>
</>
)}
</>
)
}