258 lines
11 KiB
TypeScript
258 lines
11 KiB
TypeScript
import { FC, useState, useEffect } from 'react'
|
|
import { CloseCircle } from 'iconsax-react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { useSharedStore } from '@/shared/store/sharedStore'
|
|
import Input from '@/components/Input'
|
|
import EmailInput from './EmailInput'
|
|
import EmailEditor from './EmailEditor'
|
|
import EmailAttachments from './EmailAttachments'
|
|
import EmailFormActions from './EmailFormActions'
|
|
import { useNewMessage } from './hooks/useNewMessage'
|
|
import Intelligense from '@/assets/images/intelligense.svg'
|
|
import { useGenerateEmail } from '@/pages/received/hooks/useEmailData'
|
|
import { clx } from '@/helpers/utils'
|
|
import { getIconColor } from '@/utils/colorUtils'
|
|
|
|
const NewMessage: FC = () => {
|
|
const { t } = useTranslation('global')
|
|
const { openNewMessage, setOpenNewMessage } = useSharedStore()
|
|
const [isClosing, setIsClosing] = useState(false)
|
|
const [shouldRender, setShouldRender] = useState(false)
|
|
const [isOpening, setIsOpening] = useState(false)
|
|
const [isIntelligenseOpen, setIsIntelligenseOpen] = useState(false)
|
|
const [prompt, setPrompt] = useState('')
|
|
const [showCcBcc, setShowCcBcc] = useState(false)
|
|
|
|
const {
|
|
// Form state
|
|
toEmails,
|
|
ccEmails,
|
|
bccEmails,
|
|
subject,
|
|
content,
|
|
priority,
|
|
attachments,
|
|
emailSuggestions,
|
|
|
|
// Loading states
|
|
isSending,
|
|
isSavingDraft,
|
|
|
|
// Form handlers
|
|
addEmail,
|
|
removeEmail,
|
|
addCcEmail,
|
|
removeCcEmail,
|
|
addBccEmail,
|
|
removeBccEmail,
|
|
setSubject,
|
|
setContent,
|
|
setPriority,
|
|
setAttachments,
|
|
|
|
// Search functions
|
|
searchEmailSuggestions,
|
|
|
|
// Actions
|
|
handleSend,
|
|
handleSaveDraft,
|
|
resetForm
|
|
} = useNewMessage()
|
|
const { mutate: generateEmail, isPending: isGeneratingEmail } = useGenerateEmail()
|
|
|
|
useEffect(() => {
|
|
if (openNewMessage) {
|
|
setShouldRender(true)
|
|
setIsClosing(false)
|
|
setIsOpening(true)
|
|
setTimeout(() => {
|
|
setIsOpening(false)
|
|
}, 50)
|
|
} else if (shouldRender) {
|
|
setIsClosing(true)
|
|
const timer = setTimeout(() => {
|
|
setShouldRender(false)
|
|
setIsClosing(false)
|
|
}, 300)
|
|
return () => clearTimeout(timer)
|
|
}
|
|
}, [openNewMessage, shouldRender])
|
|
|
|
const handleClose = () => {
|
|
setIsClosing(true)
|
|
setTimeout(() => {
|
|
setOpenNewMessage(false)
|
|
resetForm()
|
|
setShowCcBcc(false)
|
|
}, 300)
|
|
}
|
|
|
|
const handleSendWithClose = async () => {
|
|
const success = await handleSend()
|
|
if (success) {
|
|
handleClose()
|
|
}
|
|
}
|
|
|
|
const handleSaveDraftWithClose = async () => {
|
|
const success = await handleSaveDraft()
|
|
if (success) {
|
|
handleClose()
|
|
}
|
|
}
|
|
|
|
const handlePrompt = () => {
|
|
if (isIntelligenseOpen && prompt.length > 0) {
|
|
generateEmail({ prompt }, {
|
|
onSuccess: (data) => {
|
|
setContent(data?.data?.assistance?.suggestion?.content)
|
|
if (subject === '') {
|
|
setSubject(data?.data?.assistance?.suggestion?.subject)
|
|
}
|
|
}
|
|
})
|
|
} else {
|
|
setIsIntelligenseOpen(!isIntelligenseOpen)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{shouldRender && (
|
|
<>
|
|
<div
|
|
className={`fixed inset-0 xl:bg-transparent bg-black/50 z-[9998] transition-opacity duration-300 ${isClosing ? 'opacity-0' : isOpening ? 'opacity-0' : 'opacity-100'
|
|
}`}
|
|
onClick={handleClose}
|
|
/>
|
|
<div className={`fixed bottom-2 inset-x-2 md:bottom-4 md:inset-x-4 xl:left-4 xl:right-auto xl:bottom-4 bg-white dark:bg-[#252526] rounded-2xl md:rounded-3xl shadow-[0_0_20px_rgba(0,0,0,0.1)] z-[9999] p-4 md:p-6 xl:p-8 xl:w-[800px] max-h-[90vh] overflow-y-auto transition-transform duration-300 ease-out ${isClosing ? 'translate-y-[120%]' : isOpening ? 'translate-y-full' : 'translate-y-0'
|
|
}`}>
|
|
{/* Header */}
|
|
<div className='flex justify-between items-center mb-6 md:mb-8'>
|
|
<div className='text-lg'>
|
|
{t('new_message.title')}
|
|
</div>
|
|
<div onClick={handleClose} className='cursor-pointer p-1'>
|
|
<CloseCircle size={20} className='md:w-6 md:h-6' color={getIconColor('primary')} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div>
|
|
<div>
|
|
<label className='text-sm mb-1 block'>
|
|
{t('new_message.to')}
|
|
</label>
|
|
<div>
|
|
<EmailInput
|
|
toEmails={toEmails}
|
|
onAddEmail={addEmail}
|
|
onRemoveEmail={removeEmail}
|
|
suggestions={emailSuggestions}
|
|
onSearchSuggestions={searchEmailSuggestions}
|
|
showCcBccButton={true}
|
|
onCcBccClick={() => setShowCcBcc(!showCcBcc)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* CC/BCC Accordion */}
|
|
<div
|
|
className={clx(
|
|
'overflow-hidden transition-all duration-300 ease-in-out',
|
|
showCcBcc ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
|
|
)}
|
|
>
|
|
<div className='mt-4'>
|
|
<label className='text-sm mb-1 block'>
|
|
CC
|
|
</label>
|
|
<div>
|
|
<EmailInput
|
|
toEmails={ccEmails}
|
|
onAddEmail={addCcEmail}
|
|
onRemoveEmail={removeCcEmail}
|
|
suggestions={emailSuggestions}
|
|
onSearchSuggestions={searchEmailSuggestions}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className='mt-4'>
|
|
<label className='text-sm mb-1 block'>
|
|
BCC
|
|
</label>
|
|
<div>
|
|
<EmailInput
|
|
toEmails={bccEmails}
|
|
onAddEmail={addBccEmail}
|
|
onRemoveEmail={removeBccEmail}
|
|
suggestions={emailSuggestions}
|
|
onSearchSuggestions={searchEmailSuggestions}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className='flex gap-2 items-end mt-4'>
|
|
<div className='flex lg:flex-row flex-col flex-1 items-end gap-2'>
|
|
<Input
|
|
label={t('new_message.subject')}
|
|
value={subject}
|
|
onChange={(e) => setSubject(e.target.value)}
|
|
className='w-full'
|
|
/>
|
|
|
|
{
|
|
isIntelligenseOpen && (
|
|
<Input
|
|
placeholder={t('new_message.prompt')}
|
|
value={prompt}
|
|
onChange={(e) => setPrompt(e.target.value)}
|
|
className='w-full'
|
|
/>
|
|
)
|
|
}
|
|
</div>
|
|
|
|
<div onClick={isGeneratingEmail ? undefined : handlePrompt} className='border border-border rounded-xl h-10 px-2 flex items-center justify-center'>
|
|
<img src={Intelligense} alt='intelligense' className={clx(
|
|
'w-6',
|
|
isGeneratingEmail && 'animate-spin spin-in'
|
|
)} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className='mt-4'>
|
|
<EmailEditor
|
|
value={content}
|
|
onChange={setContent}
|
|
/>
|
|
</div>
|
|
|
|
<div className='mt-4'>
|
|
<EmailAttachments
|
|
attachments={attachments}
|
|
onAttachmentsChange={setAttachments}
|
|
/>
|
|
</div>
|
|
|
|
<div className='mt-4'>
|
|
<EmailFormActions
|
|
priority={priority}
|
|
onPriorityChange={setPriority}
|
|
onSend={handleSendWithClose}
|
|
onSaveDraft={handleSaveDraftWithClose}
|
|
isSending={isSending}
|
|
isSavingDraft={isSavingDraft}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default NewMessage |