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