Skip to content

Commit

Permalink
Keep things relatively simple
Browse files Browse the repository at this point in the history
  • Loading branch information
garronej committed May 29, 2024
1 parent 365645d commit d637f61
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 24 deletions.
42 changes: 20 additions & 22 deletions src/components/TodoApp/Todo.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,48 @@
import { memo, useState, useEffect, useReducer } from "react";
import { memo, useState, useEffect } from "react";
import { tss } from "tss-react";
import { fr } from "@codegouvfr/react-dsfr";
import { Button } from "@codegouvfr/react-dsfr/Button";
import Checkbox from "@mui/material/Checkbox";
import { useEvent } from "tools/useEvent";
import { deepEqual } from "tools/deepEqual";
import type { TodoItem } from "./type";
import { assert } from "tsafe/assert";

export type Todo = {
id: string;
// Todo item but without the id, we don't need it.
export type TodoItemLike = {
text: string;
isDone: boolean;
};

// Make sure that the type `TodoItemLike` is a subset of `TodoItem`
// This will give us red squiggles if we forget to update `TodoItemLike` when we update `TodoItem`
assert<TodoItem extends TodoItemLike ? true : false>();

type TodoProps = {
className?: string;
todo: Todo;
todo: TodoItemLike;
onUpdateTodoText: (text: string) => void;
onToggleTodo: () => void;
onDeleteTodo: () => void;
};

export const Todo = memo((props: TodoProps) => {
const { className, todo, onToggleTodo, onDeleteTodo } = props;

// NOTE: Make sure it's not stale for when used in the reducer.
// We know it's constant because we also used useListEvent() in the parent component
// but this component is not supposed to be aware of that.
const onUpdateTodoText = useEvent(props.onUpdateTodoText);
const { className, todo, onToggleTodo, onDeleteTodo, onUpdateTodoText } = props;

const [isEditing, setIsEditing] = useReducer((isEditing: boolean, isEditing_new: boolean) => {
if (isEditing_new === isEditing) {
return isEditing;
}
const [text, setText] = useState(todo.text);
const [isEditing, setIsEditing] = useState(false);

if (!isEditing_new) {
const onEditButtonClick = useEvent(() => {
if (isEditing) {
onUpdateTodoText(text);
setIsEditing(false);
} else {
setIsEditing(true);
}

return isEditing_new;
}, false);
});

const { classes, cx } = useStyles({ isEditing });

const [text, setText] = useState(todo.text);

useEffect(() => {
setText(todo.text);
}, [todo.text]);
Expand All @@ -58,7 +57,6 @@ export const Todo = memo((props: TodoProps) => {
className={cx(fr.cx("fr-input"), classes.input)}
value={text}
onChange={e => setText(e.target.value)}
onBlur={() => setIsEditing(false)}
/>
) : (
<span className={classes.text}>{todo.text}</span>
Expand All @@ -68,7 +66,7 @@ export const Todo = memo((props: TodoProps) => {
<div className={classes.buttonsWrapper}>
<Button
iconId={isEditing ? "ri-check-line" : "ri-pencil-line"}
onClick={() => setIsEditing(!isEditing)}
onClick={onEditButtonClick}
priority="secondary"
title="Edit"
/>
Expand Down
25 changes: 23 additions & 2 deletions src/components/TodoApp/TodoApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,42 @@ import { Todo } from "./Todo";
import { AddTodo } from "./AddTodo";
import { tss } from "tss-react";
import { usePartiallyAppliedEvent } from "tools/usePartiallyAppliedEvent";
import type { TodoItem } from "./type";

type Props = {
className?: string;
todos: Todo[];
todos: TodoItem[];
onAddTodo: (text: string) => void;
onUpdateTodoText: (id: string, text: string) => void;
onToggleTodo: (id: string) => void;
onDeleteTodo: (id: string) => void;
};

export function TodoApp(props: Props) {
const { className, todos, onAddTodo, onUpdateTodoText, onToggleTodo, onDeleteTodo } = props;
const { className, todos } = props;

const { classes, cx } = useStyles();

const onAddTodo = (text: string) => {
console.log(`Adding todo with text: ${text}`);
props.onAddTodo(text);
};

const onUpdateTodoText = (id: string, text: string) => {
console.log(`Updating todo with id: ${id} and text: ${text}`);
props.onUpdateTodoText(id, text);
};

const onToggleTodo = (id: string) => {
console.log(`Toggling todo with id: ${id}`);
props.onToggleTodo(id);
};

const onDeleteTodo = (id: string) => {
console.log(`Deleting todo with id: ${id}`);
props.onDeleteTodo(id);
};

/*
Example:
Expand Down
5 changes: 5 additions & 0 deletions src/components/TodoApp/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type TodoItem = {
id: string;
text: string;
isDone: boolean;
};

0 comments on commit d637f61

Please sign in to comment.