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

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
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 io.odin.Logger
  6. import monix.bio.Task
  7. import nova.monadic_sfx.util.reactive.store.Middlewares.actionLoggerMiddleware
  8. import nova.monadic_sfx.util.reactive.store.Reducer
  9. import nova.monadic_sfx.util.reactive.store.Store
  10. case class Todo(id: Int, content: String)
  11. object Todo {
  12. implicit val eqForTodo = Eq.fromUniversalEquals[Todo]
  13. }
  14. object TodoListStore {
  15. @JsonCodec
  16. sealed trait Action
  17. case object Init extends Action
  18. case class Add(content: String) extends Action
  19. case class Edit(id: Int, content: String) extends Action
  20. case class Delete(id: Int) extends Action
  21. private case class InternalAdd(content: String) extends Action
  22. private case object End extends Action
  23. object Action {
  24. implicit val eqForAction = Eq.fromUniversalEquals[Action]
  25. }
  26. case class State(todos: Vector[Todo], counter: Int)
  27. object State {
  28. implicit val eqForState = Eq.fromUniversalEquals[State]
  29. }
  30. def reducer(logger: Logger[Task])(
  31. state: State,
  32. action: Action
  33. ): (State, Option[Task[Action]]) =
  34. action match {
  35. case Init => (state, None)
  36. case Add(content) =>
  37. val nextAction = Some(for {
  38. // do some validation
  39. // _ <- logger.debug(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(logger.debug(s"Received $content") >> Task.pure(End)))
  59. case End => (state, None)
  60. }
  61. def apply(logger: Logger[Task]): Task[Store[Action, State]] =
  62. Task.deferAction(implicit s =>
  63. for {
  64. logMware <- actionLoggerMiddleware[Action, State](logger, "TodoStore")
  65. store <-
  66. Store
  67. .createL[Action, State](
  68. Init,
  69. State(Vector.empty[Todo], 0),
  70. Reducer.withOptionalEffects(reducer(logger) _),
  71. Seq(logMware)
  72. )
  73. } yield store
  74. )
  75. }
  76. // Task.deferAction(implicit s =>
  77. // Store
  78. // .createJsonL[Action, State](
  79. // Init,
  80. // State(Vector.empty[Todo], 0),
  81. // Reducer.withOptionalEffects(reducer(logger) _),
  82. // "TodoStore",
  83. // logger
  84. // // Seq(
  85. // // actionLoggerMiddleware(logger, "TodoStore")
  86. // // // actionLoggerMiddleware(logger, "TodoStore2")
  87. // // )
  88. // )
  89. // )