Spaces:
Sleeping
Sleeping
| import React, { useEffect, useState } from 'react'; | |
| import { useStore } from '@/store/useStore'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { Bell, Folder, Upload, X } from 'lucide-react'; | |
| import { invoke } from '@tauri-apps/api/core'; | |
| import { listen } from '@tauri-apps/api/event'; | |
| export const FileWatcher: React.FC = () => { | |
| const { t } = useTranslation(); | |
| const [isTauri, setIsTauri] = useState(false); | |
| const [watchedPath, setWatchedPath] = useState<string | null>(null); | |
| const [isWatching, setIsWatching] = useState(false); | |
| const [notifications, setNotifications] = useState<any[]>([]); | |
| const { addChatMessage } = useStore(); | |
| useEffect(() => { | |
| // Check if running in Tauri | |
| if ((window as any).__TAURI_INTERNALS__) { | |
| setIsTauri(true); | |
| } | |
| }, []); | |
| useEffect(() => { | |
| if (!isTauri) return; | |
| // Listen for file-change events from Tauri | |
| const unlisten = listen('file-changed', async (event: any) => { | |
| const { path, filename, action } = event.payload; | |
| if (action === 'create' || action === 'modify') { | |
| const newNotif = { | |
| id: Date.now(), | |
| filename, | |
| path, | |
| status: 'detected', | |
| timestamp: new Date().toLocaleTimeString() | |
| }; | |
| setNotifications(prev => [newNotif, ...prev].slice(0, 5)); | |
| // Auto-upload and parse logic (mocked for now) | |
| // In a real app, we would read the file content via Tauri fs and upload to server | |
| addChatMessage({ | |
| id: `file-${Date.now()}`, | |
| role: 'system', | |
| content: `Detected file: ${filename}. Automatically parsing...`, | |
| timestamp: Date.now() | |
| }); | |
| } | |
| }); | |
| return () => { | |
| unlisten.then(f => f()); | |
| }; | |
| }, [isTauri, addChatMessage]); | |
| const startWatching = async () => { | |
| try { | |
| // In a real Tauri app, we'd use a dialog to pick a folder | |
| // For this demo, we'll use a mocked path or the downloads folder | |
| const path = await invoke('start_watching', { path: '/Users/by/Downloads/codex_watch' }); | |
| setWatchedPath(path as string); | |
| setIsWatching(true); | |
| } catch (err) { | |
| console.error('Failed to start watching:', err); | |
| } | |
| }; | |
| const stopWatching = async () => { | |
| try { | |
| await invoke('stop_watching'); | |
| setIsWatching(false); | |
| } catch (err) { | |
| console.error('Failed to stop watching:', err); | |
| } | |
| }; | |
| if (!isTauri) return null; | |
| return ( | |
| <div className="fixed bottom-4 right-4 z-50 flex flex-col items-end gap-2"> | |
| {/* Notifications */} | |
| {notifications.map(n => ( | |
| <div key={n.id} className="bg-white dark:bg-slate-800 p-3 rounded-lg shadow-lg border border-indigo-500/30 flex items-center gap-3 animate-in fade-in slide-in-from-right-4"> | |
| <div className="p-2 bg-indigo-100 dark:bg-indigo-900/50 rounded-full text-indigo-600"> | |
| <Upload size={16} /> | |
| </div> | |
| <div className="flex flex-col"> | |
| <span className="text-xs font-bold truncate max-w-[150px]">{n.filename}</span> | |
| <span className="text-[10px] text-slate-500">{n.timestamp}</span> | |
| </div> | |
| <button onClick={() => setNotifications(prev => prev.filter(x => x.id !== n.id))} className="text-slate-400 hover:text-slate-600"> | |
| <X size={14} /> | |
| </button> | |
| </div> | |
| ))} | |
| {/* Control Panel */} | |
| <div className="bg-white dark:bg-slate-800 p-2 rounded-full shadow-xl border border-slate-200 dark:border-slate-700 flex items-center gap-2"> | |
| {isWatching ? ( | |
| <div className="flex items-center gap-2 px-3"> | |
| <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" /> | |
| <span className="text-xs font-medium text-slate-600 dark:text-slate-300">Watching...</span> | |
| <button | |
| onClick={stopWatching} | |
| className="p-1 hover:bg-slate-100 dark:hover:bg-slate-700 rounded-full text-red-500" | |
| > | |
| <X size={14} /> | |
| </button> | |
| </div> | |
| ) : ( | |
| <button | |
| onClick={startWatching} | |
| className="flex items-center gap-2 px-4 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-full text-xs font-bold transition-all" | |
| > | |
| <Folder size={14} /> | |
| Start File Watcher | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| }; | |