import PropTypes from 'prop-types' import { useState, useEffect, useContext, useCallback, useMemo, useRef } from 'react' // import { getModelByName } from '../../../database/ObjectModels' import DocumentPrinterIcon from '../../Icons/DocumentPrinterIcon' import { Button, Dropdown, Modal } from 'antd' import { ApiServerContext } from '../context/ApiServerContext' import DocumentTemplateIcon from '../../Icons/DocumentTemplateIcon' import NewDocumentJob from '../Management/DocumentJobs/NewDocumentJob' import { AuthContext } from '../context/AuthContext' const DocumentPrintButton = ({ type, objectData, disabled = false, ...buttonProps }) => { const { fetchObjects, connected, subscribeToObjectUpdates, subscribeToObjectTypeUpdates } = useContext(ApiServerContext) const fetchObjectsRef = useRef(fetchObjects) fetchObjectsRef.current = fetchObjects const [documentTemplates, setDocumentTemplates] = useState([]) const [currentDocumentTemplate, setCurrentDocumentTemplate] = useState(null) const [loading, setLoading] = useState(false) const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false) const subscribedIdsRef = useRef([]) const unsubscribesRef = useRef([]) const subscribeToObjectTypeUpdatesRef = useRef(null) const updateEventHandlerRef = useRef() const { token } = useContext(AuthContext) const subscriptionFilter = useMemo( () => ({ objectType: type, global: false, active: true }), [type] ) const templateMatchesFilter = useCallback( (template) => template?.objectType === type && template?.global === false && template?.active === true, [type] ) const loadDocumentTemplates = useCallback( async (silent = false) => { if (!type || token == null) return if (!silent) { setLoading(true) } try { const result = await fetchObjectsRef.current('documentTemplate', { filter: subscriptionFilter, limit: 100 // Get more templates to show in dropdown }) if (result && result.data) { setDocumentTemplates(result.data) } } catch (error) { console.error('Error fetching document templates:', error) } finally { if (!silent) { setLoading(false) } } }, [type, token, subscriptionFilter] ) const loadDocumentTemplatesRef = useRef(loadDocumentTemplates) loadDocumentTemplatesRef.current = loadDocumentTemplates // Stable key from objectData._id (excludes _isEditing so toggling edit mode doesn't trigger template reload) const objectKey = useMemo(() => { if (!objectData) return null return objectData._id ?? objectData.id ?? null }, [objectData]) // Fetch document templates when component mounts or objectData, type or token changes useEffect(() => { loadDocumentTemplates() }, [objectKey, token, type, loadDocumentTemplates]) const updateEventHandler = useCallback( (id, updatedData) => { setDocumentTemplates((prev) => { const existing = prev.find((template) => template._id === id) const merged = existing ? { ...existing, ...updatedData } : { _id: id, ...updatedData } if (!templateMatchesFilter(merged)) { return prev.filter((template) => template._id !== id) } if (existing) { return prev.map((template) => template._id === id ? merged : template ) } return [...prev, merged] }) }, [templateMatchesFilter] ) updateEventHandlerRef.current = updateEventHandler useEffect(() => { if (connected !== true) return const unsubscribe = subscribeToObjectTypeUpdates( 'documentTemplate', subscriptionFilter, () => loadDocumentTemplatesRef.current(true) ) subscribeToObjectTypeUpdatesRef.current = unsubscribe return () => { if (unsubscribe) unsubscribe() if (subscribeToObjectTypeUpdatesRef.current === unsubscribe) { subscribeToObjectTypeUpdatesRef.current = null } } }, [connected, subscriptionFilter, subscribeToObjectTypeUpdates]) useEffect(() => { if (connected !== true) return const templateIds = documentTemplates.map((template) => template._id).filter(Boolean) const newTemplateIds = templateIds.filter( (id) => !subscribedIdsRef.current.includes(id) ) newTemplateIds.forEach((itemId) => { const unsubscribe = subscribeToObjectUpdates( itemId?.toLowerCase(), 'documentTemplate', (updateData) => updateEventHandlerRef.current(itemId, updateData) ) subscribedIdsRef.current.push(itemId) if (unsubscribe) { unsubscribesRef.current.push(unsubscribe) } }) const templateIdsToUnsubscribe = subscribedIdsRef.current.filter( (id) => !templateIds.includes(id) ) templateIdsToUnsubscribe.forEach((itemId) => { const index = subscribedIdsRef.current.indexOf(itemId) if (index > -1) { subscribedIdsRef.current.splice(index, 1) const unsubscribe = unsubscribesRef.current[index] if (unsubscribe) { unsubscribe() } unsubscribesRef.current.splice(index, 1) } }) }, [documentTemplates, connected, subscribeToObjectUpdates]) useEffect(() => { return () => { unsubscribesRef.current.forEach((unsubscribe) => { if (unsubscribe) unsubscribe() }) unsubscribesRef.current = [] subscribedIdsRef.current = [] if (subscribeToObjectTypeUpdatesRef.current) { subscribeToObjectTypeUpdatesRef.current() subscribeToObjectTypeUpdatesRef.current = null } } }, []) // Handle template selection const handleTemplateSelect = (template) => { setCurrentDocumentTemplate(template) setNewDocumentJobOpen(true) // TODO: Implement the actual printing logic here // This could open a print dialog, navigate to a print page, etc. } // Group templates by tag for nested dropdown menu; untagged templates at root const menuItems = useMemo(() => { const templatesByTag = new Map() const untaggedTemplates = [] const toTemplateMenuItem = (template) => ({ key: template._id, label: template.name, icon: , onClick: () => handleTemplateSelect(template) }) for (const template of documentTemplates) { const templateTags = Array.isArray(template.tags) ? template.tags.filter(Boolean) : [] if (templateTags.length === 0) { untaggedTemplates.push(template) continue } for (const tag of templateTags) { const templates = templatesByTag.get(tag) ?? [] templates.push(template) templatesByTag.set(tag, templates) } } const taggedMenuItems = [...templatesByTag.keys()] .sort((a, b) => a.localeCompare(b)) .map((tag) => ({ key: tag, label: tag, children: templatesByTag .get(tag) .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map(toTemplateMenuItem) })) const rootUntaggedItems = untaggedTemplates .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map(toTemplateMenuItem) return [...rootUntaggedItems, ...taggedMenuItems] }, [documentTemplates]) // If no templates available, show disabled state if (documentTemplates.length === 0 && !loading) { return (