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.

83 lines
2.3 KiB

3 years ago
  1. package nova.monadic_sfx.ui.components.todo
  2. import cats.kernel.Eq
  3. import com.softwaremill.quicklens._
  4. import io.circe.generic.JsonCodec
  5. import monix.bio.Task
  6. import nova.monadic_sfx.util.reactive.store.Reducer
  7. import nova.monadic_sfx.util.reactive.store.Store
  8. case class Todo(id: Int, content: String)
  9. object Todo {
  10. implicit val eqForTodo = Eq.fromUniversalEquals[Todo]
  11. }
  12. object TodoListStore {
  13. @JsonCodec
  14. sealed trait Action
  15. case object Init extends Action
  16. case class Add(content: String) extends Action
  17. case class Edit(id: Int, content: String) extends Action
  18. case class Delete(id: Int) extends Action
  19. private case class InternalAdd(content: String) extends Action
  20. private case object End extends Action
  21. object Action {
  22. implicit val eqForAction = Eq.fromUniversalEquals[Action]
  23. }
  24. case class State(todos: Vector[Todo], counter: Int)
  25. object State {
  26. implicit val eqForState = Eq.fromUniversalEquals[State]
  27. }
  28. def reducer()(
  29. state: State,
  30. action: Action
  31. ): (State, Option[Task[Action]]) =
  32. action match {
  33. case Init => (state, None)
  34. case Add(content) =>
  35. println("hello")
  36. val nextAction = Some(for {
  37. // do some validation
  38. // _ <- logger.debug(s"Received $content")
  39. _ <- Task(println(s"Received $content"))
  40. res <- Task.pure(InternalAdd(content))
  41. } yield res)
  42. (state, nextAction)
  43. case Edit(id, content) =>
  44. val condition: Todo => Boolean = _.id == id
  45. val nextState = state
  46. .modify(_.todos.eachWhere(condition))
  47. .using(_.copy(content = content))
  48. (nextState, None)
  49. case Delete(id) =>
  50. (state.copy(state.todos.filterNot(_.id == id)), None)
  51. case InternalAdd(content) =>
  52. val nextState =
  53. state
  54. .modify(_.todos)
  55. .using(_ :+ Todo(state.counter, content))
  56. .modify(_.counter)
  57. .using(_ + 1)
  58. (nextState, Some(Task.pure(End)))
  59. case End => (state, None)
  60. }
  61. def apply(): Task[Store[Action, State]] =
  62. Task.deferAction(implicit s =>
  63. for {
  64. store <-
  65. Store
  66. .createL[Action, State](
  67. Init,
  68. State(Vector.empty[Todo], 0),
  69. Reducer.withOptionalEffects(reducer() _)
  70. )
  71. } yield store
  72. )
  73. }