File size: 4,418 Bytes
ae4ceef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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>
  );
};