You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

100 lines
2.9 KiB

package nova.monadic_sfx.ui.components.todo
import cats.kernel.Eq
import com.softwaremill.quicklens._
import io.circe.generic.JsonCodec
import io.odin.Logger
import monix.bio.Task
import nova.monadic_sfx.util.reactive.store.Middlewares.actionLoggerMiddleware
import nova.monadic_sfx.util.reactive.store.Reducer
import nova.monadic_sfx.util.reactive.store.Store
case class Todo(id: Int, content: String)
object Todo {
implicit val eqForTodo = Eq.fromUniversalEquals[Todo]
}
object TodoListStore {
@JsonCodec
sealed trait Action
case object Init extends Action
case class Add(content: String) extends Action
case class Edit(id: Int, content: String) extends Action
case class Delete(id: Int) extends Action
private case class InternalAdd(content: String) extends Action
private case object End extends Action
object Action {
implicit val eqForAction = Eq.fromUniversalEquals[Action]
}
case class State(todos: Vector[Todo], counter: Int)
object State {
implicit val eqForState = Eq.fromUniversalEquals[State]
}
def reducer(logger: Logger[Task])(
state: State,
action: Action
): (State, Option[Task[Action]]) =
action match {
case Init => (state, None)
case Add(content) =>
val nextAction = Some(for {
// do some validation
// _ <- logger.debug(s"Received $content")
res <- Task.pure(InternalAdd(content))
} yield res)
(state, nextAction)
case Edit(id, content) =>
val condition: Todo => Boolean = _.id == id
val nextState = state
.modify(_.todos.eachWhere(condition))
.using(_.copy(content = content))
(nextState, None)
case Delete(id) =>
(state.copy(state.todos.filterNot(_.id == id)), None)
case InternalAdd(content) =>
val nextState =
state
.modify(_.todos)
.using(_ :+ Todo(state.counter, content))
.modify(_.counter)
.using(_ + 1)
(nextState, Some(logger.debug(s"Received $content") >> Task.pure(End)))
case End => (state, None)
}
def apply(logger: Logger[Task]): Task[Store[Action, State]] =
Task.deferAction(implicit s =>
for {
logMware <- actionLoggerMiddleware[Action, State](logger, "TodoStore")
store <-
Store
.createL[Action, State](
Init,
State(Vector.empty[Todo], 0),
Reducer.withOptionalEffects(reducer(logger) _),
Seq(logMware)
)
} yield store
)
}
// Task.deferAction(implicit s =>
// Store
// .createJsonL[Action, State](
// Init,
// State(Vector.empty[Todo], 0),
// Reducer.withOptionalEffects(reducer(logger) _),
// "TodoStore",
// logger
// // Seq(
// // actionLoggerMiddleware(logger, "TodoStore")
// // // actionLoggerMiddleware(logger, "TodoStore2")
// // )
// )
// )