import React, { useEffect } from 'react'; import { ActivityBar, Sidebar, Editor, StatusBar, Panel, ToastContainer, showToast } from './components'; import { useAppStore, PostData, MediaData, TaskProgress } from './store'; import './App.css'; const App: React.FC = () => { const { setPosts, setMedia, addPost, updatePost, removePost, addMedia, updateMedia, removeMedia, setTasks, updateTask, setSyncStatus, setSyncConfigured, setPendingChanges, setLoading, toggleSidebar, togglePanel, setActiveView, setSelectedPost, } = useAppStore(); // Load initial data useEffect(() => { const loadData = async () => { setLoading(true); try { // First, get active project to set the correct context in backend engines await window.electronAPI?.projects.getActive(); // Load posts (now with correct project context) const posts = await window.electronAPI?.posts.getAll(); if (posts) { setPosts(posts as PostData[]); } // Load media const media = await window.electronAPI?.media.getAll(); if (media) { setMedia(media as MediaData[]); } // Check sync status const syncConfigured = await window.electronAPI?.sync.isConfigured(); setSyncConfigured(syncConfigured || false); // Get pending changes count const pending = await window.electronAPI?.sync.getPendingCount(); if (pending) { setPendingChanges(pending); } // Load tasks const tasks = await window.electronAPI?.tasks.getAll(); if (tasks) { setTasks(tasks as TaskProgress[]); } } catch (error) { console.error('Failed to load initial data:', error); } finally { setLoading(false); } }; loadData(); }, []); // Set up event listeners for real-time updates useEffect(() => { const unsubscribers: Array<() => void> = []; // Post events unsubscribers.push( window.electronAPI?.on('post:created', (post: unknown) => { addPost(post as PostData); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('post:updated', (post: unknown) => { const p = post as PostData; updatePost(p.id, p); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('post:deleted', (id: unknown) => { removePost(id as string); }) || (() => {}) ); // Media events unsubscribers.push( window.electronAPI?.on('media:imported', (media: unknown) => { addMedia(media as MediaData); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('media:updated', (media: unknown) => { const m = media as MediaData; updateMedia(m.id, m); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('media:deleted', (id: unknown) => { removeMedia(id as string); }) || (() => {}) ); // Sync events unsubscribers.push( window.electronAPI?.on('sync:started', () => { setSyncStatus('syncing'); showToast.loading('Syncing...'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('sync:completed', async () => { setSyncStatus('idle'); showToast.dismiss(); showToast.success('Sync completed'); const pending = await window.electronAPI?.sync.getPendingCount(); if (pending) { setPendingChanges(pending); } }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('sync:failed', () => { setSyncStatus('error'); showToast.dismiss(); showToast.error('Sync failed'); }) || (() => {}) ); // Task events unsubscribers.push( window.electronAPI?.on('task:progress', (task: unknown) => { const t = task as TaskProgress; updateTask(t.taskId, t); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('task:completed', (task: unknown) => { const t = task as TaskProgress; updateTask(t.taskId, t); showToast.success(`Task completed: ${t.message}`); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('task:failed', (task: unknown) => { const t = task as TaskProgress; updateTask(t.taskId, t); showToast.error(`Task failed: ${t.error || t.message}`); }) || (() => {}) ); // Menu events unsubscribers.push( window.electronAPI?.on('menu:newPost', async () => { const post = await window.electronAPI?.posts.create({ title: 'New Post', content: '# New Post\n\nStart writing...', }); if (post) { setSelectedPost((post as PostData).id); setActiveView('posts'); } }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:importMedia', () => { window.electronAPI?.media.importDialog(); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:toggleSidebar', () => { toggleSidebar(); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:togglePanel', () => { togglePanel(); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:viewPosts', () => { setActiveView('posts'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:viewMedia', () => { setActiveView('media'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:syncNow', () => { window.electronAPI?.sync.start('bidirectional'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:pushChanges', () => { window.electronAPI?.sync.start('push'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:pullChanges', () => { window.electronAPI?.sync.start('pull'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:configureSync', () => { setActiveView('settings'); }) || (() => {}) ); unsubscribers.push( window.electronAPI?.on('menu:rebuildDatabase', async () => { await window.electronAPI?.posts.rebuildFromFiles(); await window.electronAPI?.media.rebuildFromFiles(); // Reload data const posts = await window.electronAPI?.posts.getAll(); if (posts) { setPosts(posts as PostData[]); } const media = await window.electronAPI?.media.getAll(); if (media) { setMedia(media as MediaData[]); } }) || (() => {}) ); return () => { unsubscribers.forEach(unsub => unsub()); }; }, []); return (