package nova.monadic_sfx.ui.components.todo import nova.monadic_sfx.util.reactive.Store import nova.monadic_sfx.util.reactive.Reducer import nova.monadic_sfx.util.reactive.Middlewares.actionLoggerMiddleware import io.odin.Logger import monix.bio.Task import io.odin._ import io.odin.syntax._ import io.circe.generic.JsonCodec import com.softwaremill.quicklens._ case class Todo(id: Int, content: String) object TodoListStore { @JsonCodec sealed trait Command case object Init extends Command case class Add(content: String) extends Command case class Edit(id: Int, content: String) extends Command case class Delete(id: Int) extends Command case class State(todos: Vector[Todo], counter: Int) def reducer( state: State, action: Command ) = action match { case Init => state case Add(content) => state.copy( todos = state.todos :+ Todo(state.counter, content), counter = state.counter + 1 ) case Edit(id, content) => state .modify(_.todos.eachWhere(_.id == id)) .using(_.copy(content = content)) case Delete(id) => state.copy(state.todos.filterNot(_.id == id)) } def updateTodo(id: Int, content: String, todos: Vector[Todo]) = todos.view.zipWithIndex .find { case (todo, index) => todo.id == id } .map { case (todo, index) => todo.copy(content = content) -> index } .map { case (todo, index) => todos.updated(index, todo) } val middlewareLogger = consoleLogger[Task]().withAsync() def apply(logger: Logger[Task]) = Store .createL[Command, State]( Init, State(Vector.empty[Todo], 0), Reducer(reducer _), Seq(actionLoggerMiddleware(logger)) ) }