import React, { useState, useEffect } from 'react'; import { Mail, Newspaper, ClipboardList, UserPlus, Package, Shield, Calendar, FileText, Search, X, AlertTriangle, } from 'lucide-react'; import TemplatePreview from './TemplatePreview'; import { useTemplateCatalog } from '../extensions/templates'; import { applyFilters, Slot } from '../extensions/registry'; import { useFormStore } from '../store/useFormStore'; const categoryIcons = { all: FileText, contact: Mail, newsletter: Newspaper, survey: ClipboardList, register: UserPlus, wholesale: Package, warranty: Shield, booking: Calendar, }; export default function TemplateLoaderDrawer({ isOpen, onClose, onTemplateSelect, onApply, }) { const { templates: TEMPLATE_CONFIGURATIONS, categories, categoryMap: TEMPLATE_CATEGORY_MAP, preferred: PREFERRED_BY_CATEGORY } = useTemplateCatalog(); const settings = useFormStore((state) => state.settings); // An extension can limit the drawer to the templates that suit the open form (`templates.drawerScope` filter: // { match(template, key), categoryIds, label, Badge }). const scope = applyFilters('templates.drawerScope', null, { settings }) || null; const [search, setSearch] = useState(''); const [selectedCategory, setSelectedCategory] = useState('all'); const [selectedTemplate, setSelectedTemplate] = useState(null); const [showConfirmation, setShowConfirmation] = useState(false); const [isVisible, setIsVisible] = useState(false); const [isClosing, setIsClosing] = useState(false); const [adminBarHeight, setAdminBarHeight] = useState(0); // Measure WP admin bar useEffect(() => { const bar = document.getElementById('wpadminbar'); if (bar) { setAdminBarHeight(bar.offsetHeight); } const handleResize = () => { if (bar) setAdminBarHeight(bar.offsetHeight); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); const activeTemplates = Object.entries(TEMPLATE_CONFIGURATIONS).filter( ([key, t]) => !t.isDisabled && (!scope || scope.match(t, key)) ); const scopedCount = activeTemplates.length; const scopeCategoryIds = scope && Array.isArray(scope.categoryIds) ? scope.categoryIds : null; const displayedCategories = categories.filter((category) => { if (scopeCategoryIds && !scopeCategoryIds.includes(category.id)) return false; return category.id === 'all' || activeTemplates.some(([key]) => (TEMPLATE_CATEGORY_MAP[key] || 'all') === category.id); }); useEffect(() => { if (isOpen) { if (!displayedCategories.some((c) => c.id === selectedCategory)) { setSelectedCategory('all'); } setTimeout(() => { setIsVisible(true); setIsClosing(false); }, 50); } else { setIsClosing(true); setTimeout(() => { setIsVisible(false); }, 350); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, scope && scope.label]); useEffect(() => { const handleEscKey = (event) => { if (event.key === 'Escape' && isOpen) { handleClose(); } }; if (isOpen) { document.addEventListener('keydown', handleEscKey); } return () => { document.removeEventListener('keydown', handleEscKey); }; }, [isOpen]); const handleClose = () => { setIsClosing(true); setTimeout(() => { onClose(); setIsVisible(false); setSearch(''); setSelectedCategory('all'); setSelectedTemplate(null); setShowConfirmation(false); }, 350); }; const filteredTemplates = activeTemplates .filter(([key, template]) => { const templateCategory = TEMPLATE_CATEGORY_MAP[key] || 'all'; const categoryMatch = selectedCategory === 'all' || templateCategory === selectedCategory; const searchMatch = (template.name || '').toLowerCase().includes(search.toLowerCase()) || (template.description || '').toLowerCase().includes(search.toLowerCase()); return categoryMatch && searchMatch; }) .sort(([keyA], [keyB]) => { const order = PREFERRED_BY_CATEGORY[selectedCategory] || PREFERRED_BY_CATEGORY.all || []; const indexA = order.indexOf(keyA); const indexB = order.indexOf(keyB); if (indexA !== -1 && indexB !== -1) return indexA - indexB; if (indexA !== -1) return -1; if (indexB !== -1) return 1; return 0; }); const handleTemplateClick = (templateKey, template) => { setSelectedTemplate({ key: templateKey, ...template }); setShowConfirmation(true); }; const handleConfirmLoad = () => { if (selectedTemplate) { const targetHandler = onTemplateSelect || onApply; if (targetHandler) { targetHandler(selectedTemplate); } handleClose(); } }; if (!isVisible && !isOpen) { return null; } return ( <> {/* Backdrop */}
{/* Drawer */}{`Choose ${scope && scope.label ? `a ${scope.label} template` : 'a template'} to replace your current form ยท ${scopedCount} templates`}
Try adjusting your search or category filter
{template.description}
This action cannot be undone
Loading "{selectedTemplate.name}" will replace: