import React, { useState, useMemo, useEffect, useRef } from 'react';
import {
FileText,
Mail,
Newspaper,
ClipboardList,
UserPlus,
Package,
Shield,
Calendar,
Search,
X,
ArrowLeft,
Plus,
Layers,
Monitor,
Tablet,
Smartphone,
CheckCircle2,
ChevronLeft,
ChevronRight,
} from 'lucide-react';
import TemplatePreview from './TemplatePreview';
import { useTemplateCatalog } from '../extensions/templates';
import { applyFilters, Slot } from '../extensions/registry';
const categoryIcons = {
all: FileText,
contact: Mail,
newsletter: Newspaper,
survey: ClipboardList,
register: UserPlus,
wholesale: Package,
warranty: Shield,
booking: Calendar,
};
/**
* Template gallery. Templates come from the catalog (bundled + registerTemplates()). Extensions can add layout
* switcher entries (`templates.layouts` filter: [{ id, label, icon, match(template, key) }]) and card badges (slot
* `templates.cardBadges`, receives { template }).
*/
export default function TemplateGalleryScreen({
onBackToForms,
onCreateForm,
onCreateBlank,
}) {
const { templates: TEMPLATE_CONFIGURATIONS, categories, categoryMap: TEMPLATE_CATEGORY_MAP, preferred: PREFERRED_BY_CATEGORY } = useTemplateCatalog();
const layouts = applyFilters('templates.layouts', []) || [];
const [selectedLayoutType, setSelectedLayoutType] = useState('all'); // 'all' or a layout id
const [selectedCategory, setSelectedCategory] = useState('all');
const [searchQuery, setSearchQuery] = useState('');
// the reference builder select-template: 9 templates per page, back to page 1 when the filters change.
const TEMPLATES_PER_PAGE = 9;
const [currentPage, setCurrentPage] = useState(1);
const gridTopRef = useRef(null);
// Modals
const [previewTemplate, setPreviewTemplate] = useState(null);
const [previewDevice, setPreviewDevice] = useState('desktop'); // 'desktop' | 'tablet' | 'mobile'
const [createModalTemplate, setCreateModalTemplate] = useState(null);
const [formTitle, setFormTitle] = useState('');
const [formDescription, setFormDescription] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const activeTemplates = useMemo(() => {
return Object.entries(TEMPLATE_CONFIGURATIONS).filter(([, t]) => !t.isDisabled);
}, [TEMPLATE_CONFIGURATIONS]);
// Categories with at least one template ("All Templates" always).
const TEMPLATE_CATEGORIES = categories.filter((c) => c.id === 'all' || activeTemplates.some(([key]) => (TEMPLATE_CATEGORY_MAP[key] || 'all') === c.id));
const filteredTemplates = useMemo(() => {
return activeTemplates
.filter(([key, template]) => {
const layout = layouts.find((l) => l.id === selectedLayoutType);
if (layout && !layout.match(template, key)) return false;
const category = TEMPLATE_CATEGORY_MAP[key] || 'all';
const categoryMatch = selectedCategory === 'all' || category === selectedCategory;
const searchMatch =
(template.name || '').toLowerCase().includes(searchQuery.toLowerCase()) ||
(template.description || '').toLowerCase().includes(searchQuery.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;
});
}, [activeTemplates, selectedLayoutType, selectedCategory, searchQuery, layouts, TEMPLATE_CATEGORY_MAP, PREFERRED_BY_CATEGORY]);
useEffect(() => { setCurrentPage(1); }, [selectedLayoutType, selectedCategory, searchQuery]);
const totalPages = Math.max(1, Math.ceil(filteredTemplates.length / TEMPLATES_PER_PAGE));
const safePage = Math.min(currentPage, totalPages);
const firstIndex = (safePage - 1) * TEMPLATES_PER_PAGE;
const pageTemplates = filteredTemplates.slice(firstIndex, firstIndex + TEMPLATES_PER_PAGE);
const goToPage = (n) => {
setCurrentPage(Math.min(Math.max(1, n), totalPages));
if (gridTopRef.current && gridTopRef.current.scrollIntoView) gridTopRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
const pageNumbers = () => {
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, i) => i + 1);
const out = [1];
if (safePage > 3) out.push('...');
for (let n = Math.max(2, safePage - 1); n <= Math.min(totalPages - 1, safePage + 1); n++) out.push(n);
if (safePage < totalPages - 2) out.push('...');
out.push(totalPages);
return out;
};
const activeCategoryName = (TEMPLATE_CATEGORIES.find((c) => c.id === selectedCategory) || {}).name;
const handleOpenCreateModal = (key, template) => {
setCreateModalTemplate({ key, ...template });
setFormTitle(template.name || 'New Form');
setFormDescription(template.description || '');
};
const handleConfirmCreate = () => {
if (!formTitle.trim()) return;
setIsSubmitting(true);
try {
onCreateForm({
name: formTitle.trim(),
description: formDescription.trim(),
template: createModalTemplate,
});
} finally {
setIsSubmitting(false);
setCreateModalTemplate(null);
}
};
return (
{/* Top Header / Nav Bar */}
Select a Template
Choose from {activeTemplates.length} professionally designed templates or start fresh
{/* Main Body */}
{/* Controls: Search, Layout Filter, Categories */}
{/* Search Input */}
setSearchQuery(e.target.value)}
className="w-full pl-9 pr-8 py-2 border border-slate-200 rounded-xl text-xs focus:ring-2 focus:ring-gray-900 focus:border-gray-900 bg-slate-50/50"
/>
{searchQuery && (
)}
{/* Layout Switcher (extension layouts) */}
{layouts.length > 0 && (
{[{ id: 'all', label: 'All Types', icon: Layers, match: () => true }, ...layouts].map((layout) => {
const LayoutIcon = layout.icon || FileText;
const count = activeTemplates.filter(([key, t]) => layout.match(t, key)).length;
return (
);
})}
)}
{/* Category Tabs */}
{TEMPLATE_CATEGORIES.map((cat) => {
const isActive = selectedCategory === cat.id;
const IconComp = cat.Icon || categoryIcons[cat.id] || FileText;
return (
);
})}
{/* Results counter (the reference builder "Showing X-Y of N templates in …") */}
{filteredTemplates.length > 0 && (
Showing {firstIndex + 1}-{Math.min(firstIndex + TEMPLATES_PER_PAGE, filteredTemplates.length)} of {filteredTemplates.length} templates
{selectedCategory !== 'all' && activeCategoryName ? ` in ${activeCategoryName}` : ''}
)}
{/* Templates Grid */}
{filteredTemplates.length === 0 ? (
No templates found
Try adjusting your search query or choosing a different category filter.
) : (
{pageTemplates.map(([key, template]) => {
const catObj = TEMPLATE_CATEGORIES.find(
(c) => c.id === (TEMPLATE_CATEGORY_MAP[key] || 'all')
);
const CatIcon = catObj ? catObj.Icon || categoryIcons[catObj.id] || FileText : FileText;
return (
{/* Thumbnail / Preview */}
{/* Body Content */}
{/* Badges */}
{catObj?.name || 'General'}
{template.fields?.length || 0} fields
{template.name}
{template.description}
{/* Actions */}
);
})}
)}
{totalPages > 1 && (
)}
{/* Interactive Responsive Device Preview Modal */}
{previewTemplate && (
{/* Modal Top Bar */}
{previewTemplate.name}
{previewTemplate.fields?.length || 0} fields
{/* Device Viewport Selector */}
{/* Preview Viewport Canvas */}
)}
{/* Form Title & Create Confirmation Modal */}
{createModalTemplate && (
{/* Header */}
Name Your Form
Based on {createModalTemplate.name}
{/* Body */}
{/* Footer */}
)}
);
}