@contentgrowth/content-emailing 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frontend/index.cjs +7 -2
- package/dist/frontend/index.cjs.map +1 -1
- package/dist/frontend/index.js +10 -5
- package/dist/frontend/index.js.map +1 -1
- package/dist/index.cjs +7 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/frontend/index.cjs
CHANGED
|
@@ -199,6 +199,11 @@ var TemplateTester = ({
|
|
|
199
199
|
const [detectedVariables, setDetectedVariables] = (0, import_react2.useState)([]);
|
|
200
200
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
201
201
|
const [success, setSuccess] = (0, import_react2.useState)(null);
|
|
202
|
+
const defaultValuesRef = (0, import_react2.useRef)(defaultValues);
|
|
203
|
+
const defaultValuesJson = JSON.stringify(defaultValues);
|
|
204
|
+
(0, import_react2.useEffect)(() => {
|
|
205
|
+
defaultValuesRef.current = defaultValues;
|
|
206
|
+
}, [defaultValuesJson]);
|
|
202
207
|
(0, import_react2.useEffect)(() => {
|
|
203
208
|
const regex = /\{\{(\w+)\}\}/g;
|
|
204
209
|
const subjectVars = Array.from(template.subject_template.matchAll(regex)).map((m) => m[1]);
|
|
@@ -206,7 +211,7 @@ var TemplateTester = ({
|
|
|
206
211
|
const uniqueVars = Array.from(/* @__PURE__ */ new Set([...subjectVars, ...bodyVars]));
|
|
207
212
|
setDetectedVariables(uniqueVars);
|
|
208
213
|
const initialValues = {};
|
|
209
|
-
const defaults =
|
|
214
|
+
const defaults = defaultValuesRef.current.variables || {};
|
|
210
215
|
uniqueVars.forEach((v) => {
|
|
211
216
|
if (defaults[v]) {
|
|
212
217
|
initialValues[v] = defaults[v];
|
|
@@ -217,7 +222,7 @@ var TemplateTester = ({
|
|
|
217
222
|
}
|
|
218
223
|
});
|
|
219
224
|
setVariables(initialValues);
|
|
220
|
-
}, [template,
|
|
225
|
+
}, [template.template_id, template.subject_template, template.body_markdown, defaultValuesJson]);
|
|
221
226
|
const handleSubmit = async (e) => {
|
|
222
227
|
e.preventDefault();
|
|
223
228
|
setError(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/frontend/index.ts","../../src/frontend/TemplateManager.tsx","../../src/frontend/TemplateEditor.tsx","../../src/frontend/TemplateTester.tsx","../../src/frontend/EmailSettings.tsx","../../src/frontend/EmailLogsPanel.tsx"],"sourcesContent":["\nexport { TemplateManager } from './TemplateManager';\nexport type { TemplateManagerProps, EmailTemplate } from './TemplateManager';\n\nexport { TemplateEditor } from './TemplateEditor';\nexport type { TemplateEditorProps, TemplateFormData } from './TemplateEditor';\n\nexport { TemplateTester } from './TemplateTester';\nexport type { TemplateTesterProps, TestEmailData } from './TemplateTester';\n\nexport { EmailSettings } from './EmailSettings';\nexport type { EmailSettingsProps, EmailSettingsData } from './EmailSettings';\n\nexport { EmailLogsPanel } from './EmailLogsPanel';\nexport type { EmailLogsPanelProps } from './EmailLogsPanel';\n","import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { marked } from 'marked';\nimport { TemplateEditor, TemplateFormData } from './TemplateEditor';\nimport { TemplateTester, TestEmailData } from './TemplateTester';\n\nexport interface EmailTemplate {\n template_id: string;\n template_name: string;\n template_type: string;\n subject_template: string;\n body_markdown: string;\n variables?: string | null;\n description: string | null;\n is_active: number | boolean;\n created_at?: number | null;\n updated_at?: number | null;\n}\n\nexport interface TemplateManagerProps {\n /** Fetch all templates - returns promise with template array */\n onLoadTemplates: () => Promise<EmailTemplate[]>;\n /** Save a template (create or update) */\n onSaveTemplate: (data: TemplateFormData) => Promise<void>;\n /** Delete a template by ID */\n onDeleteTemplate?: (id: string) => Promise<void>;\n /** Send a test email */\n onSendTestEmail?: (data: TestEmailData) => Promise<void>;\n /** Page title */\n title?: string;\n /** Page description */\n description?: string;\n /** Template types for filtering and editor */\n templateTypes?: string[];\n /** Default values for tester */\n defaultTestValues?: {\n to?: string;\n variables?: Record<string, string>;\n };\n}\n\nconst TYPE_COLORS: Record<string, { bg: string; text: string }> = {\n 'auth': { bg: 'bg-blue-100', text: 'text-blue-800' },\n 'notification': { bg: 'bg-purple-100', text: 'text-purple-800' },\n 'marketing': { bg: 'bg-green-100', text: 'text-green-800' },\n 'system': { bg: 'bg-gray-100', text: 'text-gray-800' },\n 'invitation': { bg: 'bg-orange-100', text: 'text-orange-800' },\n 'verification': { bg: 'bg-cyan-100', text: 'text-cyan-800' },\n 'default': { bg: 'bg-gray-100', text: 'text-gray-600' }\n};\n\nconst normalizeNewlines = (text: string): string => {\n return text?.replace(/\\\\n/g, '\\n') || '';\n};\n\nexport const TemplateManager: React.FC<TemplateManagerProps> = ({\n onLoadTemplates,\n onSaveTemplate,\n onDeleteTemplate,\n onSendTestEmail,\n title = 'Email Templates',\n description = 'Manage system email templates',\n templateTypes,\n defaultTestValues\n}) => {\n // Keep props ref for passing down if needed, but we destructured\n const props = { defaultTestValues };\n const [templates, setTemplates] = useState<EmailTemplate[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [filterType, setFilterType] = useState<string>('all');\n\n // Modal states\n const [previewTemplate, setPreviewTemplate] = useState<EmailTemplate | null>(null);\n const [editingTemplate, setEditingTemplate] = useState<EmailTemplate | null>(null);\n const [testingTemplate, setTestingTemplate] = useState<EmailTemplate | null>(null);\n const [showEditor, setShowEditor] = useState(false);\n const [showTester, setShowTester] = useState(false);\n const [saving, setSaving] = useState(false);\n\n // Delete confirmation\n const [deleteConfirm, setDeleteConfirm] = useState<string | null>(null);\n\n const loadTemplates = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const data = await onLoadTemplates();\n setTemplates(data);\n } catch (e: any) {\n setError(e.message || 'Failed to load templates');\n } finally {\n setLoading(false);\n }\n }, [onLoadTemplates]);\n\n useEffect(() => {\n loadTemplates();\n }, [loadTemplates]);\n\n const openCreate = () => {\n setEditingTemplate(null);\n setShowEditor(true);\n };\n\n const openPreview = (template: EmailTemplate) => {\n setPreviewTemplate(template);\n };\n\n const openEdit = (template: EmailTemplate) => {\n setPreviewTemplate(null);\n setEditingTemplate(template);\n setShowEditor(true);\n };\n\n const openTester = (template: EmailTemplate) => {\n setTestingTemplate(template);\n setShowTester(true);\n };\n\n const handleSave = async (data: TemplateFormData) => {\n setSaving(true);\n try {\n await onSaveTemplate(data);\n setShowEditor(false);\n await loadTemplates();\n } catch (e: any) {\n // Re-throw so consumer can show toast\n setSaving(false);\n throw e;\n }\n setSaving(false);\n };\n\n const handleDelete = async (id: string) => {\n if (!onDeleteTemplate) return;\n try {\n await onDeleteTemplate(id);\n setDeleteConfirm(null);\n await loadTemplates();\n } catch (e: any) {\n setError(e.message || 'Failed to delete template');\n }\n };\n\n const handleTest = async (data: TestEmailData) => {\n if (!onSendTestEmail) return;\n setSaving(true);\n try {\n await onSendTestEmail(data);\n } finally {\n setSaving(false);\n }\n };\n\n const getTypeColor = (type: string) => TYPE_COLORS[type] || TYPE_COLORS['default'];\n\n const uniqueTypes = ['all', ...new Set(templates.map(t => t.template_type))];\n const filteredTemplates = filterType === 'all'\n ? templates\n : templates.filter(t => t.template_type === filterType);\n\n const formatDate = (timestamp: number | null | undefined) => {\n if (!timestamp) return 'N/A';\n return new Date(timestamp * 1000).toLocaleDateString('en-US', {\n month: 'short', day: 'numeric', year: 'numeric'\n });\n };\n\n // Preview markdown render\n const previewBody = useMemo(() => {\n if (!previewTemplate?.body_markdown) return '';\n let md = normalizeNewlines(previewTemplate.body_markdown);\n md = md.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded text-sm\">{{$1}}</span>');\n return marked.parse(md) as string;\n }, [previewTemplate]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\"></div>\n </div>\n );\n }\n\n return (\n <div className=\"template-manager\">\n {/* Header */}\n <div className=\"flex justify-between items-center mb-6\">\n <div>\n <h1 className=\"text-2xl font-bold text-gray-900\">{title}</h1>\n <p className=\"text-sm text-gray-500 mt-1\">{description}</p>\n </div>\n <button\n onClick={openCreate}\n className=\"px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center gap-2 shadow-sm\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n Create Template\n </button>\n </div>\n\n {/* Error Banner */}\n {error && (\n <div className=\"mb-4 p-3 rounded-lg bg-red-50 text-red-800 border border-red-200\">\n {error}\n <button onClick={() => setError(null)} className=\"ml-2 underline\">Dismiss</button>\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex gap-4 mb-6\">\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-gray-900\">{templates.length}</div>\n <div className=\"text-sm text-gray-500\">Total</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-green-600\">\n {templates.filter(t => t.is_active).length}\n </div>\n <div className=\"text-sm text-gray-500\">Active</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-yellow-600\">\n {templates.filter(t => !t.is_active).length}\n </div>\n <div className=\"text-sm text-gray-500\">Inactive</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-blue-600\">\n {new Set(templates.map(t => t.template_type)).size}\n </div>\n <div className=\"text-sm text-gray-500\">Types</div>\n </div>\n </div>\n\n {/* Filter Tabs */}\n <div className=\"flex gap-2 mb-6 border-b border-gray-200 pb-3 flex-wrap\">\n {uniqueTypes.map(type => (\n <button\n key={type}\n onClick={() => setFilterType(type)}\n className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors ${filterType === type\n ? 'bg-blue-600 text-white'\n : 'bg-gray-100 text-gray-600 hover:bg-gray-200'\n }`}\n >\n {type.charAt(0).toUpperCase() + type.slice(1)}\n </button>\n ))}\n </div>\n\n {/* Templates Grid */}\n {filteredTemplates.length === 0 ? (\n <div className=\"text-center py-16 bg-gray-50 rounded-lg border-2 border-dashed border-gray-200\">\n <svg className=\"mx-auto h-12 w-12 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\" />\n </svg>\n <h3 className=\"mt-4 text-lg font-medium text-gray-900\">No templates found</h3>\n <p className=\"mt-2 text-sm text-gray-500\">\n {filterType === 'all' ? 'Create your first template.' : `No \"${filterType}\" templates.`}\n </p>\n <button onClick={openCreate} className=\"mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg text-sm\">\n Create Template\n </button>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template) => {\n const typeColor = getTypeColor(template.template_type);\n return (\n <div\n key={template.template_id}\n className=\"bg-white rounded-lg border border-gray-200 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer overflow-hidden flex flex-col h-full\"\n onClick={() => openPreview(template)}\n >\n <div className=\"p-5 flex-1 flex flex-col\">\n <div className=\"flex items-start justify-between mb-3\">\n <span className={`px-2 py-1 text-xs font-medium rounded ${typeColor.bg} ${typeColor.text}`}>\n {template.template_type}\n </span>\n <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${template.is_active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-600'\n }`}>\n {template.is_active ? '● Active' : '○ Inactive'}\n </span>\n </div>\n <h3 className=\"font-semibold text-gray-900 mb-1\">{template.template_name}</h3>\n <p className=\"text-sm text-gray-500 flex-1 line-clamp-2\">\n {template.description || 'No description'}\n </p>\n <div className=\"text-xs text-gray-400 border-t border-gray-100 pt-3 mt-3 truncate\">\n 📧 {template.subject_template}\n </div>\n </div>\n <div className=\"bg-gray-50 px-5 py-3 flex justify-between items-center border-t border-gray-100\">\n <span className=\"text-xs text-gray-500\">\n {formatDate(template.updated_at)}\n </span>\n <div className=\"flex gap-2\">\n <button\n onClick={(e) => { e.stopPropagation(); openEdit(template); }}\n className=\"p-1.5 text-blue-600 hover:bg-blue-50 rounded\"\n title=\"Edit\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n </button>\n {onSendTestEmail && (\n <button\n onClick={(e) => { e.stopPropagation(); openTester(template); }}\n className=\"p-1.5 text-purple-600 hover:bg-purple-50 rounded\"\n title=\"Send Test Email\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n </button>\n )}\n {onDeleteTemplate && (\n <button\n onClick={(e) => { e.stopPropagation(); setDeleteConfirm(template.template_id); }}\n className=\"p-1.5 text-red-600 hover:bg-red-50 rounded\"\n title=\"Delete\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Preview Modal */}\n {previewTemplate && (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col\">\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <div>\n <h2 className=\"text-lg font-semibold text-gray-900\">{previewTemplate.template_name}</h2>\n <p className=\"text-sm text-gray-500\">{previewTemplate.template_type} • {previewTemplate.is_active ? 'Active' : 'Inactive'}</p>\n </div>\n <button onClick={() => setPreviewTemplate(null)} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-6 space-y-4\">\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Subject</label>\n <div className=\"p-3 bg-gray-50 rounded-lg border border-gray-200 font-mono text-sm\">\n {previewTemplate.subject_template}\n </div>\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Email Body</label>\n <div\n className=\"p-4 bg-white rounded-lg border border-gray-200 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{ __html: previewBody }}\n />\n </div>\n\n {previewTemplate.description && (\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Description</label>\n <p className=\"text-gray-600 text-sm\">{previewTemplate.description}</p>\n </div>\n )}\n </div>\n\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-end gap-3 bg-gray-50\">\n <button\n onClick={() => setPreviewTemplate(null)}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Close\n </button>\n <button\n onClick={() => openEdit(previewTemplate)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 flex items-center gap-2\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n Edit Template\n </button>\n {onSendTestEmail && (\n <button\n onClick={() => openTester(previewTemplate)}\n className=\"px-4 py-2 text-sm font-medium text-purple-700 bg-purple-100 rounded-lg hover:bg-purple-200 flex items-center gap-2\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n Test\n </button>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Editor Modal */}\n {showEditor && (\n <TemplateEditor\n initialData={editingTemplate ? {\n template_id: editingTemplate.template_id,\n template_name: editingTemplate.template_name,\n template_type: editingTemplate.template_type,\n subject_template: editingTemplate.subject_template,\n body_markdown: editingTemplate.body_markdown,\n description: editingTemplate.description || '',\n is_active: !!editingTemplate.is_active\n } : null}\n onSave={handleSave}\n onCancel={() => setShowEditor(false)}\n templateTypes={templateTypes}\n saving={saving}\n />\n )}\n\n {/* Tester Modal */}\n {showTester && testingTemplate && (\n <TemplateTester\n template={testingTemplate}\n onSendTest={handleTest}\n onCancel={() => setShowTester(false)}\n sending={saving}\n defaultValues={props.defaultTestValues}\n />\n )}\n\n {/* Delete Confirmation */}\n {deleteConfirm && (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-lg shadow-xl max-w-sm w-full p-6\">\n <h3 className=\"text-lg font-semibold mb-2\">Delete Template?</h3>\n <p className=\"text-gray-600 mb-4\">This action cannot be undone.</p>\n <div className=\"flex justify-end gap-3\">\n <button\n onClick={() => setDeleteConfirm(null)}\n className=\"px-4 py-2 border border-gray-300 rounded-lg\"\n >\n Cancel\n </button>\n <button\n onClick={() => handleDelete(deleteConfirm)}\n className=\"px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default TemplateManager;\n","import React, { useState, useMemo } from 'react';\nimport { marked } from 'marked';\n\nexport interface TemplateFormData {\n template_id?: string;\n template_name: string;\n template_type: string;\n subject_template: string;\n body_markdown: string;\n variables?: string;\n description: string;\n is_active: boolean;\n}\n\nexport interface TemplateEditorProps {\n /** Initial template data for editing, null for create mode */\n initialData?: TemplateFormData | null;\n /** Called when save is clicked, should return a promise */\n onSave: (data: TemplateFormData) => Promise<void>;\n /** Called when cancel/close is clicked */\n onCancel: () => void;\n /** Template types available for selection */\n templateTypes?: string[];\n /** Whether the component is in saving state */\n saving?: boolean;\n}\n\nconst DEFAULT_TYPES = ['notification', 'auth', 'marketing', 'system', 'invitation', 'verification'];\n\n// Convert escaped \\n to actual newlines for display\nconst normalizeNewlines = (text: string): string => {\n return text.replace(/\\\\n/g, '\\n');\n};\n\nexport const TemplateEditor: React.FC<TemplateEditorProps> = ({\n initialData,\n onSave,\n onCancel,\n templateTypes = DEFAULT_TYPES,\n saving = false\n}) => {\n const [activeTab, setActiveTab] = useState<'basic' | 'content'>('basic');\n const [showPreview, setShowPreview] = useState(false);\n const [formData, setFormData] = useState<TemplateFormData>({\n template_id: initialData?.template_id || '',\n template_name: initialData?.template_name || '',\n template_type: initialData?.template_type || 'notification',\n subject_template: initialData?.subject_template || '',\n // Normalize newlines when loading\n body_markdown: normalizeNewlines(initialData?.body_markdown || ''),\n description: initialData?.description || '',\n is_active: initialData?.is_active ?? true\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n await onSave(formData);\n };\n\n const isEdit = !!initialData?.template_id;\n\n // Render markdown preview with sample variables\n const renderedPreview = useMemo(() => {\n let preview = formData.body_markdown;\n // Replace template variables with styled badges for preview\n preview = preview.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded text-sm\">{{$1}}</span>');\n return marked.parse(preview) as string;\n }, [formData.body_markdown]);\n\n const subjectPreview = useMemo(() => {\n return formData.subject_template.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded\">{{$1}}</span>');\n }, [formData.subject_template]);\n\n return (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden flex flex-col\">\n {/* Header */}\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <h2 className=\"text-lg font-semibold text-gray-900\">\n {isEdit ? 'Edit Template' : 'Create New Template'}\n </h2>\n <button onClick={onCancel} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"border-b border-gray-200 px-6\">\n <div className=\"flex gap-4\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('basic')}\n className={`py-3 px-1 border-b-2 text-sm font-medium transition-colors ${activeTab === 'basic'\n ? 'border-blue-600 text-blue-600'\n : 'border-transparent text-gray-500 hover:text-gray-700'\n }`}\n >\n 📋 Basic Info\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('content')}\n className={`py-3 px-1 border-b-2 text-sm font-medium transition-colors ${activeTab === 'content'\n ? 'border-blue-600 text-blue-600'\n : 'border-transparent text-gray-500 hover:text-gray-700'\n }`}\n >\n ✉️ Email Content\n </button>\n </div>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex-1 overflow-y-auto\">\n {/* Basic Tab */}\n {activeTab === 'basic' && (\n <div className=\"p-6 space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Template Name *</label>\n <input\n type=\"text\"\n required\n value={formData.template_name}\n onChange={(e) => setFormData({ ...formData, template_name: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"e.g., Welcome Email\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Type *</label>\n <select\n value={formData.template_type}\n onChange={(e) => setFormData({ ...formData, template_type: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n >\n {templateTypes.map(type => (\n <option key={type} value={type}>\n {type.charAt(0).toUpperCase() + type.slice(1)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center pt-6\">\n <label className=\"flex items-center cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.is_active}\n onChange={(e) => setFormData({ ...formData, is_active: e.target.checked })}\n className=\"w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <span className=\"ml-2 text-sm text-gray-700\">Active</span>\n </label>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Description</label>\n <textarea\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"Brief description of when this template is used\"\n />\n </div>\n\n <div className=\"pt-4 border-t border-gray-200\">\n <p className=\"text-sm text-gray-500\">\n 💡 <strong>Tip:</strong> Use the \"Email Content\" tab to write your subject line and email body.\n </p>\n </div>\n </div>\n )}\n\n {/* Content Tab */}\n {activeTab === 'content' && (\n <div className=\"p-6 space-y-4\">\n {/* Subject Line */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Subject Line *</label>\n <input\n type=\"text\"\n required\n value={formData.subject_template}\n onChange={(e) => setFormData({ ...formData, subject_template: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm\"\n placeholder=\"e.g., Welcome to {{app_name}}, {{user_name}}!\"\n />\n {formData.subject_template && (\n <div className=\"mt-2 text-sm text-gray-600\">\n <span className=\"text-gray-500\">Preview: </span>\n <span dangerouslySetInnerHTML={{ __html: subjectPreview }} />\n </div>\n )}\n </div>\n\n {/* Body with Toggle */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Email Body (Markdown) *</label>\n <button\n type=\"button\"\n onClick={() => setShowPreview(!showPreview)}\n className={`px-3 py-1 text-xs font-medium rounded-full transition-colors ${showPreview\n ? 'bg-blue-600 text-white'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\n }`}\n >\n {showPreview ? '✏️ Edit' : '👁️ Preview'}\n </button>\n </div>\n\n {!showPreview ? (\n <div>\n <textarea\n required\n value={formData.body_markdown}\n onChange={(e) => setFormData({ ...formData, body_markdown: e.target.value })}\n rows={14}\n className=\"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm\"\n placeholder={\"# Welcome, {{user_name}}!\\n\\nThank you for signing up for **{{app_name}}**.\\n\\nWe're excited to have you on board!\\n\\n---\\n\\nBest regards,\\nThe Team\"}\n />\n <p className=\"mt-1 text-xs text-gray-500\">\n Use {\"{{variable}}\"} for dynamic content. Supports Markdown formatting.\n </p>\n </div>\n ) : (\n <div\n className=\"w-full min-h-[350px] p-4 border border-blue-200 rounded-lg bg-blue-50 prose prose-sm max-w-none overflow-y-auto\"\n dangerouslySetInnerHTML={{ __html: renderedPreview || '<p class=\"text-gray-400\">No content to preview</p>' }}\n />\n )}\n </div>\n </div>\n )}\n </form>\n\n {/* Footer */}\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-between items-center bg-gray-50\">\n <div className=\"text-sm text-gray-500\">\n {activeTab === 'basic' && 'Step 1 of 2'}\n {activeTab === 'content' && 'Step 2 of 2'}\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-900 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={saving || !formData.template_name || !formData.subject_template || !formData.body_markdown}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {saving ? 'Saving...' : (isEdit ? 'Save Changes' : 'Create Template')}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default TemplateEditor;\n","import React, { useState, useEffect } from 'react';\n\nexport interface EmailTemplate {\n template_id: string;\n template_name: string;\n subject_template: string;\n body_markdown: string;\n variables?: string | null;\n}\n\nexport interface TestEmailData {\n template_id: string;\n to: string;\n variables: Record<string, string>;\n}\n\nexport interface TemplateTesterProps {\n template: EmailTemplate;\n onSendTest: (data: TestEmailData) => Promise<void>;\n onCancel: () => void;\n sending?: boolean;\n defaultValues?: {\n to?: string;\n variables?: Record<string, string>;\n };\n}\n\nexport const TemplateTester: React.FC<TemplateTesterProps> = ({\n template,\n onSendTest,\n onCancel,\n sending = false,\n defaultValues = {}\n}) => {\n const [toEmail, setToEmail] = useState(defaultValues.to || '');\n const [variables, setVariables] = useState<Record<string, string>>({});\n const [detectedVariables, setDetectedVariables] = useState<string[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState<string | null>(null);\n\n // Extract variables from subject and body\n useEffect(() => {\n const regex = /\\{\\{(\\w+)\\}\\}/g;\n const subjectVars = Array.from(template.subject_template.matchAll(regex)).map(m => m[1]);\n const bodyVars = Array.from(template.body_markdown.matchAll(regex)).map(m => m[1]);\n\n // Unique variables\n const uniqueVars = Array.from(new Set([...subjectVars, ...bodyVars]));\n setDetectedVariables(uniqueVars);\n\n // Initialize variable values if empty\n const initialValues: Record<string, string> = {};\n\n // Default mappings provided by caller or hardcoded common ones\n const defaults: Record<string, string> = defaultValues.variables || {};\n\n uniqueVars.forEach(v => {\n // Priority: 1. Existing state (if any) 2. Default provided 3. Special handling 4. Empty\n // Note: We use existing 'variables' state if we want to preserve edits when re-parsing, \n // but here we depend on [template] so it resets on template change.\n\n if (defaults[v]) {\n initialValues[v] = defaults[v];\n } else if (v === 'email' && toEmail) {\n // Auto-fill {{email}} with toEmail if present\n initialValues[v] = toEmail;\n } else {\n initialValues[v] = '';\n }\n });\n setVariables(initialValues);\n }, [template, defaultValues]); // Depend on defaultValues so it updates if they load late\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(null);\n\n try {\n await onSendTest({\n template_id: template.template_id,\n to: toEmail,\n variables\n });\n setSuccess('Test email sent successfully!');\n } catch (e: any) {\n setError(e.message || 'Failed to send test email');\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-lg w-full overflow-hidden flex flex-col max-h-[90vh]\">\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <h2 className=\"text-lg font-semibold text-gray-900\">\n Test Template: {template.template_name}\n </h2>\n <button onClick={onCancel} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex-1 overflow-y-auto p-6 space-y-4\">\n {/* Status Messages */}\n {error && (\n <div className=\"p-3 rounded-md text-sm bg-red-50 text-red-800 border border-red-200\">\n {error}\n </div>\n )}\n {success && (\n <div className=\"p-3 rounded-md text-sm bg-green-50 text-green-800 border border-green-200\">\n {success}\n </div>\n )}\n\n {/* To Email */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">To Email *</label>\n <input\n type=\"email\"\n required\n value={toEmail}\n onChange={(e) => {\n const val = e.target.value;\n setToEmail(val);\n // If there is an 'email' variable, keep it in sync\n if (variables['email'] !== undefined) {\n setVariables(prev => ({ ...prev, email: val }));\n }\n }}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"recipient@example.com\"\n />\n </div>\n\n {/* Variable Inputs */}\n {detectedVariables.length > 0 && (\n <div className=\"pt-2\">\n <h3 className=\"text-sm font-medium text-gray-900 mb-3 pb-2 border-b border-gray-100\">\n Template Variables\n </h3>\n <div className=\"space-y-3\">\n {detectedVariables.map(variable => (\n <div key={variable}>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">\n {variable}\n </label>\n <input\n type=\"text\"\n value={variables[variable] || ''}\n onChange={(e) => setVariables({ ...variables, [variable]: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm\"\n placeholder={`Value for {{${variable}}}`}\n />\n </div>\n ))}\n </div>\n </div>\n )}\n\n {detectedVariables.length === 0 && (\n <p className=\"text-sm text-gray-500 italic\">No variables detected in this template.</p>\n )}\n </form>\n\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-end gap-3 bg-gray-50\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Close\n </button>\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={sending || !toEmail || (success != null)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {sending ? (\n <>\n <div className=\"animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent\"></div>\n Sending...\n </>\n ) : (\n <>\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\" />\n </svg>\n Send Test Email\n </>\n )}\n </button>\n </div>\n </div>\n </div>\n );\n};\n","import React, { useState, useEffect } from 'react';\n\n// Interfaces based on our backend schema\nexport interface EmailSettingsData {\n provider: string;\n fromName: string;\n fromAddress: string;\n brandName?: string;\n resendApiKey?: string;\n sendgridApiKey?: string;\n sendpulseClientId?: string;\n sendpulseClientSecret?: string;\n [key: string]: any;\n}\n\nexport interface EmailSettingsProps {\n /** Fetch settings from backend */\n onLoadSettings: () => Promise<EmailSettingsData>;\n /** Save settings to backend */\n onSaveSettings: (settings: EmailSettingsData) => Promise<void>;\n /** Test settings configuration */\n onTestSettings?: (settings: EmailSettingsData) => Promise<{ success: boolean; message?: string; error?: string }>;\n /** Optional title override */\n title?: string;\n /** Optional description override */\n description?: string;\n}\n\nconst PROVIDERS = [\n { value: 'mailchannels', label: 'MailChannels (Cloudflare)' },\n { value: 'resend', label: 'Resend' },\n { value: 'sendgrid', label: 'SendGrid' },\n { value: 'sendpulse', label: 'SendPulse' },\n];\n\nexport const EmailSettings: React.FC<EmailSettingsProps> = ({\n onLoadSettings,\n onSaveSettings,\n onTestSettings,\n title = 'Email Settings',\n description = 'Configure how the system sends transactional emails.'\n}) => {\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [testing, setTesting] = useState(false);\n\n const [settings, setSettings] = useState<EmailSettingsData>({\n provider: 'mailchannels',\n fromName: '',\n fromAddress: '',\n });\n\n useEffect(() => {\n loadData();\n }, []);\n\n const loadData = async () => {\n setLoading(true);\n try {\n const data = await onLoadSettings();\n setSettings(prev => ({ ...prev, ...data }));\n } catch (e: any) {\n console.error('Failed to load settings', e);\n } finally {\n setLoading(false);\n }\n };\n\n const handleChange = (key: string, value: string) => {\n setSettings(prev => ({ ...prev, [key]: value }));\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n await onSaveSettings(settings);\n } catch (e: any) {\n console.error('Failed to save settings', e);\n throw e; // Re-throw so parent can handle if needed (though promise is awaited)\n } finally {\n setSaving(false);\n }\n };\n\n const handleTest = async () => {\n if (!onTestSettings) return;\n setTesting(true);\n try {\n await onTestSettings(settings);\n } catch (e: any) {\n console.error('Test failed', e);\n throw e;\n } finally {\n setTesting(false);\n }\n };\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\"></div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl p-6 space-y-8\">\n <div>\n <h2 className=\"text-2xl font-bold text-gray-900\">{title}</h2>\n <p className=\"text-gray-500 mt-1\">{description}</p>\n </div>\n\n {/* Global Config Card */}\n <div className=\"bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden\">\n <div className=\"px-6 py-4 border-b border-gray-100 bg-gray-50\">\n <h3 className=\"text-lg font-medium text-gray-900\">Global Configuration</h3>\n <p className=\"text-sm text-gray-500\">Default sender identity and delivery provider.</p>\n </div>\n <div className=\"p-6 space-y-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Brand Name</label>\n <input\n type=\"text\"\n value={settings.brandName || ''}\n onChange={(e) => handleChange('brandName', e.target.value)}\n placeholder=\"e.g. Content Growth\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n <p className=\"text-xs text-gray-500\">Used in email templates as {'{{brandName}}'}</p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">From Name</label>\n <input\n type=\"text\"\n value={settings.fromName}\n onChange={(e) => handleChange('fromName', e.target.value)}\n placeholder=\"e.g. Support Team\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">From Address</label>\n <input\n type=\"email\"\n value={settings.fromAddress}\n onChange={(e) => handleChange('fromAddress', e.target.value)}\n placeholder=\"e.g. noreply@example.com\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Email Provider</label>\n <div className=\"relative\">\n <select\n value={settings.provider}\n onChange={(e) => handleChange('provider', e.target.value)}\n className=\"appearance-none w-full px-3 py-2 pr-10 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white text-gray-900\"\n >\n {PROVIDERS.map(p => (\n <option key={p.value} value={p.value}>{p.label}</option>\n ))}\n </select>\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500\">\n <svg className=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fillRule=\"evenodd\" d=\"M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n </div>\n <p className=\"text-xs text-gray-500 mt-1\">\n {settings.provider === 'mailchannels' && \"MailChannels is recommended for Cloudflare Workers (requires no API key for standard usage).\"}\n {settings.provider === 'resend' && \"Modern email API, good for transactional data.\"}\n </p>\n </div>\n </div>\n </div>\n\n {/* Provider Specific Config */}\n {settings.provider !== 'mailchannels' && (\n <div className=\"bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden\">\n <div className=\"px-6 py-4 border-b border-gray-100 bg-gray-50\">\n <h3 className=\"text-lg font-medium text-gray-900\">\n {PROVIDERS.find(p => p.value === settings.provider)?.label} Configuration\n </h3>\n </div>\n <div className=\"p-6 space-y-6\">\n {settings.provider === 'resend' && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">API Key</label>\n <input\n type=\"password\"\n value={settings.resendApiKey || ''}\n onChange={(e) => handleChange('resendApiKey', e.target.value)}\n placeholder=\"re_...\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n )}\n\n {settings.provider === 'sendgrid' && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">API Key</label>\n <input\n type=\"password\"\n value={settings.sendgridApiKey || ''}\n onChange={(e) => handleChange('sendgridApiKey', e.target.value)}\n placeholder=\"SG...\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n )}\n\n {settings.provider === 'sendpulse' && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Client ID</label>\n <input\n type=\"text\"\n value={settings.sendpulseClientId || ''}\n onChange={(e) => handleChange('sendpulseClientId', e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Client Secret</label>\n <input\n type=\"password\"\n value={settings.sendpulseClientSecret || ''}\n onChange={(e) => handleChange('sendpulseClientSecret', e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-4\">\n {onTestSettings && (\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={saving || testing}\n className={`px-4 py-2 bg-white text-gray-700 font-medium rounded-lg border border-gray-300 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors ${saving || testing ? 'opacity-70 cursor-not-allowed' : ''\n }`}\n >\n {testing ? 'Sending...' : 'Test Configuration'}\n </button>\n )}\n <button\n onClick={handleSave}\n disabled={saving || testing}\n className={`px-6 py-2 bg-blue-600 text-white font-medium rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors ${saving || testing ? 'opacity-70 cursor-not-allowed' : ''\n }`}\n >\n {saving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n );\n};\n","/**\n * Email Logs Panel Component\n * \n * A reusable React component for viewing email logs.\n * Can be embedded in any admin/sysadmin page.\n */\nimport React, { useState, useEffect } from 'react';\n\ninterface EmailLog {\n id: string;\n batchId?: string;\n recipientEmail: string;\n recipientUserId?: string;\n templateId: string;\n subject?: string;\n status: 'pending' | 'sent' | 'failed' | 'bounced' | 'complained';\n provider?: string;\n providerMessageId?: string;\n errorMessage?: string;\n errorCode?: string;\n metadata?: Record<string, any>;\n createdAt: number;\n sentAt?: number;\n}\n\ninterface EmailStats {\n total: number;\n sent: number;\n failed: number;\n pending: number;\n byTemplate: Record<string, number>;\n}\n\nexport interface EmailLogsPanelProps {\n /**\n * Function to fetch email logs from the API\n * Should accept query params and return { logs, total }\n */\n fetchLogs: (params: {\n page: number;\n limit: number;\n status?: string;\n email?: string;\n template?: string;\n }) => Promise<{ logs: EmailLog[]; total: number }>;\n\n /**\n * Function to fetch email stats from the API\n * Should accept days parameter and return EmailStats\n */\n fetchStats?: (days: number) => Promise<EmailStats>;\n\n /**\n * Title for the panel (optional)\n */\n title?: string;\n\n /**\n * Number of logs per page\n */\n pageSize?: number;\n\n /**\n * Custom class name for styling\n */\n className?: string;\n}\n\nconst statusColors: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n sent: 'bg-green-100 text-green-800',\n failed: 'bg-red-100 text-red-800',\n bounced: 'bg-orange-100 text-orange-800',\n complained: 'bg-purple-100 text-purple-800',\n};\n\nexport function EmailLogsPanel({\n fetchLogs,\n fetchStats,\n title = 'Email Logs',\n pageSize = 20,\n className = ''\n}: EmailLogsPanelProps) {\n const [logs, setLogs] = useState<EmailLog[]>([]);\n const [stats, setStats] = useState<EmailStats | null>(null);\n const [loading, setLoading] = useState(true);\n const [page, setPage] = useState(1);\n const [totalPages, setTotalPages] = useState(1);\n const [statusFilter, setStatusFilter] = useState<string>('');\n const [emailFilter, setEmailFilter] = useState<string>('');\n const [templateFilter, setTemplateFilter] = useState<string>('');\n const [showStats, setShowStats] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n loadLogs();\n }, [page, statusFilter]);\n\n useEffect(() => {\n if (fetchStats && showStats) {\n loadStats();\n }\n }, [showStats]);\n\n const loadLogs = async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchLogs({\n page,\n limit: pageSize,\n status: statusFilter || undefined,\n email: emailFilter || undefined,\n template: templateFilter || undefined,\n });\n setLogs(result.logs);\n setTotalPages(Math.ceil(result.total / pageSize));\n } catch (err: any) {\n setError(err.message || 'Failed to load logs');\n } finally {\n setLoading(false);\n }\n };\n\n const loadStats = async () => {\n if (!fetchStats) return;\n try {\n const result = await fetchStats(7);\n setStats(result);\n } catch (err) {\n console.error('Failed to load stats:', err);\n }\n };\n\n const formatDate = (timestamp: number) => {\n if (!timestamp) return '-';\n return new Date(timestamp * 1000).toLocaleString();\n };\n\n const handleSearch = (e: React.FormEvent) => {\n e.preventDefault();\n setPage(1);\n loadLogs();\n };\n\n return (\n <div className={`email-logs-panel ${className}`}>\n <div className=\"flex justify-between items-center mb-4\">\n <h2 className=\"text-xl font-semibold text-gray-900\">{title}</h2>\n <div className=\"flex gap-2\">\n {fetchStats && (\n <button\n onClick={() => setShowStats(!showStats)}\n className=\"px-3 py-1.5 text-sm border border-gray-300 rounded-md hover:bg-gray-50\"\n >\n {showStats ? 'Hide Stats' : 'Show Stats'}\n </button>\n )}\n <button\n onClick={loadLogs}\n className=\"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700\"\n >\n Refresh\n </button>\n </div>\n </div>\n\n {/* Stats Panel */}\n {showStats && stats && (\n <div className=\"mb-4 p-4 bg-gray-50 rounded-lg\">\n <h3 className=\"font-medium text-gray-700 mb-3\">Last 7 Days</h3>\n <div className=\"grid grid-cols-4 gap-4\">\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-gray-900\">{stats.total}</div>\n <div className=\"text-sm text-gray-500\">Total</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-green-600\">{stats.sent}</div>\n <div className=\"text-sm text-gray-500\">Sent</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-red-600\">{stats.failed}</div>\n <div className=\"text-sm text-gray-500\">Failed</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-yellow-600\">{stats.pending}</div>\n <div className=\"text-sm text-gray-500\">Pending</div>\n </div>\n </div>\n {Object.keys(stats.byTemplate).length > 0 && (\n <div className=\"mt-3 pt-3 border-t\">\n <div className=\"text-sm text-gray-600\">\n <strong>By Template:</strong>{' '}\n {Object.entries(stats.byTemplate).map(([template, count]) => (\n <span key={template} className=\"mr-3\">\n {template}: {count}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Filters */}\n <form onSubmit={handleSearch} className=\"mb-4 flex gap-2 flex-wrap\">\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n >\n <option value=\"\">All Statuses</option>\n <option value=\"sent\">Sent</option>\n <option value=\"failed\">Failed</option>\n <option value=\"pending\">Pending</option>\n <option value=\"bounced\">Bounced</option>\n </select>\n <input\n type=\"text\"\n value={emailFilter}\n onChange={(e) => setEmailFilter(e.target.value)}\n placeholder=\"Filter by email...\"\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n <input\n type=\"text\"\n value={templateFilter}\n onChange={(e) => setTemplateFilter(e.target.value)}\n placeholder=\"Filter by template...\"\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n <button\n type=\"submit\"\n className=\"px-4 py-2 bg-gray-600 text-white rounded-md text-sm hover:bg-gray-700\"\n >\n Search\n </button>\n </form>\n\n {/* Error */}\n {error && (\n <div className=\"mb-4 p-3 bg-red-50 text-red-700 rounded-md\">\n {error}\n </div>\n )}\n\n {/* Logs Table */}\n {loading ? (\n <div className=\"text-center py-8 text-gray-500\">Loading...</div>\n ) : logs.length === 0 ? (\n <div className=\"text-center py-8 text-gray-500\">No email logs found</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full divide-y divide-gray-200\">\n <thead className=\"bg-gray-50\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Recipient</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Template</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Subject</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Status</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Provider</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Time</th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-gray-200\">\n {logs.map((log) => (\n <tr key={log.id} className={log.status === 'failed' ? 'bg-red-50' : ''}>\n <td className=\"px-4 py-3 text-sm\">\n <div className=\"text-gray-900\">{log.recipientEmail}</div>\n {log.recipientUserId && (\n <div className=\"text-xs text-gray-400\">User: {log.recipientUserId.substring(0, 8)}...</div>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600\">\n {log.templateId}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600 max-w-xs truncate\" title={log.subject}>\n {log.subject || '-'}\n </td>\n <td className=\"px-4 py-3\">\n <span className={`px-2 py-1 text-xs font-medium rounded-full ${statusColors[log.status] || 'bg-gray-100 text-gray-800'}`}>\n {log.status}\n </span>\n {log.errorMessage && (\n <div className=\"text-xs text-red-600 mt-1\" title={log.errorMessage}>\n {log.errorMessage.substring(0, 30)}...\n </div>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600\">\n {log.provider || '-'}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-500\">\n {formatDate(log.createdAt)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {/* Pagination */}\n {totalPages > 1 && (\n <div className=\"mt-4 flex justify-between items-center\">\n <div className=\"text-sm text-gray-500\">\n Page {page} of {totalPages}\n </div>\n <div className=\"flex gap-2\">\n <button\n onClick={() => setPage(p => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"px-3 py-1.5 border border-gray-300 rounded-md text-sm disabled:opacity-50\"\n >\n Previous\n </button>\n <button\n onClick={() => setPage(p => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"px-3 py-1.5 border border-gray-300 rounded-md text-sm disabled:opacity-50\"\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_marked","React","import_react","e","React","normalizeNewlines","React","import_react","React","import_react","React"]}
|
|
1
|
+
{"version":3,"sources":["../../src/frontend/index.ts","../../src/frontend/TemplateManager.tsx","../../src/frontend/TemplateEditor.tsx","../../src/frontend/TemplateTester.tsx","../../src/frontend/EmailSettings.tsx","../../src/frontend/EmailLogsPanel.tsx"],"sourcesContent":["\nexport { TemplateManager } from './TemplateManager';\nexport type { TemplateManagerProps, EmailTemplate } from './TemplateManager';\n\nexport { TemplateEditor } from './TemplateEditor';\nexport type { TemplateEditorProps, TemplateFormData } from './TemplateEditor';\n\nexport { TemplateTester } from './TemplateTester';\nexport type { TemplateTesterProps, TestEmailData } from './TemplateTester';\n\nexport { EmailSettings } from './EmailSettings';\nexport type { EmailSettingsProps, EmailSettingsData } from './EmailSettings';\n\nexport { EmailLogsPanel } from './EmailLogsPanel';\nexport type { EmailLogsPanelProps } from './EmailLogsPanel';\n","import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { marked } from 'marked';\nimport { TemplateEditor, TemplateFormData } from './TemplateEditor';\nimport { TemplateTester, TestEmailData } from './TemplateTester';\n\nexport interface EmailTemplate {\n template_id: string;\n template_name: string;\n template_type: string;\n subject_template: string;\n body_markdown: string;\n variables?: string | null;\n description: string | null;\n is_active: number | boolean;\n created_at?: number | null;\n updated_at?: number | null;\n}\n\nexport interface TemplateManagerProps {\n /** Fetch all templates - returns promise with template array */\n onLoadTemplates: () => Promise<EmailTemplate[]>;\n /** Save a template (create or update) */\n onSaveTemplate: (data: TemplateFormData) => Promise<void>;\n /** Delete a template by ID */\n onDeleteTemplate?: (id: string) => Promise<void>;\n /** Send a test email */\n onSendTestEmail?: (data: TestEmailData) => Promise<void>;\n /** Page title */\n title?: string;\n /** Page description */\n description?: string;\n /** Template types for filtering and editor */\n templateTypes?: string[];\n /** Default values for tester */\n defaultTestValues?: {\n to?: string;\n variables?: Record<string, string>;\n };\n}\n\nconst TYPE_COLORS: Record<string, { bg: string; text: string }> = {\n 'auth': { bg: 'bg-blue-100', text: 'text-blue-800' },\n 'notification': { bg: 'bg-purple-100', text: 'text-purple-800' },\n 'marketing': { bg: 'bg-green-100', text: 'text-green-800' },\n 'system': { bg: 'bg-gray-100', text: 'text-gray-800' },\n 'invitation': { bg: 'bg-orange-100', text: 'text-orange-800' },\n 'verification': { bg: 'bg-cyan-100', text: 'text-cyan-800' },\n 'default': { bg: 'bg-gray-100', text: 'text-gray-600' }\n};\n\nconst normalizeNewlines = (text: string): string => {\n return text?.replace(/\\\\n/g, '\\n') || '';\n};\n\nexport const TemplateManager: React.FC<TemplateManagerProps> = ({\n onLoadTemplates,\n onSaveTemplate,\n onDeleteTemplate,\n onSendTestEmail,\n title = 'Email Templates',\n description = 'Manage system email templates',\n templateTypes,\n defaultTestValues\n}) => {\n // Keep props ref for passing down if needed, but we destructured\n const props = { defaultTestValues };\n const [templates, setTemplates] = useState<EmailTemplate[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [filterType, setFilterType] = useState<string>('all');\n\n // Modal states\n const [previewTemplate, setPreviewTemplate] = useState<EmailTemplate | null>(null);\n const [editingTemplate, setEditingTemplate] = useState<EmailTemplate | null>(null);\n const [testingTemplate, setTestingTemplate] = useState<EmailTemplate | null>(null);\n const [showEditor, setShowEditor] = useState(false);\n const [showTester, setShowTester] = useState(false);\n const [saving, setSaving] = useState(false);\n\n // Delete confirmation\n const [deleteConfirm, setDeleteConfirm] = useState<string | null>(null);\n\n const loadTemplates = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const data = await onLoadTemplates();\n setTemplates(data);\n } catch (e: any) {\n setError(e.message || 'Failed to load templates');\n } finally {\n setLoading(false);\n }\n }, [onLoadTemplates]);\n\n useEffect(() => {\n loadTemplates();\n }, [loadTemplates]);\n\n const openCreate = () => {\n setEditingTemplate(null);\n setShowEditor(true);\n };\n\n const openPreview = (template: EmailTemplate) => {\n setPreviewTemplate(template);\n };\n\n const openEdit = (template: EmailTemplate) => {\n setPreviewTemplate(null);\n setEditingTemplate(template);\n setShowEditor(true);\n };\n\n const openTester = (template: EmailTemplate) => {\n setTestingTemplate(template);\n setShowTester(true);\n };\n\n const handleSave = async (data: TemplateFormData) => {\n setSaving(true);\n try {\n await onSaveTemplate(data);\n setShowEditor(false);\n await loadTemplates();\n } catch (e: any) {\n // Re-throw so consumer can show toast\n setSaving(false);\n throw e;\n }\n setSaving(false);\n };\n\n const handleDelete = async (id: string) => {\n if (!onDeleteTemplate) return;\n try {\n await onDeleteTemplate(id);\n setDeleteConfirm(null);\n await loadTemplates();\n } catch (e: any) {\n setError(e.message || 'Failed to delete template');\n }\n };\n\n const handleTest = async (data: TestEmailData) => {\n if (!onSendTestEmail) return;\n setSaving(true);\n try {\n await onSendTestEmail(data);\n } finally {\n setSaving(false);\n }\n };\n\n const getTypeColor = (type: string) => TYPE_COLORS[type] || TYPE_COLORS['default'];\n\n const uniqueTypes = ['all', ...new Set(templates.map(t => t.template_type))];\n const filteredTemplates = filterType === 'all'\n ? templates\n : templates.filter(t => t.template_type === filterType);\n\n const formatDate = (timestamp: number | null | undefined) => {\n if (!timestamp) return 'N/A';\n return new Date(timestamp * 1000).toLocaleDateString('en-US', {\n month: 'short', day: 'numeric', year: 'numeric'\n });\n };\n\n // Preview markdown render\n const previewBody = useMemo(() => {\n if (!previewTemplate?.body_markdown) return '';\n let md = normalizeNewlines(previewTemplate.body_markdown);\n md = md.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded text-sm\">{{$1}}</span>');\n return marked.parse(md) as string;\n }, [previewTemplate]);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\"></div>\n </div>\n );\n }\n\n return (\n <div className=\"template-manager\">\n {/* Header */}\n <div className=\"flex justify-between items-center mb-6\">\n <div>\n <h1 className=\"text-2xl font-bold text-gray-900\">{title}</h1>\n <p className=\"text-sm text-gray-500 mt-1\">{description}</p>\n </div>\n <button\n onClick={openCreate}\n className=\"px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center gap-2 shadow-sm\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n Create Template\n </button>\n </div>\n\n {/* Error Banner */}\n {error && (\n <div className=\"mb-4 p-3 rounded-lg bg-red-50 text-red-800 border border-red-200\">\n {error}\n <button onClick={() => setError(null)} className=\"ml-2 underline\">Dismiss</button>\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex gap-4 mb-6\">\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-gray-900\">{templates.length}</div>\n <div className=\"text-sm text-gray-500\">Total</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-green-600\">\n {templates.filter(t => t.is_active).length}\n </div>\n <div className=\"text-sm text-gray-500\">Active</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-yellow-600\">\n {templates.filter(t => !t.is_active).length}\n </div>\n <div className=\"text-sm text-gray-500\">Inactive</div>\n </div>\n <div className=\"bg-white rounded-lg border border-gray-200 p-4 flex-1\">\n <div className=\"text-2xl font-bold text-blue-600\">\n {new Set(templates.map(t => t.template_type)).size}\n </div>\n <div className=\"text-sm text-gray-500\">Types</div>\n </div>\n </div>\n\n {/* Filter Tabs */}\n <div className=\"flex gap-2 mb-6 border-b border-gray-200 pb-3 flex-wrap\">\n {uniqueTypes.map(type => (\n <button\n key={type}\n onClick={() => setFilterType(type)}\n className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors ${filterType === type\n ? 'bg-blue-600 text-white'\n : 'bg-gray-100 text-gray-600 hover:bg-gray-200'\n }`}\n >\n {type.charAt(0).toUpperCase() + type.slice(1)}\n </button>\n ))}\n </div>\n\n {/* Templates Grid */}\n {filteredTemplates.length === 0 ? (\n <div className=\"text-center py-16 bg-gray-50 rounded-lg border-2 border-dashed border-gray-200\">\n <svg className=\"mx-auto h-12 w-12 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\" />\n </svg>\n <h3 className=\"mt-4 text-lg font-medium text-gray-900\">No templates found</h3>\n <p className=\"mt-2 text-sm text-gray-500\">\n {filterType === 'all' ? 'Create your first template.' : `No \"${filterType}\" templates.`}\n </p>\n <button onClick={openCreate} className=\"mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg text-sm\">\n Create Template\n </button>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredTemplates.map((template) => {\n const typeColor = getTypeColor(template.template_type);\n return (\n <div\n key={template.template_id}\n className=\"bg-white rounded-lg border border-gray-200 hover:border-blue-300 hover:shadow-md transition-all cursor-pointer overflow-hidden flex flex-col h-full\"\n onClick={() => openPreview(template)}\n >\n <div className=\"p-5 flex-1 flex flex-col\">\n <div className=\"flex items-start justify-between mb-3\">\n <span className={`px-2 py-1 text-xs font-medium rounded ${typeColor.bg} ${typeColor.text}`}>\n {template.template_type}\n </span>\n <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${template.is_active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-600'\n }`}>\n {template.is_active ? '● Active' : '○ Inactive'}\n </span>\n </div>\n <h3 className=\"font-semibold text-gray-900 mb-1\">{template.template_name}</h3>\n <p className=\"text-sm text-gray-500 flex-1 line-clamp-2\">\n {template.description || 'No description'}\n </p>\n <div className=\"text-xs text-gray-400 border-t border-gray-100 pt-3 mt-3 truncate\">\n 📧 {template.subject_template}\n </div>\n </div>\n <div className=\"bg-gray-50 px-5 py-3 flex justify-between items-center border-t border-gray-100\">\n <span className=\"text-xs text-gray-500\">\n {formatDate(template.updated_at)}\n </span>\n <div className=\"flex gap-2\">\n <button\n onClick={(e) => { e.stopPropagation(); openEdit(template); }}\n className=\"p-1.5 text-blue-600 hover:bg-blue-50 rounded\"\n title=\"Edit\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n </button>\n {onSendTestEmail && (\n <button\n onClick={(e) => { e.stopPropagation(); openTester(template); }}\n className=\"p-1.5 text-purple-600 hover:bg-purple-50 rounded\"\n title=\"Send Test Email\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n </button>\n )}\n {onDeleteTemplate && (\n <button\n onClick={(e) => { e.stopPropagation(); setDeleteConfirm(template.template_id); }}\n className=\"p-1.5 text-red-600 hover:bg-red-50 rounded\"\n title=\"Delete\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {/* Preview Modal */}\n {previewTemplate && (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col\">\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <div>\n <h2 className=\"text-lg font-semibold text-gray-900\">{previewTemplate.template_name}</h2>\n <p className=\"text-sm text-gray-500\">{previewTemplate.template_type} • {previewTemplate.is_active ? 'Active' : 'Inactive'}</p>\n </div>\n <button onClick={() => setPreviewTemplate(null)} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-6 space-y-4\">\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Subject</label>\n <div className=\"p-3 bg-gray-50 rounded-lg border border-gray-200 font-mono text-sm\">\n {previewTemplate.subject_template}\n </div>\n </div>\n\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Email Body</label>\n <div\n className=\"p-4 bg-white rounded-lg border border-gray-200 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{ __html: previewBody }}\n />\n </div>\n\n {previewTemplate.description && (\n <div>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">Description</label>\n <p className=\"text-gray-600 text-sm\">{previewTemplate.description}</p>\n </div>\n )}\n </div>\n\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-end gap-3 bg-gray-50\">\n <button\n onClick={() => setPreviewTemplate(null)}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Close\n </button>\n <button\n onClick={() => openEdit(previewTemplate)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 flex items-center gap-2\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z\" />\n </svg>\n Edit Template\n </button>\n {onSendTestEmail && (\n <button\n onClick={() => openTester(previewTemplate)}\n className=\"px-4 py-2 text-sm font-medium text-purple-700 bg-purple-100 rounded-lg hover:bg-purple-200 flex items-center gap-2\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n Test\n </button>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Editor Modal */}\n {showEditor && (\n <TemplateEditor\n initialData={editingTemplate ? {\n template_id: editingTemplate.template_id,\n template_name: editingTemplate.template_name,\n template_type: editingTemplate.template_type,\n subject_template: editingTemplate.subject_template,\n body_markdown: editingTemplate.body_markdown,\n description: editingTemplate.description || '',\n is_active: !!editingTemplate.is_active\n } : null}\n onSave={handleSave}\n onCancel={() => setShowEditor(false)}\n templateTypes={templateTypes}\n saving={saving}\n />\n )}\n\n {/* Tester Modal */}\n {showTester && testingTemplate && (\n <TemplateTester\n template={testingTemplate}\n onSendTest={handleTest}\n onCancel={() => setShowTester(false)}\n sending={saving}\n defaultValues={props.defaultTestValues}\n />\n )}\n\n {/* Delete Confirmation */}\n {deleteConfirm && (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-lg shadow-xl max-w-sm w-full p-6\">\n <h3 className=\"text-lg font-semibold mb-2\">Delete Template?</h3>\n <p className=\"text-gray-600 mb-4\">This action cannot be undone.</p>\n <div className=\"flex justify-end gap-3\">\n <button\n onClick={() => setDeleteConfirm(null)}\n className=\"px-4 py-2 border border-gray-300 rounded-lg\"\n >\n Cancel\n </button>\n <button\n onClick={() => handleDelete(deleteConfirm)}\n className=\"px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default TemplateManager;\n","import React, { useState, useMemo } from 'react';\nimport { marked } from 'marked';\n\nexport interface TemplateFormData {\n template_id?: string;\n template_name: string;\n template_type: string;\n subject_template: string;\n body_markdown: string;\n variables?: string;\n description: string;\n is_active: boolean;\n}\n\nexport interface TemplateEditorProps {\n /** Initial template data for editing, null for create mode */\n initialData?: TemplateFormData | null;\n /** Called when save is clicked, should return a promise */\n onSave: (data: TemplateFormData) => Promise<void>;\n /** Called when cancel/close is clicked */\n onCancel: () => void;\n /** Template types available for selection */\n templateTypes?: string[];\n /** Whether the component is in saving state */\n saving?: boolean;\n}\n\nconst DEFAULT_TYPES = ['notification', 'auth', 'marketing', 'system', 'invitation', 'verification'];\n\n// Convert escaped \\n to actual newlines for display\nconst normalizeNewlines = (text: string): string => {\n return text.replace(/\\\\n/g, '\\n');\n};\n\nexport const TemplateEditor: React.FC<TemplateEditorProps> = ({\n initialData,\n onSave,\n onCancel,\n templateTypes = DEFAULT_TYPES,\n saving = false\n}) => {\n const [activeTab, setActiveTab] = useState<'basic' | 'content'>('basic');\n const [showPreview, setShowPreview] = useState(false);\n const [formData, setFormData] = useState<TemplateFormData>({\n template_id: initialData?.template_id || '',\n template_name: initialData?.template_name || '',\n template_type: initialData?.template_type || 'notification',\n subject_template: initialData?.subject_template || '',\n // Normalize newlines when loading\n body_markdown: normalizeNewlines(initialData?.body_markdown || ''),\n description: initialData?.description || '',\n is_active: initialData?.is_active ?? true\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n await onSave(formData);\n };\n\n const isEdit = !!initialData?.template_id;\n\n // Render markdown preview with sample variables\n const renderedPreview = useMemo(() => {\n let preview = formData.body_markdown;\n // Replace template variables with styled badges for preview\n preview = preview.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded text-sm\">{{$1}}</span>');\n return marked.parse(preview) as string;\n }, [formData.body_markdown]);\n\n const subjectPreview = useMemo(() => {\n return formData.subject_template.replace(/\\{\\{(\\w+)\\}\\}/g, '<span class=\"bg-blue-100 text-blue-800 px-1 rounded\">{{$1}}</span>');\n }, [formData.subject_template]);\n\n return (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden flex flex-col\">\n {/* Header */}\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <h2 className=\"text-lg font-semibold text-gray-900\">\n {isEdit ? 'Edit Template' : 'Create New Template'}\n </h2>\n <button onClick={onCancel} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"border-b border-gray-200 px-6\">\n <div className=\"flex gap-4\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('basic')}\n className={`py-3 px-1 border-b-2 text-sm font-medium transition-colors ${activeTab === 'basic'\n ? 'border-blue-600 text-blue-600'\n : 'border-transparent text-gray-500 hover:text-gray-700'\n }`}\n >\n 📋 Basic Info\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('content')}\n className={`py-3 px-1 border-b-2 text-sm font-medium transition-colors ${activeTab === 'content'\n ? 'border-blue-600 text-blue-600'\n : 'border-transparent text-gray-500 hover:text-gray-700'\n }`}\n >\n ✉️ Email Content\n </button>\n </div>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex-1 overflow-y-auto\">\n {/* Basic Tab */}\n {activeTab === 'basic' && (\n <div className=\"p-6 space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Template Name *</label>\n <input\n type=\"text\"\n required\n value={formData.template_name}\n onChange={(e) => setFormData({ ...formData, template_name: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"e.g., Welcome Email\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Type *</label>\n <select\n value={formData.template_type}\n onChange={(e) => setFormData({ ...formData, template_type: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n >\n {templateTypes.map(type => (\n <option key={type} value={type}>\n {type.charAt(0).toUpperCase() + type.slice(1)}\n </option>\n ))}\n </select>\n </div>\n <div className=\"flex items-center pt-6\">\n <label className=\"flex items-center cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={formData.is_active}\n onChange={(e) => setFormData({ ...formData, is_active: e.target.checked })}\n className=\"w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <span className=\"ml-2 text-sm text-gray-700\">Active</span>\n </label>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Description</label>\n <textarea\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"Brief description of when this template is used\"\n />\n </div>\n\n <div className=\"pt-4 border-t border-gray-200\">\n <p className=\"text-sm text-gray-500\">\n 💡 <strong>Tip:</strong> Use the \"Email Content\" tab to write your subject line and email body.\n </p>\n </div>\n </div>\n )}\n\n {/* Content Tab */}\n {activeTab === 'content' && (\n <div className=\"p-6 space-y-4\">\n {/* Subject Line */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Subject Line *</label>\n <input\n type=\"text\"\n required\n value={formData.subject_template}\n onChange={(e) => setFormData({ ...formData, subject_template: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm\"\n placeholder=\"e.g., Welcome to {{app_name}}, {{user_name}}!\"\n />\n {formData.subject_template && (\n <div className=\"mt-2 text-sm text-gray-600\">\n <span className=\"text-gray-500\">Preview: </span>\n <span dangerouslySetInnerHTML={{ __html: subjectPreview }} />\n </div>\n )}\n </div>\n\n {/* Body with Toggle */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Email Body (Markdown) *</label>\n <button\n type=\"button\"\n onClick={() => setShowPreview(!showPreview)}\n className={`px-3 py-1 text-xs font-medium rounded-full transition-colors ${showPreview\n ? 'bg-blue-600 text-white'\n : 'bg-gray-200 text-gray-700 hover:bg-gray-300'\n }`}\n >\n {showPreview ? '✏️ Edit' : '👁️ Preview'}\n </button>\n </div>\n\n {!showPreview ? (\n <div>\n <textarea\n required\n value={formData.body_markdown}\n onChange={(e) => setFormData({ ...formData, body_markdown: e.target.value })}\n rows={14}\n className=\"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 font-mono text-sm\"\n placeholder={\"# Welcome, {{user_name}}!\\n\\nThank you for signing up for **{{app_name}}**.\\n\\nWe're excited to have you on board!\\n\\n---\\n\\nBest regards,\\nThe Team\"}\n />\n <p className=\"mt-1 text-xs text-gray-500\">\n Use {\"{{variable}}\"} for dynamic content. Supports Markdown formatting.\n </p>\n </div>\n ) : (\n <div\n className=\"w-full min-h-[350px] p-4 border border-blue-200 rounded-lg bg-blue-50 prose prose-sm max-w-none overflow-y-auto\"\n dangerouslySetInnerHTML={{ __html: renderedPreview || '<p class=\"text-gray-400\">No content to preview</p>' }}\n />\n )}\n </div>\n </div>\n )}\n </form>\n\n {/* Footer */}\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-between items-center bg-gray-50\">\n <div className=\"text-sm text-gray-500\">\n {activeTab === 'basic' && 'Step 1 of 2'}\n {activeTab === 'content' && 'Step 2 of 2'}\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-900 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={saving || !formData.template_name || !formData.subject_template || !formData.body_markdown}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {saving ? 'Saving...' : (isEdit ? 'Save Changes' : 'Create Template')}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default TemplateEditor;\n","import React, { useState, useEffect, useMemo, useRef } from 'react';\n\nexport interface EmailTemplate {\n template_id: string;\n template_name: string;\n subject_template: string;\n body_markdown: string;\n variables?: string | null;\n}\n\nexport interface TestEmailData {\n template_id: string;\n to: string;\n variables: Record<string, string>;\n}\n\nexport interface TemplateTesterProps {\n template: EmailTemplate;\n onSendTest: (data: TestEmailData) => Promise<void>;\n onCancel: () => void;\n sending?: boolean;\n defaultValues?: {\n to?: string;\n variables?: Record<string, string>;\n };\n}\n\nexport const TemplateTester: React.FC<TemplateTesterProps> = ({\n template,\n onSendTest,\n onCancel,\n sending = false,\n defaultValues = {}\n}) => {\n const [toEmail, setToEmail] = useState(defaultValues.to || '');\n const [variables, setVariables] = useState<Record<string, string>>({});\n const [detectedVariables, setDetectedVariables] = useState<string[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState<string | null>(null);\n\n // Stabilize defaultValues to prevent infinite re-renders\n const defaultValuesRef = useRef(defaultValues);\n const defaultValuesJson = JSON.stringify(defaultValues);\n\n useEffect(() => {\n defaultValuesRef.current = defaultValues;\n }, [defaultValuesJson]);\n\n // Extract variables from subject and body\n useEffect(() => {\n const regex = /\\{\\{(\\w+)\\}\\}/g;\n const subjectVars = Array.from(template.subject_template.matchAll(regex)).map(m => m[1]);\n const bodyVars = Array.from(template.body_markdown.matchAll(regex)).map(m => m[1]);\n\n // Unique variables\n const uniqueVars = Array.from(new Set([...subjectVars, ...bodyVars]));\n setDetectedVariables(uniqueVars);\n\n // Initialize variable values if empty\n const initialValues: Record<string, string> = {};\n\n // Default mappings provided by caller or hardcoded common ones\n const defaults: Record<string, string> = defaultValuesRef.current.variables || {};\n\n uniqueVars.forEach(v => {\n // Priority: 1. Existing state (if any) 2. Default provided 3. Special handling 4. Empty\n // Note: We use existing 'variables' state if we want to preserve edits when re-parsing, \n // but here we depend on [template] so it resets on template change.\n\n if (defaults[v]) {\n initialValues[v] = defaults[v];\n } else if (v === 'email' && toEmail) {\n // Auto-fill {{email}} with toEmail if present\n initialValues[v] = toEmail;\n } else {\n initialValues[v] = '';\n }\n });\n setVariables(initialValues);\n }, [template.template_id, template.subject_template, template.body_markdown, defaultValuesJson]); // Use JSON for stable comparison\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(null);\n\n try {\n await onSendTest({\n template_id: template.template_id,\n to: toEmail,\n variables\n });\n setSuccess('Test email sent successfully!');\n } catch (e: any) {\n setError(e.message || 'Failed to send test email');\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-white rounded-xl shadow-2xl max-w-lg w-full overflow-hidden flex flex-col max-h-[90vh]\">\n <div className=\"px-6 py-4 border-b border-gray-200 flex items-center justify-between bg-gray-50\">\n <h2 className=\"text-lg font-semibold text-gray-900\">\n Test Template: {template.template_name}\n </h2>\n <button onClick={onCancel} className=\"text-gray-400 hover:text-gray-600\">\n <svg className=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex-1 overflow-y-auto p-6 space-y-4\">\n {/* Status Messages */}\n {error && (\n <div className=\"p-3 rounded-md text-sm bg-red-50 text-red-800 border border-red-200\">\n {error}\n </div>\n )}\n {success && (\n <div className=\"p-3 rounded-md text-sm bg-green-50 text-green-800 border border-green-200\">\n {success}\n </div>\n )}\n\n {/* To Email */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">To Email *</label>\n <input\n type=\"email\"\n required\n value={toEmail}\n onChange={(e) => {\n const val = e.target.value;\n setToEmail(val);\n // If there is an 'email' variable, keep it in sync\n if (variables['email'] !== undefined) {\n setVariables(prev => ({ ...prev, email: val }));\n }\n }}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n placeholder=\"recipient@example.com\"\n />\n </div>\n\n {/* Variable Inputs */}\n {detectedVariables.length > 0 && (\n <div className=\"pt-2\">\n <h3 className=\"text-sm font-medium text-gray-900 mb-3 pb-2 border-b border-gray-100\">\n Template Variables\n </h3>\n <div className=\"space-y-3\">\n {detectedVariables.map(variable => (\n <div key={variable}>\n <label className=\"block text-xs font-medium text-gray-500 uppercase mb-1\">\n {variable}\n </label>\n <input\n type=\"text\"\n value={variables[variable] || ''}\n onChange={(e) => setVariables({ ...variables, [variable]: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm\"\n placeholder={`Value for {{${variable}}}`}\n />\n </div>\n ))}\n </div>\n </div>\n )}\n\n {detectedVariables.length === 0 && (\n <p className=\"text-sm text-gray-500 italic\">No variables detected in this template.</p>\n )}\n </form>\n\n <div className=\"px-6 py-4 border-t border-gray-200 flex justify-end gap-3 bg-gray-50\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-100\"\n >\n Close\n </button>\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={sending || !toEmail || (success != null)}\n className=\"px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {sending ? (\n <>\n <div className=\"animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent\"></div>\n Sending...\n </>\n ) : (\n <>\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\" />\n </svg>\n Send Test Email\n </>\n )}\n </button>\n </div>\n </div>\n </div>\n );\n};\n","import React, { useState, useEffect } from 'react';\n\n// Interfaces based on our backend schema\nexport interface EmailSettingsData {\n provider: string;\n fromName: string;\n fromAddress: string;\n brandName?: string;\n resendApiKey?: string;\n sendgridApiKey?: string;\n sendpulseClientId?: string;\n sendpulseClientSecret?: string;\n [key: string]: any;\n}\n\nexport interface EmailSettingsProps {\n /** Fetch settings from backend */\n onLoadSettings: () => Promise<EmailSettingsData>;\n /** Save settings to backend */\n onSaveSettings: (settings: EmailSettingsData) => Promise<void>;\n /** Test settings configuration */\n onTestSettings?: (settings: EmailSettingsData) => Promise<{ success: boolean; message?: string; error?: string }>;\n /** Optional title override */\n title?: string;\n /** Optional description override */\n description?: string;\n}\n\nconst PROVIDERS = [\n { value: 'mailchannels', label: 'MailChannels (Cloudflare)' },\n { value: 'resend', label: 'Resend' },\n { value: 'sendgrid', label: 'SendGrid' },\n { value: 'sendpulse', label: 'SendPulse' },\n];\n\nexport const EmailSettings: React.FC<EmailSettingsProps> = ({\n onLoadSettings,\n onSaveSettings,\n onTestSettings,\n title = 'Email Settings',\n description = 'Configure how the system sends transactional emails.'\n}) => {\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [testing, setTesting] = useState(false);\n\n const [settings, setSettings] = useState<EmailSettingsData>({\n provider: 'mailchannels',\n fromName: '',\n fromAddress: '',\n });\n\n useEffect(() => {\n loadData();\n }, []);\n\n const loadData = async () => {\n setLoading(true);\n try {\n const data = await onLoadSettings();\n setSettings(prev => ({ ...prev, ...data }));\n } catch (e: any) {\n console.error('Failed to load settings', e);\n } finally {\n setLoading(false);\n }\n };\n\n const handleChange = (key: string, value: string) => {\n setSettings(prev => ({ ...prev, [key]: value }));\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n await onSaveSettings(settings);\n } catch (e: any) {\n console.error('Failed to save settings', e);\n throw e; // Re-throw so parent can handle if needed (though promise is awaited)\n } finally {\n setSaving(false);\n }\n };\n\n const handleTest = async () => {\n if (!onTestSettings) return;\n setTesting(true);\n try {\n await onTestSettings(settings);\n } catch (e: any) {\n console.error('Test failed', e);\n throw e;\n } finally {\n setTesting(false);\n }\n };\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\"></div>\n </div>\n );\n }\n\n return (\n <div className=\"max-w-4xl p-6 space-y-8\">\n <div>\n <h2 className=\"text-2xl font-bold text-gray-900\">{title}</h2>\n <p className=\"text-gray-500 mt-1\">{description}</p>\n </div>\n\n {/* Global Config Card */}\n <div className=\"bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden\">\n <div className=\"px-6 py-4 border-b border-gray-100 bg-gray-50\">\n <h3 className=\"text-lg font-medium text-gray-900\">Global Configuration</h3>\n <p className=\"text-sm text-gray-500\">Default sender identity and delivery provider.</p>\n </div>\n <div className=\"p-6 space-y-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Brand Name</label>\n <input\n type=\"text\"\n value={settings.brandName || ''}\n onChange={(e) => handleChange('brandName', e.target.value)}\n placeholder=\"e.g. Content Growth\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n <p className=\"text-xs text-gray-500\">Used in email templates as {'{{brandName}}'}</p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">From Name</label>\n <input\n type=\"text\"\n value={settings.fromName}\n onChange={(e) => handleChange('fromName', e.target.value)}\n placeholder=\"e.g. Support Team\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">From Address</label>\n <input\n type=\"email\"\n value={settings.fromAddress}\n onChange={(e) => handleChange('fromAddress', e.target.value)}\n placeholder=\"e.g. noreply@example.com\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Email Provider</label>\n <div className=\"relative\">\n <select\n value={settings.provider}\n onChange={(e) => handleChange('provider', e.target.value)}\n className=\"appearance-none w-full px-3 py-2 pr-10 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white text-gray-900\"\n >\n {PROVIDERS.map(p => (\n <option key={p.value} value={p.value}>{p.label}</option>\n ))}\n </select>\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500\">\n <svg className=\"h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fillRule=\"evenodd\" d=\"M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n </div>\n <p className=\"text-xs text-gray-500 mt-1\">\n {settings.provider === 'mailchannels' && \"MailChannels is recommended for Cloudflare Workers (requires no API key for standard usage).\"}\n {settings.provider === 'resend' && \"Modern email API, good for transactional data.\"}\n </p>\n </div>\n </div>\n </div>\n\n {/* Provider Specific Config */}\n {settings.provider !== 'mailchannels' && (\n <div className=\"bg-white rounded-lg border border-gray-200 shadow-sm overflow-hidden\">\n <div className=\"px-6 py-4 border-b border-gray-100 bg-gray-50\">\n <h3 className=\"text-lg font-medium text-gray-900\">\n {PROVIDERS.find(p => p.value === settings.provider)?.label} Configuration\n </h3>\n </div>\n <div className=\"p-6 space-y-6\">\n {settings.provider === 'resend' && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">API Key</label>\n <input\n type=\"password\"\n value={settings.resendApiKey || ''}\n onChange={(e) => handleChange('resendApiKey', e.target.value)}\n placeholder=\"re_...\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n )}\n\n {settings.provider === 'sendgrid' && (\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">API Key</label>\n <input\n type=\"password\"\n value={settings.sendgridApiKey || ''}\n onChange={(e) => handleChange('sendgridApiKey', e.target.value)}\n placeholder=\"SG...\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n )}\n\n {settings.provider === 'sendpulse' && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Client ID</label>\n <input\n type=\"text\"\n value={settings.sendpulseClientId || ''}\n onChange={(e) => handleChange('sendpulseClientId', e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium text-gray-700\">Client Secret</label>\n <input\n type=\"password\"\n value={settings.sendpulseClientSecret || ''}\n onChange={(e) => handleChange('sendpulseClientSecret', e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500\"\n />\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-4\">\n {onTestSettings && (\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={saving || testing}\n className={`px-4 py-2 bg-white text-gray-700 font-medium rounded-lg border border-gray-300 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors ${saving || testing ? 'opacity-70 cursor-not-allowed' : ''\n }`}\n >\n {testing ? 'Sending...' : 'Test Configuration'}\n </button>\n )}\n <button\n onClick={handleSave}\n disabled={saving || testing}\n className={`px-6 py-2 bg-blue-600 text-white font-medium rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors ${saving || testing ? 'opacity-70 cursor-not-allowed' : ''\n }`}\n >\n {saving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n );\n};\n","/**\n * Email Logs Panel Component\n * \n * A reusable React component for viewing email logs.\n * Can be embedded in any admin/sysadmin page.\n */\nimport React, { useState, useEffect } from 'react';\n\ninterface EmailLog {\n id: string;\n batchId?: string;\n recipientEmail: string;\n recipientUserId?: string;\n templateId: string;\n subject?: string;\n status: 'pending' | 'sent' | 'failed' | 'bounced' | 'complained';\n provider?: string;\n providerMessageId?: string;\n errorMessage?: string;\n errorCode?: string;\n metadata?: Record<string, any>;\n createdAt: number;\n sentAt?: number;\n}\n\ninterface EmailStats {\n total: number;\n sent: number;\n failed: number;\n pending: number;\n byTemplate: Record<string, number>;\n}\n\nexport interface EmailLogsPanelProps {\n /**\n * Function to fetch email logs from the API\n * Should accept query params and return { logs, total }\n */\n fetchLogs: (params: {\n page: number;\n limit: number;\n status?: string;\n email?: string;\n template?: string;\n }) => Promise<{ logs: EmailLog[]; total: number }>;\n\n /**\n * Function to fetch email stats from the API\n * Should accept days parameter and return EmailStats\n */\n fetchStats?: (days: number) => Promise<EmailStats>;\n\n /**\n * Title for the panel (optional)\n */\n title?: string;\n\n /**\n * Number of logs per page\n */\n pageSize?: number;\n\n /**\n * Custom class name for styling\n */\n className?: string;\n}\n\nconst statusColors: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n sent: 'bg-green-100 text-green-800',\n failed: 'bg-red-100 text-red-800',\n bounced: 'bg-orange-100 text-orange-800',\n complained: 'bg-purple-100 text-purple-800',\n};\n\nexport function EmailLogsPanel({\n fetchLogs,\n fetchStats,\n title = 'Email Logs',\n pageSize = 20,\n className = ''\n}: EmailLogsPanelProps) {\n const [logs, setLogs] = useState<EmailLog[]>([]);\n const [stats, setStats] = useState<EmailStats | null>(null);\n const [loading, setLoading] = useState(true);\n const [page, setPage] = useState(1);\n const [totalPages, setTotalPages] = useState(1);\n const [statusFilter, setStatusFilter] = useState<string>('');\n const [emailFilter, setEmailFilter] = useState<string>('');\n const [templateFilter, setTemplateFilter] = useState<string>('');\n const [showStats, setShowStats] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n loadLogs();\n }, [page, statusFilter]);\n\n useEffect(() => {\n if (fetchStats && showStats) {\n loadStats();\n }\n }, [showStats]);\n\n const loadLogs = async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchLogs({\n page,\n limit: pageSize,\n status: statusFilter || undefined,\n email: emailFilter || undefined,\n template: templateFilter || undefined,\n });\n setLogs(result.logs);\n setTotalPages(Math.ceil(result.total / pageSize));\n } catch (err: any) {\n setError(err.message || 'Failed to load logs');\n } finally {\n setLoading(false);\n }\n };\n\n const loadStats = async () => {\n if (!fetchStats) return;\n try {\n const result = await fetchStats(7);\n setStats(result);\n } catch (err) {\n console.error('Failed to load stats:', err);\n }\n };\n\n const formatDate = (timestamp: number) => {\n if (!timestamp) return '-';\n return new Date(timestamp * 1000).toLocaleString();\n };\n\n const handleSearch = (e: React.FormEvent) => {\n e.preventDefault();\n setPage(1);\n loadLogs();\n };\n\n return (\n <div className={`email-logs-panel ${className}`}>\n <div className=\"flex justify-between items-center mb-4\">\n <h2 className=\"text-xl font-semibold text-gray-900\">{title}</h2>\n <div className=\"flex gap-2\">\n {fetchStats && (\n <button\n onClick={() => setShowStats(!showStats)}\n className=\"px-3 py-1.5 text-sm border border-gray-300 rounded-md hover:bg-gray-50\"\n >\n {showStats ? 'Hide Stats' : 'Show Stats'}\n </button>\n )}\n <button\n onClick={loadLogs}\n className=\"px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700\"\n >\n Refresh\n </button>\n </div>\n </div>\n\n {/* Stats Panel */}\n {showStats && stats && (\n <div className=\"mb-4 p-4 bg-gray-50 rounded-lg\">\n <h3 className=\"font-medium text-gray-700 mb-3\">Last 7 Days</h3>\n <div className=\"grid grid-cols-4 gap-4\">\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-gray-900\">{stats.total}</div>\n <div className=\"text-sm text-gray-500\">Total</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-green-600\">{stats.sent}</div>\n <div className=\"text-sm text-gray-500\">Sent</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-red-600\">{stats.failed}</div>\n <div className=\"text-sm text-gray-500\">Failed</div>\n </div>\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-yellow-600\">{stats.pending}</div>\n <div className=\"text-sm text-gray-500\">Pending</div>\n </div>\n </div>\n {Object.keys(stats.byTemplate).length > 0 && (\n <div className=\"mt-3 pt-3 border-t\">\n <div className=\"text-sm text-gray-600\">\n <strong>By Template:</strong>{' '}\n {Object.entries(stats.byTemplate).map(([template, count]) => (\n <span key={template} className=\"mr-3\">\n {template}: {count}\n </span>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Filters */}\n <form onSubmit={handleSearch} className=\"mb-4 flex gap-2 flex-wrap\">\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n >\n <option value=\"\">All Statuses</option>\n <option value=\"sent\">Sent</option>\n <option value=\"failed\">Failed</option>\n <option value=\"pending\">Pending</option>\n <option value=\"bounced\">Bounced</option>\n </select>\n <input\n type=\"text\"\n value={emailFilter}\n onChange={(e) => setEmailFilter(e.target.value)}\n placeholder=\"Filter by email...\"\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n <input\n type=\"text\"\n value={templateFilter}\n onChange={(e) => setTemplateFilter(e.target.value)}\n placeholder=\"Filter by template...\"\n className=\"px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n <button\n type=\"submit\"\n className=\"px-4 py-2 bg-gray-600 text-white rounded-md text-sm hover:bg-gray-700\"\n >\n Search\n </button>\n </form>\n\n {/* Error */}\n {error && (\n <div className=\"mb-4 p-3 bg-red-50 text-red-700 rounded-md\">\n {error}\n </div>\n )}\n\n {/* Logs Table */}\n {loading ? (\n <div className=\"text-center py-8 text-gray-500\">Loading...</div>\n ) : logs.length === 0 ? (\n <div className=\"text-center py-8 text-gray-500\">No email logs found</div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full divide-y divide-gray-200\">\n <thead className=\"bg-gray-50\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Recipient</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Template</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Subject</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Status</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Provider</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">Time</th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-gray-200\">\n {logs.map((log) => (\n <tr key={log.id} className={log.status === 'failed' ? 'bg-red-50' : ''}>\n <td className=\"px-4 py-3 text-sm\">\n <div className=\"text-gray-900\">{log.recipientEmail}</div>\n {log.recipientUserId && (\n <div className=\"text-xs text-gray-400\">User: {log.recipientUserId.substring(0, 8)}...</div>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600\">\n {log.templateId}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600 max-w-xs truncate\" title={log.subject}>\n {log.subject || '-'}\n </td>\n <td className=\"px-4 py-3\">\n <span className={`px-2 py-1 text-xs font-medium rounded-full ${statusColors[log.status] || 'bg-gray-100 text-gray-800'}`}>\n {log.status}\n </span>\n {log.errorMessage && (\n <div className=\"text-xs text-red-600 mt-1\" title={log.errorMessage}>\n {log.errorMessage.substring(0, 30)}...\n </div>\n )}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-600\">\n {log.provider || '-'}\n </td>\n <td className=\"px-4 py-3 text-sm text-gray-500\">\n {formatDate(log.createdAt)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {/* Pagination */}\n {totalPages > 1 && (\n <div className=\"mt-4 flex justify-between items-center\">\n <div className=\"text-sm text-gray-500\">\n Page {page} of {totalPages}\n </div>\n <div className=\"flex gap-2\">\n <button\n onClick={() => setPage(p => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"px-3 py-1.5 border border-gray-300 rounded-md text-sm disabled:opacity-50\"\n >\n Previous\n </button>\n <button\n onClick={() => setPage(p => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"px-3 py-1.5 border border-gray-300 rounded-md text-sm disabled:opacity-50\"\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_marked","React","import_react","e","React","normalizeNewlines","React","import_react","React","import_react","React"]}
|