File size: 4,776 Bytes
81ff144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useState, useEffect } from 'react';
import { supabase } from '../services/supabase';
import { Save, CheckCircle, XCircle, ThumbsUp, ThumbsDown } from 'lucide-react';
import { motion } from 'framer-motion';

interface TaskEditorProps {
  taskId: string;
  onClose: () => void;
}

interface EditableTask {
  id: string;
  title: string;
  output_data: unknown;
}

const TaskEditor: React.FC<TaskEditorProps> = ({ taskId, onClose }) => {
  const [task, setTask] = useState<EditableTask | null>(null);
  const [editedOutput, setEditedOutput] = useState('');
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    const fetchTask = async () => {
      const { data } = await supabase
        .from('tasks')
        .select('id,title,output_data')
        .eq('id', taskId)
        .single();
      
      if (data) {
        setTask(data);
        setEditedOutput(JSON.stringify(data.output_data, null, 2));
      }
    };
    fetchTask();
  }, [taskId]);

  const handleSave = async () => {
    setSaving(true);
    try {
      const parsed = JSON.parse(editedOutput);
      await supabase
        .from('tasks')
        .update({ output_data: parsed })
        .eq('id', taskId);
      alert('Task updated successfully!');
    } catch {
      alert('Invalid JSON format');
    }
    setSaving(false);
  };

  const handleFeedback = async (rating: number) => {
    await supabase.from('task_feedback').upsert({
      task_id: taskId,
      rating: rating
    });
    alert(rating === 1 ? 'Glad you liked it!' : 'Feedback recorded. We will use this to improve.');
  };

  const handleApprove = async () => {
    await supabase.from('tasks').update({ status: 'done' }).eq('id', taskId);
    onClose();
  };

  if (!task) return null;

  return (
    <motion.div 
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      style={{ 
        position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, 
        background: 'rgba(0,0,0,0.8)', backdropFilter: 'blur(8px)',
        zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '2rem'
      }}
    >
      <motion.div 
        initial={{ y: 50 }}
        animate={{ y: 0 }}
        className="glass-panel task-editor-panel"
        style={{ width: '100%', maxWidth: '800px', maxHeight: '90vh', display: 'flex', flexDirection: 'column' }}
      >
        <div style={{ padding: 'var(--space-lg)', borderBottom: '1px solid var(--glass-border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <h2 style={{ fontSize: '1.5rem' }}>{task.title}</h2>
            <p style={{ color: 'var(--text-dim)', fontSize: '0.9rem' }}>Review and refine agent output</p>
          </div>
          <button onClick={onClose}><XCircle size={24} color="var(--text-muted)" /></button>
        </div>

        <div style={{ flex: 1, padding: 'var(--space-lg)', overflowY: 'auto' }}>
          <label style={{ display: 'block', marginBottom: 'var(--space-sm)', fontWeight: 600 }}>Raw Output (JSON)</label>
          <textarea
            className="task-editor-textarea"
            value={editedOutput}
            onChange={(e) => setEditedOutput(e.target.value)}
            style={{ 
              width: '100%', height: '400px', background: 'rgba(0,0,0,0.3)', 
              color: 'var(--accent)', fontFamily: 'monospace', padding: '1rem',
              border: '1px solid var(--glass-border)', borderRadius: 'var(--radius-md)',
              outline: 'none', resize: 'none'
            }}
          />
        </div>

        <div style={{ padding: 'var(--space-lg)', borderTop: '1px solid var(--glass-border)', display: 'flex', gap: 'var(--space-md)', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ display: 'flex', gap: 'var(--space-md)' }}>
            <button className="btn btn-glass" style={{ padding: '0.5rem' }} onClick={() => handleFeedback(1)}>
              <ThumbsUp size={18} color="var(--success)" />
            </button>
            <button className="btn btn-glass" style={{ padding: '0.5rem' }} onClick={() => handleFeedback(-1)}>
              <ThumbsDown size={18} color="var(--danger)" />
            </button>
          </div>

          <div style={{ display: 'flex', gap: 'var(--space-md)' }}>
            <button className="btn btn-glass" onClick={handleSave} disabled={saving}>
              <Save size={18} />
              {saving ? 'Saving...' : 'Save Draft'}
            </button>
            <button className="btn btn-primary" onClick={handleApprove}>
              <CheckCircle size={18} />
              Approve & Finalize
            </button>
          </div>
        </div>
      </motion.div>
    </motion.div>
  );
};

export default TaskEditor;