import Todo from './generated/Todo.js'; import * as React from 'react'; import { useState, useCallback, memo } from 'react'; import { commit, P, UpdateType, sid } from '@aphro/runtime-ts'; import { useQuery, useBind, useQueryOne } from './store.js'; import TodoList, { Data } from './generated/TodoList.js'; type Filter = Data['filter']; function Header({ todoList }: { todoList: TodoList }) { const [newText, setNewText] = useState(''); return (

todos

setNewText(e.target.value)} onKeyUp={e => { const target = e.target as HTMLInputElement; if (e.key === 'Enter' && target.value.trim() !== '') { Todo.create(todoList.ctx, { text: target.value, listId: todoList.id, completed: false, }).save(); setNewText(''); } }} />
); } const TodoView = memo( ({ todo, editing, startEditing, saveTodo, }: { key?: any; todo: Todo; editing: boolean; startEditing: (t: Todo) => void; saveTodo: (todo: Todo, text: string) => void; }) => { let body; const [text, setText] = useState(todo.text); useBind(todo, ['text', 'completed']); const deleteTodo = () => todo.delete().save(); const toggleTodo = () => todo.update({ completed: !todo.completed }).save(); if (editing) { body = ( saveTodo(todo, text)} onKeyUp={e => e.key === 'Enter' && saveTodo(todo, text)} onChange={e => setText(e.target.value)} /> ); } else { body = (
); } return (
  • {body}
  • ); }, ); function Footer({ remaining, todos, clearCompleted, todoList, }: { remaining: number; todos: Todo[]; clearCompleted: () => void; todoList: TodoList; }) { let clearCompletedButton; if (remaining !== todos.length) { clearCompletedButton = ( ); } const updateFilter = (filter: Filter) => todoList.update({ filter }).save(); return ( ); } export default function App() { const list = useQueryOne(TodoList.queryAll, { key: 'list' }); const clearCompleted = () => commit( list.ctx, completeTodos.map(t => t.delete()), ); const startEditing = useCallback( (todo: Todo) => list.update({ editing: todo.id }).save(), [list], ); const saveTodo = useCallback( (todo: Todo, text: string) => { commit(list.ctx, todo.update({ text: text }), list.update({ editing: null })); }, [list], ); const toggleAll = () => { if (remaining === 0) { // uncomplete all commit( list.ctx, completeTodos.map(t => t.update({ completed: false })), ); } else { // complete all commit( list.ctx, activeTodos.map(t => t.update({ completed: true })), ); } }; let toggleAllCheck; useBind(list, ['filter', 'editing']); const activeTodos = useQuery(() => list.queryTodos().whereCompleted(P.equals(false)), { key: 'activeTodos', }); const completeTodos = useQuery(() => list.queryTodos().whereCompleted(P.equals(true)), { key: 'completeTodos', }); const allTodos = useQuery(() => list.queryTodos(), { on: UpdateType.CREATE_OR_DELETE, key: 'allTodos', }); const remaining = activeTodos.length; let todos = list.filter === 'active' ? activeTodos : list.filter === 'completed' ? completeTodos : allTodos; if (allTodos.length) { toggleAllCheck = ( <> ); } return (
    0 ? {} : { display: 'none' }}> {toggleAllCheck}
      {todos.map(t => ( ))}
    ); }