import * as React from 'react'; import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; import { Textarea } from '@/components/ui/textarea'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Info } from 'lucide-react'; import { cn } from '@/components/ui/utils'; const quillModules = { toolbar: [ [{ header: [1, 2, 3, false] }], ['bold', 'italic', 'underline'], [{ list: 'ordered' }, { list: 'bullet' }], ['link'], ['blockquote'], ['clean'], ], }; const quillFormats = ['header', 'bold', 'italic', 'underline', 'list', 'bullet', 'link', 'blockquote']; /** Handlebars helpers/partials or full HTML docs must be edited as source — rich editors strip or corrupt them. */ export function requiresAdvancedHtmlEditing(html: string): boolean { const s = html || ''; return ( /\{\{\s*[>#\/]/.test(s) || /\{\{>\s*\w+/.test(s) || /]/i.test(s) || /<\/html>/i.test(s) || /]/i.test(s) ); } export type EmailTemplateBodyEditorHandle = { insertPlaceholder: (placeholder: string) => void; }; type Props = { value: string; onChange: (html: string) => void; /** visual | html */ tab: string; onTabChange: (v: string) => void; textareaRef: React.RefObject; }; export const EmailTemplateBodyEditor = React.forwardRef( ({ value, onChange, tab, onTabChange, textareaRef }, ref) => { const quillRef = React.useRef(null); const advanced = React.useMemo(() => requiresAdvancedHtmlEditing(value), [value]); React.useImperativeHandle(ref, () => ({ insertPlaceholder: (placeholder: string) => { const token = `{{${placeholder}}}`; if (tab === 'html' && textareaRef.current) { const el = textareaRef.current; const start = el.selectionStart ?? 0; const end = el.selectionEnd ?? 0; const next = value.slice(0, start) + token + value.slice(end); onChange(next); requestAnimationFrame(() => { el.focus(); const pos = start + token.length; el.setSelectionRange(pos, pos); }); return; } const editor = quillRef.current?.getEditor?.(); if (!editor) return; const range = editor.getSelection(true); const idx = range?.index ?? editor.getLength(); editor.insertText(idx, token, 'user'); }, })); return (
Rich text HTML source {advanced && ( This template uses layout partials ({'{{> ...}}'}), block helpers, or a full HTML document. Edit it in HTML source so nothing is stripped. Use placeholders on the left to insert fields safely. )}

Use headings, lists, and links. Insert dynamic fields from Available Placeholders on the left.