rsnext/examples/with-reasonml-todo/components/TodoApp.re
2019-05-23 16:48:13 -05:00

111 lines
2.4 KiB
ReasonML

module TodoId = {
type t = string;
let prefix = ref(0);
let make = () => {
let prefix = Js.Math.random_int(1000000, 9999999)->string_of_int;
let suffix = Js.Date.now()->int_of_float->string_of_int;
{j|$prefix::$suffix|j}
}
};
module Todo = {
[@bs.deriving abstract]
type t = {
id: TodoId.t,
mutable finished: bool,
text: string,
};
let make = (~finished=false, text) => t(~id=TodoId.make(), ~finished, ~text);
let complete = t => {
t->finishedSet(true);
t
}
let isSame = (t1, t2) => t1->idGet === t2->idGet
};
module TodoList = {
type t = array(Todo.t);
let contains = (list, todo) => list->Belt.Array.some(Todo.isSame(todo));
let complete = (list, target) =>
list->Belt.Array.map(todo =>
todo->Todo.isSame(target) ? todo->Todo.complete : todo
);
let add = (list, todo) => {
if (!list->contains(todo)) {
list->Belt.Array.concat([|todo|])
} else {
// panic - should be unreachable
let id = todo->Todo.idGet;
Js.Exn.raiseError({j|Could not add todo $id, it already exists.|j});
}
}
let remove = (list, todo) =>
list->Belt.Array.keep(current => !todo->Todo.isSame(current));
}
type t = {
today: TodoList.t,
tomorrow: TodoList.t,
}
type day =
| Today
| Tomorrow;
type action =
| Add(day, Todo.t)
| Complete(day, Todo.t)
| Remove(day, Todo.t)
let appState = ref({ today: [||], tomorrow: [||] });
let add = (state, day, todo) => {
switch(day) {
| Today => { ...state, today: state.today->TodoList.add(todo) }
| Tomorrow => { ...state, tomorrow: state.tomorrow->TodoList.add(todo) }
}
}
let complete = (state, day, todo) => {
switch(day) {
| Today => { ...state, today: state.today->TodoList.complete(todo) }
| Tomorrow => { ...state, tomorrow: state.tomorrow->TodoList.complete(todo) }
}
}
let remove = (state, day, todo) => {
switch(day) {
| Today => { ...state, today: state.today->TodoList.remove(todo) }
| Tomorrow => { ...state, tomorrow: state.tomorrow->TodoList.remove(todo) }
}
}
let getDay = (state, day) => {
switch(day) {
| Today => state.today
| Tomorrow => state.tomorrow
}
}
let reducer = (state, action) => {
let newState = switch(action) {
| Add(day, todo) => add(state, day, todo)
| Complete(day, todo) => complete(state, day, todo)
| Remove(day, todo) => remove(state, day, todo)
};
appState := newState;
newState;
}
let useTodoReducer = () => React.useReducer(reducer, appState^);