import React, { useEffect, useState } from 'react'; import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Placeholder from '@tiptap/extension-placeholder'; import Link from '@tiptap/extension-link'; import TextAlign from '@tiptap/extension-text-align'; import Image from '@tiptap/extension-image'; import { ButtonExtension } from './tiptap-button-extension'; import { openWPMediaImage } from '@/lib/wp-media'; import { Bold, Italic, List, ListOrdered, Link as LinkIcon, AlignLeft, AlignCenter, AlignRight, ImageIcon, MousePointer, Undo, Redo, } from 'lucide-react'; import { Button } from './button'; import { Input } from './input'; import { Label } from './label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from './dialog'; import { __ } from '@/lib/i18n'; interface RichTextEditorProps { content: string; onChange: (content: string) => void; placeholder?: string; variables?: string[]; onVariableInsert?: (variable: string) => void; } export function RichTextEditor({ content, onChange, placeholder = __('Start typing...'), variables = [], onVariableInsert, }: RichTextEditorProps) { const editor = useEditor({ extensions: [ StarterKit, Placeholder.configure({ placeholder, }), Link.configure({ openOnClick: false, HTMLAttributes: { class: 'text-primary underline', }, }), TextAlign.configure({ types: ['heading', 'paragraph'], }), Image.configure({ inline: true, HTMLAttributes: { class: 'max-w-full h-auto rounded', }, }), ButtonExtension, ], content, onUpdate: ({ editor }) => { onChange(editor.getHTML()); }, editorProps: { attributes: { class: 'prose prose-sm max-w-none focus:outline-none min-h-[200px] px-4 py-3', }, }, }); // Update editor content when prop changes (fix for default value not showing) useEffect(() => { if (editor && content) { const currentContent = editor.getHTML(); // Only update if content is different (avoid infinite loops) if (content !== currentContent) { console.log('RichTextEditor: Updating content', { content, currentContent }); editor.commands.setContent(content); } } }, [content, editor]); if (!editor) { return null; } const insertVariable = (variable: string) => { editor.chain().focus().insertContent(`{${variable}}`).run(); if (onVariableInsert) { onVariableInsert(variable); } }; const setLink = () => { const url = window.prompt(__('Enter URL:')); if (url) { editor.chain().focus().setLink({ href: url }).run(); } }; const [buttonDialogOpen, setButtonDialogOpen] = useState(false); const [buttonText, setButtonText] = useState('Click Here'); const [buttonHref, setButtonHref] = useState('{order_url}'); const [buttonStyle, setButtonStyle] = useState<'solid' | 'outline'>('solid'); const addImage = () => { openWPMediaImage((file) => { editor.chain().focus().setImage({ src: file.url, alt: file.alt || file.title, title: file.title, }).run(); }); }; const openButtonDialog = () => { setButtonText('Click Here'); setButtonHref('{order_url}'); setButtonStyle('solid'); setButtonDialogOpen(true); }; const insertButton = () => { editor.chain().focus().setButton({ text: buttonText, href: buttonHref, style: buttonStyle }).run(); setButtonDialogOpen(false); }; const getActiveHeading = () => { if (editor.isActive('heading', { level: 1 })) return 'h1'; if (editor.isActive('heading', { level: 2 })) return 'h2'; if (editor.isActive('heading', { level: 3 })) return 'h3'; if (editor.isActive('heading', { level: 4 })) return 'h4'; return 'p'; }; const setHeading = (value: string) => { if (value === 'p') { editor.chain().focus().setParagraph().run(); } else { const level = parseInt(value.replace('h', '')) as 1 | 2 | 3 | 4; editor.chain().focus().setHeading({ level }).run(); } }; return (
{/* Toolbar */}
{/* Heading Selector */}
{/* Editor */} {/* Variables */} {variables.length > 0 && (
{__('Available Variables:')}
{variables.map((variable) => ( ))}
)} {/* Button Dialog */} {__('Insert Button')} {__('Add a styled button to your content. Use variables for dynamic links.')}
setButtonText(e.target.value)} placeholder={__('e.g., View Order')} />
setButtonHref(e.target.value)} placeholder="{order_url}" /> {variables.length > 0 && (
{variables.map((variable) => ( setButtonHref(buttonHref + `{${variable}}`)} > {`{${variable}}`} ))}
)}
); }