Created
October 3, 2022 20:54
-
-
Save brandonchadlange/4fc268600d1636b80bb926e4e8ee82fc to your computer and use it in GitHub Desktop.
Todos full implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Todo { | |
description: string; | |
complete: boolean; | |
} | |
const useTodoListViewModel = () => { | |
const [todos, setTodos] = useState<Todo[]>([]); | |
const createTodo = (description: string) => { | |
const newTodo: Todo = { | |
description, | |
complete: false, | |
}; | |
setTodos((current) => [...current, newTodo]); | |
}; | |
return { | |
todos, | |
createTodo, | |
}; | |
}; | |
const TodoList = ({ todos }: { todos: Todo[] }) => { | |
const todoList = todos.map((todo) => <Todo todo={todo} />); | |
return <ul>{todoList}</ul>; | |
}; | |
const useTodoViewModel = (todo: Todo) => { | |
const [checked, setChecked] = useState(todo.complete); | |
const textDecoration = { | |
textDecoration: todo.complete ? "line-through" : "none", | |
}; | |
const toggleChecked = () => { | |
setChecked((checked) => !checked); | |
}; | |
return { | |
description: todo.description, | |
checked, | |
textDecoration, | |
toggleChecked, | |
}; | |
}; | |
const Todo = ({ todo }: { todo: Todo }) => { | |
const vm = useTodoViewModel(todo); | |
return ( | |
<li> | |
<label> | |
<input | |
defaultChecked={vm.checked} | |
onChange={vm.toggleChecked} | |
type="checkbox" | |
/> | |
<span style={{ ...vm.textDecoration }}>{vm.description}</span> | |
</label> | |
</li> | |
); | |
}; | |
const useAddTodoVm = (onAdd: (description: string) => void) => { | |
const [inputText, setInputText] = useState(""); | |
const addTodo = () => { | |
onAdd(inputText); | |
setInputText(""); | |
}; | |
return { | |
inputText, | |
setInputText, | |
addTodo, | |
}; | |
}; | |
interface AddTodoViewModel { | |
inputText: string; | |
setInputText: (inputText: string) => void; | |
addTodo: () => void; | |
} | |
const AddTodo = ({ viewModel }: { viewModel: AddTodoViewModel }) => { | |
return ( | |
<> | |
<input | |
value={viewModel.inputText} | |
onChange={(e) => viewModel.setInputText(e.target.value)} | |
type="text" | |
placeholder="Add todo" | |
/> | |
<button onClick={viewModel.addTodo}>Add</button> | |
</> | |
); | |
}; | |
const Todos = () => { | |
const listVm = useTodoListViewModel(); | |
const addTodoVm = useAddTodoVm(listVm.createTodo); | |
return ( | |
<> | |
<TodoList todos={listVm.todos} /> | |
<AddTodo viewModel={addTodoVm} /> | |
</> | |
); | |
}; | |
export default Todos; |
yogithesymbian
commented
Jun 26, 2024
@brandonchadlange how about these
pattern
INTERFACE
// todo/interface/list.tsx
interface Todo {
description: string;
complete: boolean;
}
// todo/interface/add.tsx
interface AddTodoViewModel {
inputText: string;
setInputText: (inputText: string) => void;
addTodo: () => void;
}
VIEW MODEL
// todo/view-model/view-model.tsx
const useTodoViewModel = (todo: Todo) => {
const [checked, setChecked] = useState(todo.complete);
const textDecoration = {
textDecoration: todo.complete ? "line-through" : "none",
};
const toggleChecked = () => {
setChecked((checked) => !checked);
};
return {
description: todo.description,
checked,
textDecoration,
toggleChecked,
};
};
const useTodoListViewModel = () => {
const [todos, setTodos] = useState<Todo[]>([]);
const createTodo = (description: string) => {
const newTodo: Todo = {
description,
complete: false,
};
setTodos((current) => [...current, newTodo]);
};
return {
todos,
createTodo,
};
};
const useAddTodoVm = (onAdd: (description: string) => void) => {
const [inputText, setInputText] = useState("");
const addTodo = () => {
onAdd(inputText);
setInputText("");
};
return {
inputText,
setInputText,
addTodo,
};
};
component
// todo/component/todo-list.tsx
const Todo = ({ todo }: { todo: Todo }) => {
const vm = useTodoViewModel(todo);
return (
<li>
<label>
<input
defaultChecked={vm.checked}
onChange={vm.toggleChecked}
type="checkbox"
/>
<span style={{ ...vm.textDecoration }}>{vm.description}</span>
</label>
</li>
);
};
const TodoList = ({ todos }: { todos: Todo[] }) => {
const todoList = todos.map((todo) => <Todo todo={todo} />);
return <ul>{todoList}</ul>;
};
// todo/component/add-todo.tsx
const AddTodo = ({ viewModel }: { viewModel: AddTodoViewModel }) => {
return (
<>
<input
value={viewModel.inputText}
onChange={(e) => viewModel.setInputText(e.target.value)}
type="text"
placeholder="Add todo"
/>
<button onClick={viewModel.addTodo}>Add</button>
</>
);
};
// todo/page.tsx
const Todos = () => {
const listVm = useTodoListViewModel();
const addTodoVm = useAddTodoVm(listVm.createTodo);
return (
<>
<TodoList todos={listVm.todos} />
<AddTodo viewModel={addTodoVm} />
</>
);
};
export default Todos;
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment