import { useState, useEffect, useRef } from 'react'; import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query'; import { X, Save, Loader2, RotateCcw, Plus, Eye } from 'lucide-react'; import { api } from '../api/client'; import type { NotificationTemplate, NotificationTemplateUpdate } from '../api/client'; import { Button } from './Button'; interface NotificationTemplateEditorProps { template: NotificationTemplate; onClose: () => void; } export function NotificationTemplateEditor({ template, onClose }: NotificationTemplateEditorProps) { const queryClient = useQueryClient(); const bodyRef = useRef(null); const [titleTemplate, setTitleTemplate] = useState(template.title_template); const [bodyTemplate, setBodyTemplate] = useState(template.body_template); const [error, setError] = useState(null); const [showPreview, setShowPreview] = useState(true); // Fetch variables for this event type const { data: variablesData } = useQuery({ queryKey: ['template-variables'], queryFn: api.getTemplateVariables, }); // Get variables for this template's event type const eventVariables = variablesData?.find(v => v.event_type === template.event_type); // Live preview const { data: preview, isLoading: previewLoading } = useQuery({ queryKey: ['template-preview', template.event_type, titleTemplate, bodyTemplate], queryFn: () => api.previewTemplate({ event_type: template.event_type, title_template: titleTemplate, body_template: bodyTemplate, }), enabled: showPreview && titleTemplate.length > 0 && bodyTemplate.length > 0, }); // Close on Escape key useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [onClose]); // Update mutation const updateMutation = useMutation({ mutationFn: (data: NotificationTemplateUpdate) => api.updateNotificationTemplate(template.id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notification-templates'] }); onClose(); }, onError: (err: Error) => { setError(err.message); }, }); // Reset mutation const resetMutation = useMutation({ mutationFn: () => api.resetNotificationTemplate(template.id), onSuccess: (resetTemplate) => { setTitleTemplate(resetTemplate.title_template); setBodyTemplate(resetTemplate.body_template); queryClient.invalidateQueries({ queryKey: ['notification-templates'] }); }, onError: (err: Error) => { setError(err.message); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setError(null); if (!titleTemplate.trim()) { setError('Title is required'); return; } if (!bodyTemplate.trim()) { setError('Body is required'); return; } updateMutation.mutate({ title_template: titleTemplate, body_template: bodyTemplate, }); }; const insertVariable = (variable: string) => { const textarea = bodyRef.current; if (!textarea) return; const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = bodyTemplate; const before = text.substring(0, start); const after = text.substring(end); const newValue = before + `{${variable}}` + after; setBodyTemplate(newValue); // Restore focus and cursor position setTimeout(() => { textarea.focus(); const newCursor = start + variable.length + 2; textarea.setSelectionRange(newCursor, newCursor); }, 0); }; const hasChanges = titleTemplate !== template.title_template || bodyTemplate !== template.body_template; return (
{/* Header */}

Edit Template: {template.name}

{/* Content */}
{error && (
{error}
)} {/* Title */}
setTitleTemplate(e.target.value)} className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded text-white focus:outline-none focus:ring-1 focus:ring-bambu-green" placeholder="Notification title..." />
{/* Body */}