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:
hamid zarghami
2025-07-22 13:15:42 +03:30
parent f844ff53d4
commit 013d4238c9
5 changed files with 176 additions and 10 deletions
+63 -3
View File
@@ -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} &lt;${messageDetail.from.address}&gt;
</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}