# Todos - Basic

In ConanJs we wanted to be original, and we have decided to start showing how to build a list of Todos in our first tutorial. We will then go a bit further than other frameworks do, and will show how we can add Asynchronous calls and optimistic updates.

The code for this example is available at GitHub:

{% embed url="<https://github.com/conan-js/conan-js-examples/tree/master/todo-list>" %}

and you can also check this [code sandbox](#code-sandbox) at the bottom of this page.

If you are coming from Redux, you might want to see how this compares to the TODO from Redux, if that is the case, have a look at this article:

{% embed url="<https://medium.com/conanjs/conanjs-vs-redux-comparing-a-simple-todo-app-222b87363865?source=friends_link&sk=80e501985b27f9694ac74c9bae1fbb61>" %}

## Initial steps

### Adding ConanJs to the project

In the project root, just run:

```typescript
npm install conan-js-core
```

## Implementing the Todos app

### Domain model

{% hint style="success" %}
Our examples are in typescript, if you use javascript, you can just ignore the type definitions and it will all work just fine on your end.

The following interfaces are to define with Typescript the domain for the application.
{% endhint %}

Our data structure for this example will be very straightforward, simply having a Todo, TodoList and status entities. We will also model the visibility filters as:

```typescript
export enum ToDoStatus {
    PENDING = 'PENDING',
    COMPLETED = 'COMPLETED'
}

export interface ToDo {
    id: string;
    description: string;
    status: ToDoStatus;
}

export enum VisibilityFilters {
    SHOW_ALL = 'SHOW_ALL',
    SHOW_COMPLETED = 'SHOW_COMPLETED',
    SHOW_ACTIVE = 'SHOW_ACTIVE'
}

export interface TodoListData {
    todos: ToDo[];
    appliedFilter: VisibilityFilters;
}
```

### Creating the Todos state

To create the state we will use [Conan.state](https://docs.conanjs.io/tutorials/conan-state-demos/todos/broken-reference) as we will need to pass our custom reducers later on. The data part of our state will be represented by the *TodoListData,* which holds an array of Todos and a current applied filter. We are initially just passing one reducer to add a Todo to the current array of todos.

{% tabs %}
{% tab title="Js" %}

```javascript
export const todoListSyncState$ = Conan.state({
    name: 'todos-sync',
    initialData: {
        appliedFilter: VisibilityFilters.SHOW_ALL,
        todos: []
    },
    reducers: ({
        $addTodo: (todo) => ({
            todos: [...getState().todos, todo],
            appliedFilter: getState().appliedFilter
        })
    }),
});
```

{% endtab %}

{% tab title="Ts" %}

```typescript
export type TodoListState = ConanState<TodoListData>;


export const todoListSyncState$: TodoListState  = Conan.state<TodoListData>({
    name: 'todos-sync',
    initialData: {
        appliedFilter: VisibilityFilters.SHOW_ALL,
        todos: []
    },
    reducers: getState => ({
        $addTodo: (todo: ToDo): TodoListData => ({
            todos: [...getState().todos, todo],
            appliedFilter: getState().appliedFilter
        })
    }),
});
```

{% endtab %}
{% endtabs %}

Let's add our newly defined state to [Conan Dependency Injection](https://docs.conanjs.io/dependency-injection), so that is accesible from all the app.

{% tabs %}
{% tab title="Js" %}

```javascript
export let diContext = DiContextFactory.createContext({
    todoListState: todoListSyncState$,
});
```

{% endtab %}

{% tab title="Ts" %}

```typescript
export let diContext: App = DiContextFactory.createContext<App>({
        todoListState: todoListSyncState$,
    }
);
```

{% endtab %}
{% endtabs %}

###

### Connecting the state

To use our new reducer and add a Todo, we just need to connect our presentation components with Conan state. For a guide on the different ways of connecting the state please visit [Using the State](https://docs.conanjs.io/data/conan-state/subscribing-state)

For this example we will use Conan HOC [StateConnect](https://docs.conanjs.io/data/conan-state/subscribing-state):

{% tabs %}
{% tab title="Js" %}

```javascript
<StateConnect from={diContext.todoListState} into={TodoListRenderer} 
    fallbackValue={{
            todos: [],
            appliedFilter: VisibilityFilters.SHOW_ALL
}}/>
```

{% endtab %}

{% tab title="Ts" %}

```typescript
<StateConnect<TodoListData, TodoListActions>
    from={diContext.todoListState}
    into={TodoListRenderer}
    fallbackValue={{
        todos: [],
        appliedFilter: VisibilityFilters.SHOW_ALL
    }}
/>
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
As we have added our state to Conan DI, we can just use it with ***diContext.todoListState***
{% endhint %}

### Adding a Todo

To add a Todo, *TodoListRenderer* can now make use of our state data and actions. It can now include the AddTodo component and pass the action addTodo created by ConanJs, from the reducer we created before:

```javascript
<AddTodo onClick={actions.addTodo}/>
```

### �Toggling a Todo

To toggle a Todo we will add a new reducer to the Conan state, and pass it in the reducers input parameter:

{% tabs %}
{% tab title="Js" %}

```javascript
$toggleTodo: (toggledTodo) => ({
        todos: getState().todos.map(todo => todo.id !== toggledTodo.id ? todo : {
            ...todo,
            status: (todo.status === ToDoStatus.PENDING ? ToDoStatus.COMPLETED : ToDoStatus.PENDING)
        }),
        appliedFilter: getState().appliedFilter
}),
```

{% endtab %}

{% tab title="Ts" %}

```typescript
$toggleTodo: (toggledTodo: ToDo): TodoListData => ({
        todos: getState().todos.map(todo =>
            todo.id !== toggledTodo.id ? todo : {
                ...todo,
                status: (todo.status === ToDoStatus.PENDING ? ToDoStatus.COMPLETED : ToDoStatus.PENDING)
            },
        ),
        appliedFilter: getState().appliedFilter
})
```

{% endtab %}
{% endtabs %}

TodoListRenderer can now render the list of Todos and pass the action to toggle them:

{% tabs %}
{% tab title="Js" %}

```javascript
<ul>
    (data.todos).map(todo => 
    <Todo key={todo.id} onClick={() => actions.toggleTodo(todo)} 
        text={todo.description} completed={todo.status === ToDoStatus.COMPLETED}/>)}
</ul>
```

{% endtab %}

{% tab title="Ts" %}

```typescript
{filterToDos(data.todos, data.appliedFilter).map(todo =>
    <Todo
        key={todo.id}
        onClick={() => actions.toggleTodo(todo)}
        text={todo.description}
        completed={todo.status === ToDoStatus.COMPLETED}
    />
)}
```

{% endtab %}
{% endtabs %}

### �Filtering Todos

Let's add the last reducer to the Conan state in order to filter Todos:

{% tabs %}
{% tab title="Js" %}

```javascript
$filter: (filter) => ({
    todos: getState().todos,
    appliedFilter: filter
})
```

{% endtab %}

{% tab title="Ts" %}

```typescript
$filter: (filter: VisibilityFilters): TodoListData => ({
    todos: getState().todos,
    appliedFilter: filter
})
```

{% endtab %}
{% endtabs %}

TodoListRenderer can now pass the filter action to the Footer component:

```javascript
<FooterRenderer appliedFilter={data.appliedFilter} filterUpdater={actions.filter}/>
```

We can use the current filter now to only show the correct Todos:

{% tabs %}
{% tab title="Js" %}

```javascript
<ul>
    {filterToDos(data.todos, data.appliedFilter).map(todo => <Todo key={todo.id} onClick={() => actions.toggleTodo(todo)} text={todo.description} completed={todo.status === ToDoStatus.COMPLETED}/>)}
</ul>

export function filterToDos(todos, filter) {
    switch (filter) {
        case VisibilityFilters.SHOW_ALL:
            return todos;
        case VisibilityFilters.SHOW_COMPLETED:
            return todos.filter(t => t.status === ToDoStatus.COMPLETED);
        case VisibilityFilters.SHOW_ACTIVE:
            return todos.filter(t => t.status === ToDoStatus.PENDING);
        default:
            throw new Error('Unknown filter: ' + filter);
    }
}
```

{% endtab %}

{% tab title="Ts" %}

```typescript
<ul>
    {filterToDos(data.todos, data.appliedFilter).map(todo =>
        <Todo
            key={todo.id}
            onClick={() => actions.toggleTodo(todo)}
            text={todo.description}
            completed={todo.status === ToDoStatus.COMPLETED}
        />
    )}
</ul>

export function filterToDos(todos: ToDo[], filter: VisibilityFilters): ToDo[] {
    switch (filter) {
        case VisibilityFilters.SHOW_ALL:
            return todos;
        case VisibilityFilters.SHOW_COMPLETED:
            return todos.filter(t => t.status === ToDoStatus.COMPLETED);
        case VisibilityFilters.SHOW_ACTIVE:
            return todos.filter(t => t.status === ToDoStatus.PENDING);
        default:
            throw new Error('Unknown filter: ' + filter);
    }
}
```

{% endtab %}
{% endtabs %}

## Code sandbox

All the files needed for this example are available in this codesandbox. Please be aware that although we explain the stops in both Javascript and Typescript, our examples are written in Typescript.

{% embed url="<https://codesandbox.io/s/ve8zx>" %}
