import PropTypes from 'prop-types'
import {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState
} from 'react'
import { Modal } from 'antd'
import ObjectInfo from '../../common/ObjectInfo'
import NewObjectForm from '../../common/NewObjectForm'
import WizardView from '../../common/WizardView'
import TemplatePreview from '../../common/TemplatePreview'
import ProgressDisplay from '../../common/ProgressDisplay'
import { ApiServerContext } from '../../context/ApiServerContext'
import { resolveEmailRecipients } from '../../utils/emailRecipients'
const progressByState = {
queued: 10,
rendering: 35,
sending: 70,
sent: 100,
error: 100
}
const EMPTY_RECIPIENT_CANDIDATES = []
const EMPTY_DEFAULT_VALUES = {}
const EmailWizardContent = ({
accounts,
defaultCandidates,
handleSubmit,
submitLoading,
objectData,
setObjectData,
form,
formValid,
onCreated
}) => {
const { fetchObject } = useContext(ApiServerContext)
const [candidates, setCandidates] = useState(defaultCandidates)
useEffect(() => {
if (defaultCandidates.length) {
setCandidates(defaultCandidates)
return
}
let cancelled = false
resolveEmailRecipients({
type: objectData?.objectType,
objectData: objectData?.object,
fetchObject
}).then((result) => {
if (!cancelled) setCandidates(result)
})
return () => {
cancelled = true
}
}, [
defaultCandidates,
fetchObject,
objectData?.object,
objectData?.objectType
])
useEffect(() => {
setObjectData((previous) => ({
...previous,
_recipientCandidates: candidates
}))
}, [candidates, setObjectData])
useEffect(() => {
const currentAccount = objectData?.emailAccount
const account =
accounts.find(
(entry) => entry._id === (currentAccount?._id || currentAccount)
) || accounts[0]
if (!account || objectData?.emailAccount) return
form.setFieldsValue({ emailAccount: account, fromEmail: account.fromEmail })
setObjectData((previous) => ({
...previous,
emailAccount: account,
fromEmail: account.fromEmail
}))
}, [accounts, form, objectData?.emailAccount, setObjectData])
useEffect(() => {
if (!candidates.length || objectData?.recipientEmail) return
const candidate = candidates[0]
const values = {
recipientEmail: candidate.email,
recipientType: candidate.recipientType,
recipient: candidate.recipient
}
form.setFieldsValue(values)
setObjectData((previous) => ({ ...previous, ...values }))
}, [candidates, form, objectData?.recipientEmail, setObjectData])
return (
)
}
]}
submitText='Send'
title='Send Email'
formValid={
formValid && Boolean(objectData?.recipientEmail) && accounts.length > 0
}
loading={submitLoading}
sideBarGrow
sideBar={
}
onSubmit={async () => {
const result = await handleSubmit()
if (result?._id) onCreated(result)
}}
/>
)
}
EmailWizardContent.propTypes = {
accounts: PropTypes.array.isRequired,
defaultCandidates: PropTypes.array.isRequired,
handleSubmit: PropTypes.func.isRequired,
submitLoading: PropTypes.bool,
objectData: PropTypes.object,
setObjectData: PropTypes.func.isRequired,
form: PropTypes.object.isRequired,
formValid: PropTypes.bool,
onCreated: PropTypes.func.isRequired
}
const NewEmailMessage = ({
onOk,
defaultValues = EMPTY_DEFAULT_VALUES,
recipientCandidates = EMPTY_RECIPIENT_CANDIDATES
}) => {
const {
fetchObject,
fetchObjects,
connected,
subscribeToObjectUpdates,
subscribeToObjectTypeUpdates
} = useContext(ApiServerContext)
const [accounts, setAccounts] = useState([])
const [sendingMessage, setSendingMessage] = useState(null)
const fetchObjectRef = useRef(fetchObject)
const fetchObjectsRef = useRef(fetchObjects)
const fetchedMessageIdRef = useRef(null)
fetchObjectRef.current = fetchObject
fetchObjectsRef.current = fetchObjects
const initialValues = useMemo(
() => ({ read: false, ...defaultValues }),
[defaultValues]
)
const loadAccounts = useCallback(async () => {
const result = await fetchObjectsRef.current('emailAccount', {
filter: { active: true },
limit: 100
})
setAccounts(Array.isArray(result?.data) ? result.data : [])
}, [])
useEffect(() => {
loadAccounts()
}, [loadAccounts])
useEffect(() => {
if (!connected) return undefined
return subscribeToObjectTypeUpdates(
'emailAccount',
{ active: true },
loadAccounts
)
}, [connected, loadAccounts, subscribeToObjectTypeUpdates])
useEffect(() => {
if (!connected) return undefined
const unsubscribes = accounts
.filter((account) => account?._id)
.map((account) =>
subscribeToObjectUpdates(
account._id.toLowerCase(),
'emailAccount',
(update) => {
const merged = { ...account, ...update }
setAccounts((previous) =>
merged.active === true
? previous.map((entry) =>
entry._id === account._id ? merged : entry
)
: previous.filter((entry) => entry._id !== account._id)
)
}
)
)
return () => unsubscribes.forEach((unsubscribe) => unsubscribe?.())
}, [accounts, connected, subscribeToObjectUpdates])
useEffect(() => {
const id = sendingMessage?._id
if (!id) return undefined
let cancelled = false
if (fetchedMessageIdRef.current !== id) {
fetchedMessageIdRef.current = id
fetchObjectRef.current(id, 'emailMessage').then((current) => {
if (!cancelled && current?._id) {
setSendingMessage((previous) => ({ ...previous, ...current }))
}
})
}
const unsubscribe =
connected === true
? subscribeToObjectUpdates(id.toLowerCase(), 'emailMessage', (update) =>
setSendingMessage((previous) => ({ ...previous, ...update }))
)
: undefined
return () => {
cancelled = true
unsubscribe?.()
}
}, [connected, sendingMessage?._id, subscribeToObjectUpdates])
useEffect(() => {
if (sendingMessage?.state?.type === 'sent') onOk?.(sendingMessage)
}, [onOk, sendingMessage])
return (
<>
{(formProps) => (
)}
setSendingMessage(null)}
maskClosable={false}
centered
destroyOnHidden
zIndex={2000}
width={360}
getContainer={() => document.body}
>
{sendingMessage?.state?.message ||
`Email ${sendingMessage?.state?.type || 'queued'}...`}
>
)
}
NewEmailMessage.propTypes = {
onOk: PropTypes.func,
defaultValues: PropTypes.object,
recipientCandidates: PropTypes.array
}
export default NewEmailMessage