import React, { useCallback, useState, useEffect, useRef } from 'react'; import { useEditor } from '@craftjs/core'; import { useEditorConfig } from '../../state/EditorConfigContext'; import { useWhpApi } from '../../hooks/useWhpApi'; import { usePages } from '../../state/PageContext'; import { DeviceMode } from '../../types'; import { TemplateModal } from './TemplateModal'; import { HeadCodeModal } from './HeadCodeModal'; import { SitesmithButton } from '../sitesmith/SitesmithButton'; interface TopBarProps { device: DeviceMode; onDeviceChange: (device: DeviceMode) => void; } export const TopBar: React.FC = ({ device, onDeviceChange }) => { const { whpConfig, isWHP } = useEditorConfig(); const { actions, query, canUndo, canRedo } = useEditor((_state, query) => ({ canUndo: query.history.canUndo(), canRedo: query.history.canRedo(), })); const { save, publish, load } = useWhpApi(); const { headerPage, footerPage } = usePages(); const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle'); const [publishStatus, setPublishStatus] = useState<'idle' | 'publishing' | 'published' | 'error'>('idle'); const [isDraft, setIsDraft] = useState(false); const [templateModalOpen, setTemplateModalOpen] = useState(false); const [headCodeModalOpen, setHeadCodeModalOpen] = useState(false); const [sitesmithOpen, setSitesmithOpen] = useState(false); const saveTimeoutRef = useRef | null>(null); const publishTimeoutRef = useRef | null>(null); const hasLoadedRef = useRef(false); // Load saved state on mount useEffect(() => { if (!isWHP || hasLoadedRef.current) return; hasLoadedRef.current = true; load().catch((e) => { console.warn('Failed to load project from WHP API:', e); }); }, [isWHP, load]); // Auto-save every 30 seconds useEffect(() => { if (!isWHP) return; const interval = setInterval(() => { save() .then((result) => { if (result?.success) { setSaveStatus('saved'); setIsDraft(true); if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current); saveTimeoutRef.current = setTimeout(() => setSaveStatus('idle'), 2000); } }) .catch(() => { // Silent fail for auto-save }); }, 30000); return () => clearInterval(interval); }, [isWHP, save]); const handleSave = useCallback(async () => { setSaveStatus('saving'); try { const result = await save(); if (result?.success) { setSaveStatus('saved'); setIsDraft(true); if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current); saveTimeoutRef.current = setTimeout(() => setSaveStatus('idle'), 2500); } else { setSaveStatus('error'); if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current); saveTimeoutRef.current = setTimeout(() => setSaveStatus('idle'), 3000); } } catch (e) { console.error('Save failed:', e); setSaveStatus('error'); if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current); saveTimeoutRef.current = setTimeout(() => setSaveStatus('idle'), 3000); } }, [save]); const handlePublish = useCallback(async () => { setPublishStatus('publishing'); try { const result = await publish(); if (result?.success) { setPublishStatus('published'); setIsDraft(false); if (publishTimeoutRef.current) clearTimeout(publishTimeoutRef.current); publishTimeoutRef.current = setTimeout(() => setPublishStatus('idle'), 3000); } else { setPublishStatus('error'); if (publishTimeoutRef.current) clearTimeout(publishTimeoutRef.current); publishTimeoutRef.current = setTimeout(() => setPublishStatus('idle'), 3000); } } catch (e) { console.error('Publish failed:', e); setPublishStatus('error'); if (publishTimeoutRef.current) clearTimeout(publishTimeoutRef.current); publishTimeoutRef.current = setTimeout(() => setPublishStatus('idle'), 3000); } }, [publish]); // Cleanup timeouts on unmount useEffect(() => { return () => { if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current); if (publishTimeoutRef.current) clearTimeout(publishTimeoutRef.current); }; }, []); return ( ); };