Public
HTTP (deprecated)
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
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
/** @jsxImportSource https://esm.sh/react */
import React from "https://esm.sh/react";
import { renderToString } from "https://esm.sh/react-dom@18.2.0/server";
import { sqlite } from "https://esm.town/v/std/sqlite?v=4";
import { html } from "https://esm.town/v/stevekrouse/html";
sqlite.execute(`CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT 0
)`);
async function addTask(description: string) {
await sqlite.execute({
sql: `INSERT INTO tasks (description) VALUES (?)`,
args: [description],
});
}
async function getTasks() {
const { columns, rows } = await sqlite.execute(`SELECT id, description, completed FROM tasks`);
return rows.map((row) => {
const task: { [key: string]: any } = {};
columns.forEach((col, index) => {
if (col === "completed") {
task[col] = Boolean(row[index]);
} else {
task[col] = row[index];
}
});
return task;
});
}
async function toggleTaskCompletion(id: number, completed: boolean) {
await sqlite.execute({
sql: `UPDATE tasks SET completed = ? WHERE id = ?`,
args: [completed ? 1 : 0, id],
});
}
async function removeTask(id: number) {
await sqlite.execute({
sql: `DELETE FROM tasks WHERE id = ?`,
args: [id],
});
}
export let tasks = async (req: Request): Promise<Response> => {
if (req.method === "POST") {
const formData = await req.formData();
const action = formData.get("action");
if (action === "add") {
const description = formData.get("description");
if (typeof description === "string") {
await addTask(description);
}
} else if (action === "toggle") {
const id = formData.get("id");
const completed = formData.get("completed") === "on";
if (typeof id === "string") {
await toggleTaskCompletion(parseInt(id), completed);
}
}
if (action === "remove") {
const id = formData.get("id");
if (typeof id === "string") {
await removeTask(parseInt(id));
}
}
// Redirect to refresh the page and show the updated task list
return new Response(null, {
status: 303,
headers: {
Location: req.url,
},
});
}
const tasks = await getTasks();
return html(
renderToString(
<html lang="en">
<head>
<title>Tasks</title>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet" />
</head>
<body className="bg-gray-100">
<div className="max-w-xl mx-auto py-10">
<h1 className="text-3xl font-bold mb-6">Tasks</h1>
<form method="POST" className="mb-6">
<input type="hidden" name="action" value="add" />
<input
type="text"
stevekrouse-todo_app.web.val.run
January 25, 2024