Follow the Setting up Preact tutorial to set up the proper base for this ToDo application.
You can use a custom CSS for a nicer visual effect. Add the following CSS link to the <head>
section in config/client/index.html
:
<link rel="stylesheet" href="http://fip.zaiste.net/main.css">
App
ComponentIn features/Base/View/index.tsx
replace the content with the following code:
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
interface Task {
name: string;
done: boolean
};
function App() {
const [newTask, setNewTask] = useState('');
const [tasks, setTasks] = useState([] as Task[]);
const addTodo = () => {
setTasks([...tasks, { name: newTask, done: false }]);
setNewTask('');
}
const onInput = (event: Event) => {
const { value } = event.target as HTMLInputElement;
setNewTask(value)
}
const onKeyUp = (event: KeyboardEvent) => {
const { key } = event;
if (key === 'Enter') {
addTodo();
}
}
return (
<div class="task-container">
<div class="task-input">
<input
placeholder="Add new item..."
type="text"
class="task-new"
value={newTask}
onInput={onInput}
onKeyUp={onKeyUp}
/>
<button class="task-add" onClick={addTodo}>Add</button>
</div>
<ul class="task-list">
{tasks.map((task, index) => (
<li key={index} class="task-item" v-for="task in state.tasks">
<label class="task-item-container">
<div class="task-checkbox">
<input type="checkbox" class="opacity-0 absolute" value={task.done} />
<svg class="task-checkbox-icon" viewBox="0 0 20 20">
<path d="M0 11l2-2 5 5L18 3l2 2L7 18z" />
</svg>
</div>
<div class="ml-2">{task.name}</div>
</label>
</li>
))}
</ul>
</div>
);
}
export { App };
In features/Task/Controller
create browse.ts
. The naming is important. The browse
name corresponds to the HTTP GET
request that is supposed to respond with a collection of a given resource. In this case, it's a collection of tasks.
We create a handler function that describes the action that will happen once such request is received. In Kretes, handlers are functions that take HTTP requests as input and return HTTP responses as output. The OK
convenience wrapper corresponds to the 200 OK
response. We define the list of tasks in memory for now, as the tasks
variable.
import { Handler, response } from 'kretes';
const { OK } = response;
const tasks = [
{ name: 'Use TypeScript 4.x', done: false },
{ name: 'Learn Kretes', done: false },
{ name: 'Enjoy programming', done: false },
]
export const browse: Handler = ({ params }) => {
return OK(tasks);
}
Connect the front-end with the REST endpoint using the useEffect
hook and the built-in fetch
browser API.
const fetchData = async () => {
const response = await fetch('/task');
const result = await response.json();
setTasks(result);
};
useEffect(() => fetchData(), [])
Found a mistake?Found a mistake? Would you like to suggest an improvement?