import PropTypes from 'prop-types' import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' import { Button, Dropdown, Modal } from 'antd' import { ApiServerContext } from '../context/ApiServerContext' import { AuthContext } from '../context/AuthContext' import MailIcon from '../../Icons/MailIcon' import EmailTemplateIcon from '../../Icons/EmailTemplateIcon' import NewEmailMessage from '../Management/EmailMessages/NewEmailMessage' import { getDefaultEmailRecipient, resolveEmailRecipients } from '../utils/emailRecipients' const EmailSendButton = ({ type, objectData, disabled = false, ...buttonProps }) => { const { fetchObject, fetchObjects, connected, subscribeToObjectUpdates, subscribeToObjectTypeUpdates } = useContext(ApiServerContext) const { token } = useContext(AuthContext) const [templates, setTemplates] = useState([]) const [recipients, setRecipients] = useState([]) const [selectedTemplate, setSelectedTemplate] = useState(null) const [open, setOpen] = useState(false) const [loading, setLoading] = useState(false) const fetchObjectsRef = useRef(fetchObjects) const fetchObjectRef = useRef(fetchObject) fetchObjectsRef.current = fetchObjects fetchObjectRef.current = fetchObject const filter = useMemo( () => ({ objectType: type, global: false, active: true }), [type] ) const matches = useCallback( (template) => template?.objectType === type && template?.global === false && template?.active === true, [type] ) const loadTemplates = useCallback( async (silent = false) => { if (!type || token == null) return if (!silent) setLoading(true) try { const result = await fetchObjectsRef.current('emailTemplate', { filter, limit: 100 }) setTemplates(Array.isArray(result?.data) ? result.data : []) } finally { if (!silent) setLoading(false) } }, [filter, token, type] ) useEffect(() => { loadTemplates() }, [loadTemplates]) useEffect(() => { let cancelled = false setRecipients([]) resolveEmailRecipients({ type, objectData, fetchObject: (...args) => fetchObjectRef.current(...args) }).then((result) => { if (!cancelled) setRecipients(result) }) return () => { cancelled = true } }, [objectData, type]) useEffect(() => { if (!connected) return undefined return subscribeToObjectTypeUpdates('emailTemplate', filter, () => loadTemplates(true) ) }, [ connected, filter, loadTemplates, subscribeToObjectTypeUpdates ]) useEffect(() => { if (!connected) return undefined const unsubscribes = templates .filter((template) => template?._id) .map((template) => subscribeToObjectUpdates( template._id.toLowerCase(), 'emailTemplate', (update) => { setTemplates((previous) => { const merged = { ...template, ...update } if (!matches(merged)) { return previous.filter((entry) => entry._id !== template._id) } return previous.map((entry) => entry._id === template._id ? merged : entry ) }) } ) ) return () => unsubscribes.forEach((unsubscribe) => unsubscribe?.()) }, [connected, matches, subscribeToObjectUpdates, templates]) const menuItems = useMemo(() => { const byTag = new Map() const untagged = [] const makeItem = (template) => ({ key: template._id, label: template.name, icon: , onClick: () => { setSelectedTemplate(template) setOpen(true) } }) templates.forEach((template) => { const tags = Array.isArray(template.tags) ? template.tags.filter(Boolean) : [] if (!tags.length) { untagged.push(template) } else { tags.forEach((tag) => byTag.set(tag, [...(byTag.get(tag) || []), template])) } }) return [ ...untagged .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map(makeItem), ...[...byTag.entries()] .sort(([a], [b]) => a.localeCompare(b)) .map(([tag, taggedTemplates]) => ({ key: tag, label: tag, children: taggedTemplates .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map(makeItem) })) ] }, [templates]) const defaultRecipient = useMemo( () => getDefaultEmailRecipient(recipients), [recipients] ) const unavailable = disabled || loading || !templates.length || !recipients.length const title = !recipients.length ? 'No email recipients available for this object' : !templates.length ? 'No email templates available for this object type' : 'Send email' return ( <>