File size: 10,233 Bytes
b33923b
c59bca4
b33923b
 
 
 
 
 
 
 
 
c59bca4
 
 
 
 
 
b33923b
 
 
 
 
 
 
 
c59bca4
 
 
 
 
 
 
b33923b
 
 
 
 
c59bca4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b33923b
 
 
c59bca4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b33923b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import React, { useState } from 'react';
import { Plus, Sparkles, MoreVertical, Trash2, Edit2, Check, LayoutGrid, Rocket, Github, Loader2, RefreshCcw, MessageSquarePlus } from 'lucide-react';
import { Note } from '../types';

interface NotesPanelProps {
  notes: Note[];
  onAddNote: () => void;
  onUpdateNote: (note: Note) => void;
  onDeleteNote: (id: string) => void;
  onUseTemplate: (note: Note) => void;
  onGenerateSummary: (note: Note) => void;
  queue?: string[];
  hfTimerQueue?: { templates: string[], nextExecutionTime: number };
  onHuggingFaceCue?: () => void;
  onRefreshTemplates?: () => void;
  isRefreshing?: boolean;
  onOpenNewSession?: () => void;
}

export const NotesPanel: React.FC<NotesPanelProps> = ({
  notes,
  onAddNote,
  onUpdateNote,
  onDeleteNote,
  onUseTemplate,
  onGenerateSummary,
  queue = [],
  hfTimerQueue,
  onHuggingFaceCue,
  onRefreshTemplates,
  isRefreshing,
  onOpenNewSession
}) => {
  const [editingId, setEditingId] = useState<string | null>(null);

  return (
    <div className="flex flex-col h-full bg-gray-50 border-r border-gray-200">
      <div className="p-4 border-b border-gray-200 bg-white sticky top-0 z-10">
        <div className="flex justify-between items-center mb-4">
            <h2 className="font-semibold text-gray-800 text-lg">Message Templates</h2>
            <div className="flex items-center gap-2">
                {onRefreshTemplates && (
                    <button
                        onClick={onRefreshTemplates}
                        disabled={isRefreshing}
                        className="p-2 bg-indigo-50 text-indigo-600 hover:bg-indigo-100 rounded-full transition-all"
                        title="Sync Templates"
                    >
                        <RefreshCcw className={`w-4 h-4 ${isRefreshing ? 'animate-spin' : ''}`} />
                    </button>
                )}
                {onOpenNewSession && (
                    <button
                        onClick={onOpenNewSession}
                        className="p-2 bg-green-50 text-green-600 hover:bg-green-100 rounded-full transition-all"
                        title="New Session"
                    >
                        <MessageSquarePlus className="w-4 h-4" />
                    </button>
                )}
                <button
                    onClick={onAddNote}
                    className="p-2 bg-yellow-400 hover:bg-yellow-500 text-yellow-900 rounded-full shadow-sm transition-all"
                    title="New Template"
                >
                    <Plus className="w-5 h-5" />
                </button>
            </div>
        </div>

        {/* HuggingFace Cue Button */}
        {onHuggingFaceCue && (
            <button
                onClick={onHuggingFaceCue}
                className="w-full bg-gradient-to-r from-indigo-600 to-violet-600 text-white p-2.5 rounded-xl text-sm font-bold flex items-center justify-center gap-2 hover:opacity-90 transition-all shadow-md mb-2"
            >
                <Rocket className="w-4 h-4" />
                HF Deployment Cue
            </button>
        )}

        {/* Queue Status */}
        {hfTimerQueue && hfTimerQueue.templates.length > 0 && (
            <div className="bg-indigo-50 border border-indigo-100 rounded-lg p-2 flex items-center gap-2 mb-2">
                <div className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse" />
                <span className="text-[10px] font-bold text-indigo-700 uppercase tracking-wider">
                    Auto-Queue: {hfTimerQueue.templates.length} waiting (runs in {Math.max(0, Math.ceil((hfTimerQueue.nextExecutionTime - Date.now()) / 60000))} mins)
                </span>
            </div>
        )}

        {queue.length > 0 && (
            <div className="bg-gray-100 rounded-lg p-2 flex items-center gap-2">
                <div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
                <span className="text-[10px] font-bold text-gray-500 uppercase tracking-wider">
                    Cue: {queue.length} templates pending
                </span>
            </div>
        )}
      </div>

      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {/* Load Templates Button - Only show if no remote templates exist and handler is provided */}
        {onRefreshTemplates && !notes.some(n => n.id.startsWith('github-')) && (
            <div className="bg-white rounded-xl border-2 border-dashed border-gray-200 p-8 flex flex-col items-center justify-center text-center space-y-4 hover:border-indigo-300 transition-colors">
                <div className="p-3 bg-indigo-50 text-indigo-600 rounded-full">
                    {isRefreshing ? <Loader2 className="w-8 h-8 animate-spin" /> : <Github className="w-8 h-8" />}
                </div>
                <div>
                    <h3 className="font-bold text-gray-800">No Remote Templates</h3>
                    <p className="text-sm text-gray-500 max-w-[200px] mx-auto">
                        Connect to GitHub to load your shared message templates.
                    </p>
                </div>
                <button
                    onClick={onRefreshTemplates}
                    disabled={isRefreshing}
                    className="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-lg font-semibold text-sm transition-all shadow-sm flex items-center gap-2"
                >
                    {isRefreshing ? 'Loading...' : 'Load Templates'}
                </button>
            </div>
        )}

        {notes.map((note) => (
          <div
            key={note.id}
            className={`group relative bg-white rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition-all duration-200 ${
              editingId === note.id ? 'ring-2 ring-indigo-500 border-transparent' : ''
            }`}
          >
            <div className="p-4">
              {editingId === note.id ? (
                <div className="space-y-2">
                  <input
                    type="text"
                    value={note.title}
                    onChange={(e) => onUpdateNote({ ...note, title: e.target.value })}
                    className="w-full font-bold text-gray-800 bg-transparent outline-none placeholder-gray-400"
                    placeholder="Title"
                    autoFocus
                  />
                  <textarea
                    value={note.content}
                    onChange={(e) => onUpdateNote({ ...note, content: e.target.value })}
                    className="w-full text-sm text-gray-600 bg-transparent outline-none resize-none h-24 placeholder-gray-400"
                    placeholder="Type your message template..."
                  />
                  <div className="flex justify-end gap-2 pt-2">
                     <button
                        onClick={() => setEditingId(null)}
                        className="p-1.5 text-green-600 hover:bg-green-50 rounded-full"
                        title="Done Editing"
                     >
                       <Check className="w-4 h-4" />
                     </button>
                  </div>
                </div>
              ) : (
                <>
                  <h3 className="font-bold text-gray-800 mb-2 truncate">{note.title || 'Untitled'}</h3>
                  <p className="text-sm text-gray-600 line-clamp-3 mb-3 whitespace-pre-wrap">
                    {note.content || 'Empty note'}
                  </p>

                  {/* AI Summary Section */}
                  {note.summary ? (
                    <div className="bg-indigo-50 rounded-lg p-2 mb-3">
                      <div className="flex items-center gap-1.5 text-xs font-semibold text-indigo-700 mb-1">
                        <Sparkles className="w-3 h-3" />
                        <span>AI Summary</span>
                      </div>
                      <div className="text-xs text-indigo-600 whitespace-pre-wrap leading-relaxed">
                        {note.summary}
                      </div>
                    </div>
                  ) : (
                    <button
                        onClick={(e) => {
                            e.stopPropagation();
                            onGenerateSummary(note);
                        }}
                        className="text-xs flex items-center gap-1 text-gray-400 hover:text-indigo-600 transition-colors mb-3"
                    >
                        <Sparkles className="w-3 h-3" />
                        Generate Summary
                    </button>
                  )}

                  <div className="flex items-center justify-between mt-2 pt-2 border-t border-gray-100 opacity-0 group-hover:opacity-100 transition-opacity">
                    <div className="flex gap-1">
                       <button
                        onClick={(e) => {
                          e.stopPropagation();
                          setEditingId(note.id);
                        }}
                        className="p-1.5 text-gray-400 hover:text-indigo-600 hover:bg-gray-100 rounded-lg"
                        title="Edit"
                      >
                        <Edit2 className="w-4 h-4" />
                      </button>
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          onDeleteNote(note.id);
                        }}
                        className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-gray-100 rounded-lg"
                        title="Delete"
                      >
                        <Trash2 className="w-4 h-4" />
                      </button>
                    </div>
                    
                    <button
                      onClick={() => onUseTemplate(note)}
                      className="text-xs font-medium bg-gray-900 text-white px-3 py-1.5 rounded-lg hover:bg-black transition-colors"
                    >
                      Use Template
                    </button>
                  </div>
                </>
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};