feat: Add emoji reaction feature and improve reply formatting
- Add emoji-picker-react package - Create EmojiReaction component for quick emoji responses - Replace EmojiHappy icon with interactive EmojiReaction component - Implement emoji selection as structured reply messages - Improve reply HTML formatting with better styling and Persian date - Add contextual information to both emoji reactions and text replies - Update success messages to be more concise
This commit is contained in:
@@ -3,9 +3,9 @@ import { FC, useEffect, 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 { DocumentDownload } from 'iconsax-react'
|
||||
import Header from './Components/Header'
|
||||
import { useGetMessageDetail, useDownloadAttachment } from './hooks/useEmailData'
|
||||
import { useGetMessageDetail, useDownloadAttachment, useSendEmail } from './hooks/useEmailData'
|
||||
import { toast } from '@/components/Toast'
|
||||
import { formatDate, sanitizeEmailHTML, detectTextDirection } from '@/config/func'
|
||||
import SkeletonDetail from './Components/SkeletonDetail'
|
||||
@@ -13,17 +13,22 @@ import { useEmailActions } from '@/hooks/useEmailActions'
|
||||
import { MailboxEnum } from './enum/Enum'
|
||||
import Reply from '@/components/newMessage/Reply'
|
||||
import Forward from '@/components/newMessage/Forward'
|
||||
import EmojiReaction from '@/components/EmojiReaction'
|
||||
import { useAuthStore } from '@/pages/auth/store/AuthStore'
|
||||
import { SendEmailDto } from './types/Types'
|
||||
|
||||
const DetailEmail: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const emailActions = useEmailActions()
|
||||
const { email: userEmail } = useAuthStore()
|
||||
const { id, mailbox } = useParams<{ id: string, mailbox: string }>()
|
||||
const [activeAction, setActiveAction] = useState<'reply' | 'forward' | null>(null)
|
||||
|
||||
// API hooks
|
||||
const { data: messageDetail, isLoading, error } = useGetMessageDetail(id || '', mailbox || '')
|
||||
const downloadAttachmentMutation = useDownloadAttachment()
|
||||
const sendEmailMutation = useSendEmail()
|
||||
|
||||
const handleDownloadAttachment = async (attachmentId: string, filename: string) => {
|
||||
if (!id) {
|
||||
@@ -55,6 +60,61 @@ const DetailEmail: FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleEmojiSelect = async (emoji: string) => {
|
||||
if (!messageDetail) {
|
||||
toast('اطلاعات پیام یافت نشد', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
// Format date to Persian for reply context
|
||||
const originalDate = new Date(messageDetail.date)
|
||||
const persianDate = new Intl.DateTimeFormat('fa-IR', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}).format(originalDate)
|
||||
|
||||
const reactionHtml = `
|
||||
<div style="font-size: 24px; text-align: center; margin: 20px 0;">
|
||||
${emoji}
|
||||
</div>
|
||||
<br />
|
||||
<div dir="rtl" style="color: #666; font-size: 12px; border-top: 1px solid #ddd; padding-top: 10px;">
|
||||
در پاسخ به پیام ${persianDate} از ${messageDetail.from.name} <${messageDetail.from.address}>
|
||||
</div>
|
||||
`
|
||||
|
||||
const replyData: SendEmailDto = {
|
||||
from: { address: userEmail || 'sender@example.com' },
|
||||
to: [
|
||||
{
|
||||
address: messageDetail.from.address,
|
||||
name: messageDetail.from.name,
|
||||
},
|
||||
],
|
||||
replyTo: {
|
||||
name: messageDetail.from.name,
|
||||
address: messageDetail.from.address,
|
||||
},
|
||||
subject: messageDetail.subject.startsWith('Re:')
|
||||
? messageDetail.subject
|
||||
: `Re: ${messageDetail.subject}`,
|
||||
html: reactionHtml,
|
||||
text: `واکنش: ${emoji}\n\nدر پاسخ به پیام ${persianDate} از ${messageDetail.from.name}`,
|
||||
}
|
||||
|
||||
try {
|
||||
await sendEmailMutation.mutateAsync(replyData)
|
||||
toast('واکنش نشان داد', 'success')
|
||||
} catch (error) {
|
||||
console.error('Send error:', error)
|
||||
toast('خطا در نشان دادن واکنش', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// Mark message as seen when it's loaded and not already seen
|
||||
useEffect(() => {
|
||||
if (messageDetail && !messageDetail.seen && id) {
|
||||
@@ -163,7 +223,7 @@ const DetailEmail: FC = () => {
|
||||
{activeAction === null && (
|
||||
<div className='flex mt-9 justify-end'>
|
||||
<div className='flex gap-5 text-sm'>
|
||||
<EmojiHappy size={24} color='black' />
|
||||
<EmojiReaction onEmojiSelect={handleEmojiSelect} />
|
||||
|
||||
<Reply
|
||||
originalMessage={messageDetail}
|
||||
|
||||
Reference in New Issue
Block a user