From 2ad5ce929f6d69c9aaca71573744b30e02ab8bed Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Fri, 27 Jun 2025 10:10:56 +0200 Subject: Add cloudflare basic impl --- src/components/SimpleTest.tsx | 32 +++++++ src/components/TaskManager.tsx | 202 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 src/components/SimpleTest.tsx create mode 100644 src/components/TaskManager.tsx (limited to 'src/components') diff --git a/src/components/SimpleTest.tsx b/src/components/SimpleTest.tsx new file mode 100644 index 0000000..cfabeab --- /dev/null +++ b/src/components/SimpleTest.tsx @@ -0,0 +1,32 @@ +import { useState } from 'react'; + +export default function SimpleTest() { + const [count, setCount] = useState(0); + + return ( +
+

Simple Test Component

+
+

This is a simple React component to test if the infinite refresh is caused by the API calls.

+
+ + {count} + +
+

+ If this component works without refreshing, the issue is in the TaskManager API calls. +

+
+
+ ); +} \ No newline at end of file diff --git a/src/components/TaskManager.tsx b/src/components/TaskManager.tsx new file mode 100644 index 0000000..a10a5f9 --- /dev/null +++ b/src/components/TaskManager.tsx @@ -0,0 +1,202 @@ +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([]); + const [newTask, setNewTask] = useState({ title: '', description: '' }); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(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 ( +
+

Task Manager

+
Loading tasks...
+
+ ); + } + + if (error) { + return ( +
+

Task Manager

+
+

Error: {error}

+ +
+
+ ); + } + + return ( +
+

Task Manager

+ +
+
+ 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" + /> +
+
+