diff options
| author | Yuval Adam <_@yuv.al> | 2025-06-27 10:41:40 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-06-27 10:41:40 +0200 |
| commit | c896691084bfc786dc1780ce36fd71e6f7ab9d60 (patch) | |
| tree | 0e60f238bb42c24441dfbfbcab6f240c0d4d0d67 /src/components/TaskManager.tsx | |
| parent | 8403930448013787bd0a986ece086f20ef6d9a57 (diff) | |
Migrate from react to svelte
Diffstat (limited to 'src/components/TaskManager.tsx')
| -rw-r--r-- | src/components/TaskManager.tsx | 202 |
1 files changed, 0 insertions, 202 deletions
diff --git a/src/components/TaskManager.tsx b/src/components/TaskManager.tsx deleted file mode 100644 index a10a5f9..0000000 --- a/src/components/TaskManager.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { useState, useEffect, useCallback } from 'react'; - -interface Task { - id: number; - title: string; - description: string; - completed: boolean; - created_at?: string; - updated_at?: string; -} - -export default function TaskManager() { - const [tasks, setTasks] = useState<Task[]>([]); - const [newTask, setNewTask] = useState({ title: '', description: '' }); - const [loading, setLoading] = useState(true); - const [error, setError] = useState<string | null>(null); - - const fetchTasks = useCallback(async () => { - try { - setError(null); - const response = await fetch('/api/tasks'); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - console.log('Fetched tasks:', data); - setTasks(Array.isArray(data) ? data : []); - } catch (error) { - console.error('Failed to fetch tasks:', error); - setError(error instanceof Error ? error.message : 'Failed to fetch tasks'); - setTasks([]); - } finally { - setLoading(false); - } - }, []); - - useEffect(() => { - fetchTasks(); - }, [fetchTasks]); - - const createTask = async (e: React.FormEvent) => { - e.preventDefault(); - if (!newTask.title.trim()) return; - - try { - const response = await fetch('/api/tasks', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(newTask) - }); - - if (response.ok) { - setNewTask({ title: '', description: '' }); - fetchTasks(); - } - } catch (error) { - console.error('Failed to create task:', error); - } - }; - - const toggleTask = async (task: Task) => { - try { - await fetch(`/api/tasks/${task.id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ ...task, completed: !task.completed }) - }); - fetchTasks(); - } catch (error) { - console.error('Failed to update task:', error); - } - }; - - const deleteTask = async (id: number) => { - try { - await fetch(`/api/tasks/${id}`, { method: 'DELETE' }); - fetchTasks(); - } catch (error) { - console.error('Failed to delete task:', error); - } - }; - - if (loading) { - return ( - <div className="max-w-2xl mx-auto p-6"> - <h1 className="text-3xl font-bold mb-6">Task Manager</h1> - <div className="p-4 text-center">Loading tasks...</div> - </div> - ); - } - - if (error) { - return ( - <div className="max-w-2xl mx-auto p-6"> - <h1 className="text-3xl font-bold mb-6">Task Manager</h1> - <div className="p-4 bg-red-50 border border-red-200 rounded-lg"> - <p className="text-red-700">Error: {error}</p> - <button - onClick={fetchTasks} - className="mt-2 px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600" - > - Retry - </button> - </div> - </div> - ); - } - - return ( - <div className="max-w-2xl mx-auto p-6"> - <h1 className="text-3xl font-bold mb-6">Task Manager</h1> - - <form onSubmit={createTask} className="mb-8 space-y-4"> - <div> - <input - type="text" - placeholder="Task title" - value={newTask.title} - onChange={(e) => setNewTask({ ...newTask, title: e.target.value })} - className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - /> - </div> - <div> - <textarea - placeholder="Task description (optional)" - value={newTask.description} - onChange={(e) => setNewTask({ ...newTask, description: e.target.value })} - className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - rows={3} - /> - </div> - <button - type="submit" - className="w-full bg-blue-500 text-white p-3 rounded-lg hover:bg-blue-600 transition-colors" - > - Add Task - </button> - </form> - - <div className="space-y-4"> - {tasks.length === 0 ? ( - <p className="text-gray-500 text-center">No tasks yet. Create your first task above!</p> - ) : ( - tasks.map((task) => ( - <div - key={task.id} - className={`p-4 border rounded-lg ${ - task.completed ? 'bg-green-50 border-green-200' : 'bg-white border-gray-200' - }`} - > - <div className="flex items-start justify-between"> - <div className="flex-1"> - <h3 - className={`font-semibold ${ - task.completed ? 'line-through text-gray-500' : 'text-gray-900' - }`} - > - {task.title} - </h3> - {task.description && ( - <p - className={`mt-1 ${ - task.completed ? 'line-through text-gray-400' : 'text-gray-600' - }`} - > - {task.description} - </p> - )} - {task.created_at && ( - <p className="text-xs text-gray-400 mt-2"> - Created: {new Date(task.created_at).toLocaleString()} - </p> - )} - </div> - <div className="flex space-x-2 ml-4"> - <button - onClick={() => toggleTask(task)} - className={`px-3 py-1 rounded text-sm ${ - task.completed - ? 'bg-yellow-500 text-white hover:bg-yellow-600' - : 'bg-green-500 text-white hover:bg-green-600' - }`} - > - {task.completed ? 'Undo' : 'Complete'} - </button> - <button - onClick={() => deleteTask(task.id)} - className="px-3 py-1 bg-red-500 text-white rounded text-sm hover:bg-red-600" - > - Delete - </button> - </div> - </div> - </div> - )) - )} - </div> - </div> - ); -}
\ No newline at end of file |
