| import { useState } from 'react'; | |
| import type { Task } from '../types'; | |
| interface TaskCompleteModalProps { | |
| task: Task; | |
| onClose: () => void; | |
| onComplete: (taskId: string, whatIDid: string, codeSnippet?: string) => Promise<void>; | |
| } | |
| export function TaskCompleteModal({ task, onClose, onComplete }: TaskCompleteModalProps) { | |
| const [whatIDid, setWhatIDid] = useState(''); | |
| const [codeSnippet, setCodeSnippet] = useState(''); | |
| const [isSubmitting, setIsSubmitting] = useState(false); | |
| const [error, setError] = useState(''); | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (!whatIDid.trim()) { | |
| setError('Please describe what you did'); | |
| return; | |
| } | |
| setIsSubmitting(true); | |
| setError(''); | |
| try { | |
| await onComplete(task.id, whatIDid.trim(), codeSnippet.trim() || undefined); | |
| onClose(); | |
| } catch (err) { | |
| setError(err instanceof Error ? err.message : 'Failed to complete task'); | |
| } finally { | |
| setIsSubmitting(false); | |
| } | |
| }; | |
| return ( | |
| <div className="fixed inset-0 z-50 flex items-center justify-center"> | |
| {/* Backdrop */} | |
| <div | |
| className="absolute inset-0 bg-black/60 backdrop-blur-sm" | |
| onClick={onClose} | |
| /> | |
| {/* Modal */} | |
| <div className="relative bg-slate-900 border border-white/20 rounded-xl w-full max-w-lg mx-4 shadow-2xl"> | |
| {/* Header */} | |
| <div className="px-6 py-4 border-b border-white/10"> | |
| <h2 className="text-xl font-bold text-white">Complete Task</h2> | |
| <p className="text-purple-300/70 text-sm mt-1 truncate">{task.title}</p> | |
| </div> | |
| {/* Form */} | |
| <form onSubmit={handleSubmit} className="p-6 space-y-4"> | |
| {error && ( | |
| <div className="p-3 bg-red-500/20 border border-red-500/50 rounded-lg text-red-200 text-sm"> | |
| {error} | |
| </div> | |
| )} | |
| <div> | |
| <label className="block text-white text-sm font-medium mb-2"> | |
| What did you do? <span className="text-red-400">*</span> | |
| </label> | |
| <textarea | |
| value={whatIDid} | |
| onChange={(e) => setWhatIDid(e.target.value)} | |
| placeholder="Describe what you accomplished..." | |
| rows={3} | |
| className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-purple-500 resize-none" | |
| autoFocus | |
| /> | |
| </div> | |
| <div> | |
| <label className="block text-white text-sm font-medium mb-2"> | |
| Code snippet (optional) | |
| </label> | |
| <textarea | |
| value={codeSnippet} | |
| onChange={(e) => setCodeSnippet(e.target.value)} | |
| placeholder="Paste any relevant code..." | |
| rows={4} | |
| className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-lg text-white placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-purple-500 resize-none font-mono text-sm" | |
| /> | |
| </div> | |
| {/* Actions */} | |
| <div className="flex gap-3 pt-2"> | |
| <button | |
| type="button" | |
| onClick={onClose} | |
| disabled={isSubmitting} | |
| className="flex-1 px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-all" | |
| > | |
| Cancel | |
| </button> | |
| <button | |
| type="submit" | |
| disabled={isSubmitting || !whatIDid.trim()} | |
| className="flex-1 px-4 py-3 bg-green-600 hover:bg-green-700 disabled:bg-green-800 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-all" | |
| > | |
| {isSubmitting ? 'Completing...' : 'Complete Task'} | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| ); | |
| } | |