Guest User

Untitled

a guest
Nov 6th, 2026
19
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.55 KB | None | 0 0
  1. "use client";
  2.  
  3. import { useEffect, useState } from "react";
  4.  
  5. type Task = { id: number; title: string; done: boolean; created_at: string };
  6.  
  7. type Health = { server: string; version: string };
  8.  
  9. export default function Home() {
  10.  
  11.   const [tasks, setTasks] = useState<Task[]>([]);
  12.  
  13.   const [health, setHealth] = useState<Health | null>(null);
  14.  
  15.   const [title, setTitle] = useState("");
  16.  
  17.   const [error, setError] = useState("");
  18.  
  19.   const [version, setVersion] = useState(0); // bump to reload
  20.  
  21.   const reload = () => setVersion((v) => v + 1);
  22.  
  23.   // Load tasks and server info on start and after any write
  24.  
  25.   useEffect(() => {
  26.  
  27.     let cancelled = false;
  28.  
  29.     Promise.all([fetch("/api/tasks"), fetch("/api/health")])
  30.  
  31.       .then(async ([t, h]) => {
  32.  
  33.         if (!t.ok || !h.ok) throw new Error("Database request failed");
  34.  
  35.         const [taskData, healthData] = await Promise.all([t.json(), h.json()]);
  36.  
  37.         if (!cancelled) {
  38.  
  39.           setTasks(taskData);
  40.  
  41.           setHealth(healthData);
  42.  
  43.           setError("");
  44.  
  45.         }
  46.  
  47.       })
  48.  
  49.       .catch((e) => !cancelled && setError(e.message));
  50.  
  51.     return () => {
  52.  
  53.       cancelled = true;
  54.  
  55.     };
  56.  
  57.   }, [version]);
  58.  
  59.   async function addTask(e: React.FormEvent) {
  60.  
  61.     e.preventDefault();
  62.  
  63.     if (!title.trim()) return;
  64.  
  65.     await fetch("/api/tasks", {
  66.  
  67.       method: "POST",
  68.  
  69.       headers: { "Content-Type": "application/json" },
  70.  
  71.       body: JSON.stringify({ title }),
  72.  
  73.     });
  74.  
  75.     setTitle("");
  76.  
  77.     reload();
  78.  
  79.   }
  80.  
  81.   async function toggle(t: Task) {
  82.  
  83.     await fetch(`/api/tasks/${t.id}`, {
  84.  
  85.       method: "PATCH",
  86.  
  87.       headers: { "Content-Type": "application/json" },
  88.  
  89.       body: JSON.stringify({ done: !t.done }),
  90.  
  91.     });
  92.  
  93.     reload();
  94.  
  95.   }
  96.  
  97.   async function remove(t: Task) {
  98.  
  99.     await fetch(`/api/tasks/${t.id}`, { method: "DELETE" });
  100.  
  101.     reload();
  102.  
  103.   }
  104.  
  105.   return (
  106.  
  107.     <main style={{ maxWidth: 560, margin: "40px auto", fontFamily: "system-ui", padding: "0 16px" }}>
  108.  
  109.       <h1>Task App (Amazon RDS MySQL)</h1>
  110.  
  111.       <p style={{ color: "#666" }}>
  112.  
  113.         {health ? `Served by ${health.server} · MySQL ${health.version}` : "Connecting…"}
  114.  
  115.       </p>
  116.  
  117.       {error && <p style={{ color: "crimson" }}>{error}</p>}
  118.  
  119.       <form onSubmit={addTask} style={{ display: "flex", gap: 8, margin: "16px 0" }}>
  120.  
  121.         <input
  122.  
  123.           value={title}
  124.  
  125.           onChange={(e) => setTitle(e.target.value)}
  126.  
  127.           placeholder="New task"
  128.  
  129.           style={{ flex: 1, padding: 8 }}
  130.  
  131.         />
  132.  
  133.         <button>Add</button>
  134.  
  135.       </form>
  136.  
  137.       <ul style={{ listStyle: "none", padding: 0 }}>
  138.  
  139.         {tasks.map((t) => (
  140.  
  141.           <li key={t.id} style={{ display: "flex", gap: 8, padding: "8px 0", borderBottom: "1px solid #ddd" }}>
  142.  
  143.             <input type="checkbox" checked={t.done} onChange={() => toggle(t)} />
  144.  
  145.             <span style={{ flex: 1, textDecoration: t.done ? "line-through" : "none" }}>{t.title}</span>
  146.  
  147.             <button onClick={() => remove(t)}>Delete</button>
  148.  
  149.           </li>
  150.  
  151.         ))}
  152.  
  153.       </ul>
  154.  
  155.       <p>{tasks.length} task(s)</p>
  156.  
  157.     </main>
  158.  
  159.   );
  160.  
  161. }
Advertisement
Add Comment
Please, Sign In to add comment