import React, { useState } from 'react'; import { useEditor } from '@craftjs/core'; import { useEditorConfig } from '../../state/EditorConfigContext'; import { useSitesmith } from '../../hooks/useSitesmith'; import { useApplyAiResponse } from '../../utils/apply-ai-response'; import { summarizeCanvas } from '../../utils/canvas-summary'; import { UpgradeBanner } from './UpgradeBanner'; import { ScopeConfirmDialog } from './ScopeConfirmDialog'; import { MessageList } from './MessageList'; import { ChatInput } from './ChatInput'; import { SitesmithResponse } from '../../types/sitesmith'; interface Props { onClose: () => void; } export const SitesmithModal: React.FC = ({ onClose }) => { const cfg = useEditorConfig(); const siteId = cfg.whpConfig?.siteId ?? 0; const { query } = useEditor(); const { summary, messages, send, loading } = useSitesmith(siteId); const apply = useApplyAiResponse(); const [busy, setBusy] = useState(false); const [pendingReplace, setPendingReplace] = useState(null); const [error, setError] = useState(null); const canChat = summary && (summary.status === 'OK_BONUS' || summary.status === 'OK_MONTHLY'); const overlay: React.CSSProperties = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.8)', zIndex: 9000, display: 'flex', alignItems: 'center', justifyContent: 'center' }; const panel: React.CSSProperties = { background: '#0f0f17', border: '1px solid #27272a', borderRadius: 12, width: 'min(720px, 90vw)', maxHeight: '90vh', display: 'flex', flexDirection: 'column' }; const header: React.CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px 18px', borderBottom: '1px solid #27272a' }; const body: React.CSSProperties = { flex: 1, padding: '14px 18px', overflowY: 'auto', display: 'flex', flexDirection: 'column' }; const footer: React.CSSProperties = { padding: '12px 18px', borderTop: '1px solid #27272a' }; const closeBtn:React.CSSProperties = { background: 'transparent', color: '#a1a1aa', border: 'none', fontSize: 18, cursor: 'pointer' }; const errBox: React.CSSProperties = { background: '#3b1d1d', border: '1px solid #7f1d1d', color: '#fecaca', padding: '8px 12px', borderRadius: 6, marginBottom: 10, fontSize: 13 }; const handleSend = async (text: string) => { setBusy(true); setError(null); try { const canvas = summarizeCanvas(query.getSerializedNodes()); const result = await send(text, canvas); if (!result.ok) { setError(result.message || 'Failed'); return; } if (result.response.type === 'replace' && result.response.scope === 'site') { setPendingReplace(result.response); return; } const applied = await apply(result.response); if (!applied.ok) setError(applied.message || 'Apply failed'); } catch (e: any) { setError(String(e?.message ?? e)); } finally { setBusy(false); } }; const confirmReplace = async () => { if (!pendingReplace) return; const r = await apply(pendingReplace); setPendingReplace(null); if (!r.ok) setError(r.message || 'Apply failed'); }; return (
✨ Sitesmith
{summary && summary.enabled && (
{summary.monthly_used} / {summary.monthly_cap} this month {summary.bonus_credits > 0 && ` • +${summary.bonus_credits} bonus`}
)}
{error &&
{error}
} {loading ?
Loading…
: }
setPendingReplace(null)} />
); };