import React, { Component } from 'react'; import './TodoApp.css'; interface Item { name: string; completed: boolean; } interface AppState { items: Item[]; // existing items newName: string; // text in the field to add a new name } export class TodoApp extends Component<{}, AppState> { constructor(props: any) { super(props); this.state = { items: [], newName: "" }; setTimeout(() => this.refresh(), 0); // get the correct state from the server } // Called when the user checks the box next to an uncompleted item. The // second parameter is the index of that item in the list. completeItem(evt: any, index: number) { const items = this.state.items.slice(0); items[index] = {name: items[index].name, completed: true}; this.setState({items: items}); fetch("http://localhost:4567/completed?name=" + encodeURIComponent(items[index].name), {method: "POST", body: ""}) .then((resp) => { if (!resp.ok) throw new Error(`bad response: ${resp.statusText}`); setTimeout(() => this.refresh(), 5500); // update when it disappears }); } // Called when the user clicks on the button to add the new item. addItem(evt: any) { const name = this.state.newName.trim().replace('\t', ' '); // no tabs if (name.length > 0) { const items = this.state.items.slice(0); items.push({name: name, completed: false}); this.setState({items: items, newName: ""}); fetch("http://localhost:4567/add?name=" + encodeURIComponent(name), {method: "POST", body: ""}) .then((resp) => { if (!resp.ok) throw new Error(`bad response: ${resp.statusText}`); }); } } // Called when the user clisk the Refresh button. Sync to server state. refresh() { fetch("http://localhost:4567/list") .then((resp) => resp.text()) .then((text) => { const items = []; if (text.length > 0) { const lines = text.split('\n'); for (let i = 0; i < lines.length; i++) { const text = lines[i].trim(); if (text.endsWith("\t(completed)")) { items.push({name: text.substring(0, text.length-12), completed: true}); } else { items.push({name: text, completed: false}); } } } this.setState({items: items}); }); } // Called each time the text in the new item name field is changed. setNewName(evt: any) { this.setState({newName: evt.target.value}); } render() { let items : any[] = []; for (let i = 0; i < this.state.items.length; i++) { if (this.state.items[i].completed) { items.push(
); } else { items.push(
this.completeItem(evt, i)} />
); } } return (

To-Do List

{items}

Check the item to mark it completed.

New item: this.setNewName(evt)} />

); } }