diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala index 151e08d..13719b0 100644 --- a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala +++ b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala @@ -11,13 +11,13 @@ def renderApp: Task[Unit] object LaminarApp: - def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWith(_.renderApp) + def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWithZIO(_.renderApp) object LaminarAppLive: - val layer: URLayer[Router[Page], LaminarApp] = - (LaminarAppLive(_)).toLayer[LaminarApp] + val layer: URLayer[AppState & Router[Page], LaminarApp] = + (LaminarAppLive(_, _)).toLayer[LaminarApp] -class LaminarAppLive(router: Router[Page]) extends LaminarApp: +class LaminarAppLive(state: AppState, router: Router[Page]) extends LaminarApp: given Router[Page] = router def renderApp: Task[Unit] = @@ -31,7 +31,7 @@ val appContainer = dom.document.querySelector("#app") render( appContainer, - renderPage(state.MockAppState(using unsafeWindowOwner, router)) + renderPage ) } @@ -47,9 +47,7 @@ ) } - private def renderPage(state: AppState)(using - router: Router[Page] - ): HtmlElement = + private def renderPage: HtmlElement = val pageSplitter = SplitRender[Page, HtmlElement](router.$currentPage) .collectSignal[Page.Detail]( connectors @@ -73,13 +71,13 @@ connectors.DashboardPageConnector(state).apply ) .collect[Page.NotFound](pg => - pages.errors.NotFoundPage(Routes.homePage, pg.url, state.actionBus) + pages.errors.NotFoundPage(Page.homePage, pg.url, state.actionBus) ) .collect[Page.UnhandledError](pg => pages.errors .UnhandledErrorPage( pages.errors.UnhandledErrorPage - .ViewModel(Routes.homePage, pg.errorName, pg.errorMessage), + .ViewModel(Page.homePage, pg.errorName, pg.errorMessage), state.actionBus ) ) diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala index 151e08d..13719b0 100644 --- a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala +++ b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala @@ -11,13 +11,13 @@ def renderApp: Task[Unit] object LaminarApp: - def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWith(_.renderApp) + def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWithZIO(_.renderApp) object LaminarAppLive: - val layer: URLayer[Router[Page], LaminarApp] = - (LaminarAppLive(_)).toLayer[LaminarApp] + val layer: URLayer[AppState & Router[Page], LaminarApp] = + (LaminarAppLive(_, _)).toLayer[LaminarApp] -class LaminarAppLive(router: Router[Page]) extends LaminarApp: +class LaminarAppLive(state: AppState, router: Router[Page]) extends LaminarApp: given Router[Page] = router def renderApp: Task[Unit] = @@ -31,7 +31,7 @@ val appContainer = dom.document.querySelector("#app") render( appContainer, - renderPage(state.MockAppState(using unsafeWindowOwner, router)) + renderPage ) } @@ -47,9 +47,7 @@ ) } - private def renderPage(state: AppState)(using - router: Router[Page] - ): HtmlElement = + private def renderPage: HtmlElement = val pageSplitter = SplitRender[Page, HtmlElement](router.$currentPage) .collectSignal[Page.Detail]( connectors @@ -73,13 +71,13 @@ connectors.DashboardPageConnector(state).apply ) .collect[Page.NotFound](pg => - pages.errors.NotFoundPage(Routes.homePage, pg.url, state.actionBus) + pages.errors.NotFoundPage(Page.homePage, pg.url, state.actionBus) ) .collect[Page.UnhandledError](pg => pages.errors .UnhandledErrorPage( pages.errors.UnhandledErrorPage - .ViewModel(Routes.homePage, pg.errorName, pg.errorMessage), + .ViewModel(Page.homePage, pg.errorName, pg.errorMessage), state.actionBus ) ) diff --git a/app/src/main/scala/mdr/pdb/app/Main.scala b/app/src/main/scala/mdr/pdb/app/Main.scala index 25582c1..733278c 100644 --- a/app/src/main/scala/mdr/pdb/app/Main.scala +++ b/app/src/main/scala/mdr/pdb/app/Main.scala @@ -31,35 +31,29 @@ @JSExportTopLevel("app") object Main extends ZIOApp: - override type Environment = ZEnv & LaminarApp + override type Environment = ZEnv & Router[Page] & AppState & Api & LaminarApp override val tag: EnvironmentTag[Environment] = EnvironmentTag[Environment] + // TODO: config override val layer: ZLayer[ZIOAppArgs, Any, Environment] = - ZEnv.live ++ (Routes.layer >>> LaminarAppLive.layer) + ZEnv.live ++ (Routes.router >+> ApiLive.layer( + Some("/mdr/pdb/api") + ) >+> state.AppStateLive.layer( + unsafeWindowOwner + ) >+> LaminarAppLive.layer) override def run = for - _ <- RIO.async[LaminarApp, Unit](cb => + _ <- RIO.async[Environment, Unit](cb => documentEvents.onDomContentLoaded .foreach(_ => cb(program))(unsafeWindowOwner) ) yield () private def program: RIO[LaminarApp, Unit] = - import Routes.given - for - _ <- testApi - _ <- LaminarApp.renderApp + for _ <- LaminarApp.renderApp yield () - private val testApi: Task[Unit] = Task.attempt { - Api(Some("/mdr/pdb/api")) - .alive(()) - .foreach(org.scalajs.dom.console.log(_))(using - scala.concurrent.ExecutionContext.global - ) - } - // Pull in the stylesheet val css: Css.type = Css diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala index 151e08d..13719b0 100644 --- a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala +++ b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala @@ -11,13 +11,13 @@ def renderApp: Task[Unit] object LaminarApp: - def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWith(_.renderApp) + def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWithZIO(_.renderApp) object LaminarAppLive: - val layer: URLayer[Router[Page], LaminarApp] = - (LaminarAppLive(_)).toLayer[LaminarApp] + val layer: URLayer[AppState & Router[Page], LaminarApp] = + (LaminarAppLive(_, _)).toLayer[LaminarApp] -class LaminarAppLive(router: Router[Page]) extends LaminarApp: +class LaminarAppLive(state: AppState, router: Router[Page]) extends LaminarApp: given Router[Page] = router def renderApp: Task[Unit] = @@ -31,7 +31,7 @@ val appContainer = dom.document.querySelector("#app") render( appContainer, - renderPage(state.MockAppState(using unsafeWindowOwner, router)) + renderPage ) } @@ -47,9 +47,7 @@ ) } - private def renderPage(state: AppState)(using - router: Router[Page] - ): HtmlElement = + private def renderPage: HtmlElement = val pageSplitter = SplitRender[Page, HtmlElement](router.$currentPage) .collectSignal[Page.Detail]( connectors @@ -73,13 +71,13 @@ connectors.DashboardPageConnector(state).apply ) .collect[Page.NotFound](pg => - pages.errors.NotFoundPage(Routes.homePage, pg.url, state.actionBus) + pages.errors.NotFoundPage(Page.homePage, pg.url, state.actionBus) ) .collect[Page.UnhandledError](pg => pages.errors .UnhandledErrorPage( pages.errors.UnhandledErrorPage - .ViewModel(Routes.homePage, pg.errorName, pg.errorMessage), + .ViewModel(Page.homePage, pg.errorName, pg.errorMessage), state.actionBus ) ) diff --git a/app/src/main/scala/mdr/pdb/app/Main.scala b/app/src/main/scala/mdr/pdb/app/Main.scala index 25582c1..733278c 100644 --- a/app/src/main/scala/mdr/pdb/app/Main.scala +++ b/app/src/main/scala/mdr/pdb/app/Main.scala @@ -31,35 +31,29 @@ @JSExportTopLevel("app") object Main extends ZIOApp: - override type Environment = ZEnv & LaminarApp + override type Environment = ZEnv & Router[Page] & AppState & Api & LaminarApp override val tag: EnvironmentTag[Environment] = EnvironmentTag[Environment] + // TODO: config override val layer: ZLayer[ZIOAppArgs, Any, Environment] = - ZEnv.live ++ (Routes.layer >>> LaminarAppLive.layer) + ZEnv.live ++ (Routes.router >+> ApiLive.layer( + Some("/mdr/pdb/api") + ) >+> state.AppStateLive.layer( + unsafeWindowOwner + ) >+> LaminarAppLive.layer) override def run = for - _ <- RIO.async[LaminarApp, Unit](cb => + _ <- RIO.async[Environment, Unit](cb => documentEvents.onDomContentLoaded .foreach(_ => cb(program))(unsafeWindowOwner) ) yield () private def program: RIO[LaminarApp, Unit] = - import Routes.given - for - _ <- testApi - _ <- LaminarApp.renderApp + for _ <- LaminarApp.renderApp yield () - private val testApi: Task[Unit] = Task.attempt { - Api(Some("/mdr/pdb/api")) - .alive(()) - .foreach(org.scalajs.dom.console.log(_))(using - scala.concurrent.ExecutionContext.global - ) - } - // Pull in the stylesheet val css: Css.type = Css diff --git a/app/src/main/scala/mdr/pdb/app/Page.scala b/app/src/main/scala/mdr/pdb/app/Page.scala index 7e067a2..8ac73d3 100644 --- a/app/src/main/scala/mdr/pdb/app/Page.scala +++ b/app/src/main/scala/mdr/pdb/app/Page.scala @@ -21,6 +21,8 @@ object Page: + val homePage: Page = Page.Directory + case class Titled[V](value: V, title: Option[String] = None): val show: String = title.getOrElse(value.toString) diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala index 151e08d..13719b0 100644 --- a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala +++ b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala @@ -11,13 +11,13 @@ def renderApp: Task[Unit] object LaminarApp: - def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWith(_.renderApp) + def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWithZIO(_.renderApp) object LaminarAppLive: - val layer: URLayer[Router[Page], LaminarApp] = - (LaminarAppLive(_)).toLayer[LaminarApp] + val layer: URLayer[AppState & Router[Page], LaminarApp] = + (LaminarAppLive(_, _)).toLayer[LaminarApp] -class LaminarAppLive(router: Router[Page]) extends LaminarApp: +class LaminarAppLive(state: AppState, router: Router[Page]) extends LaminarApp: given Router[Page] = router def renderApp: Task[Unit] = @@ -31,7 +31,7 @@ val appContainer = dom.document.querySelector("#app") render( appContainer, - renderPage(state.MockAppState(using unsafeWindowOwner, router)) + renderPage ) } @@ -47,9 +47,7 @@ ) } - private def renderPage(state: AppState)(using - router: Router[Page] - ): HtmlElement = + private def renderPage: HtmlElement = val pageSplitter = SplitRender[Page, HtmlElement](router.$currentPage) .collectSignal[Page.Detail]( connectors @@ -73,13 +71,13 @@ connectors.DashboardPageConnector(state).apply ) .collect[Page.NotFound](pg => - pages.errors.NotFoundPage(Routes.homePage, pg.url, state.actionBus) + pages.errors.NotFoundPage(Page.homePage, pg.url, state.actionBus) ) .collect[Page.UnhandledError](pg => pages.errors .UnhandledErrorPage( pages.errors.UnhandledErrorPage - .ViewModel(Routes.homePage, pg.errorName, pg.errorMessage), + .ViewModel(Page.homePage, pg.errorName, pg.errorMessage), state.actionBus ) ) diff --git a/app/src/main/scala/mdr/pdb/app/Main.scala b/app/src/main/scala/mdr/pdb/app/Main.scala index 25582c1..733278c 100644 --- a/app/src/main/scala/mdr/pdb/app/Main.scala +++ b/app/src/main/scala/mdr/pdb/app/Main.scala @@ -31,35 +31,29 @@ @JSExportTopLevel("app") object Main extends ZIOApp: - override type Environment = ZEnv & LaminarApp + override type Environment = ZEnv & Router[Page] & AppState & Api & LaminarApp override val tag: EnvironmentTag[Environment] = EnvironmentTag[Environment] + // TODO: config override val layer: ZLayer[ZIOAppArgs, Any, Environment] = - ZEnv.live ++ (Routes.layer >>> LaminarAppLive.layer) + ZEnv.live ++ (Routes.router >+> ApiLive.layer( + Some("/mdr/pdb/api") + ) >+> state.AppStateLive.layer( + unsafeWindowOwner + ) >+> LaminarAppLive.layer) override def run = for - _ <- RIO.async[LaminarApp, Unit](cb => + _ <- RIO.async[Environment, Unit](cb => documentEvents.onDomContentLoaded .foreach(_ => cb(program))(unsafeWindowOwner) ) yield () private def program: RIO[LaminarApp, Unit] = - import Routes.given - for - _ <- testApi - _ <- LaminarApp.renderApp + for _ <- LaminarApp.renderApp yield () - private val testApi: Task[Unit] = Task.attempt { - Api(Some("/mdr/pdb/api")) - .alive(()) - .foreach(org.scalajs.dom.console.log(_))(using - scala.concurrent.ExecutionContext.global - ) - } - // Pull in the stylesheet val css: Css.type = Css diff --git a/app/src/main/scala/mdr/pdb/app/Page.scala b/app/src/main/scala/mdr/pdb/app/Page.scala index 7e067a2..8ac73d3 100644 --- a/app/src/main/scala/mdr/pdb/app/Page.scala +++ b/app/src/main/scala/mdr/pdb/app/Page.scala @@ -21,6 +21,8 @@ object Page: + val homePage: Page = Page.Directory + case class Titled[V](value: V, title: Option[String] = None): val show: String = title.getOrElse(value.toString) diff --git a/app/src/main/scala/mdr/pdb/app/Routes.scala b/app/src/main/scala/mdr/pdb/app/Routes.scala index f81c9d4..46db170 100644 --- a/app/src/main/scala/mdr/pdb/app/Routes.scala +++ b/app/src/main/scala/mdr/pdb/app/Routes.scala @@ -10,9 +10,9 @@ object Routes: - val layer: ULayer[Router[Page]] = ZLayer.succeed(Routes().router) + val layer: ULayer[Routes] = ZLayer.succeed(Routes()) - val homePage: Page = Page.Directory + val router: ULayer[Router[Page]] = layer.project(_.router) class Routes(): import Page.* @@ -33,7 +33,7 @@ given router: Router[Page] = Router[Page]( routes = List( - Route.static(homePage, root / endOfSegments, basePath = base), + Route.static(Page.homePage, root / endOfSegments, basePath = base), Route.static( Dashboard, root / "dashboard" / endOfSegments, diff --git a/app/src/main/scala/mdr/pdb/app/Api.scala b/app/src/main/scala/mdr/pdb/app/Api.scala index fedcd48..ea46468 100644 --- a/app/src/main/scala/mdr/pdb/app/Api.scala +++ b/app/src/main/scala/mdr/pdb/app/Api.scala @@ -1,12 +1,19 @@ package mdr.pdb.app +import zio.* import mdr.pdb.api.Endpoints import sttp.client3.* import sttp.tapir.DecodeResult import org.scalajs.dom import scala.concurrent.Future -class Api(base: Option[String]) extends CustomTapir: +trait Api: + def alive(): Future[DecodeResult[Either[Unit, String]]] + +object ApiLive: + def layer(base: Option[String]): ULayer[Api] = ZLayer.succeed(ApiLive(base)) + +class ApiLive(base: Option[String]) extends Api with CustomTapir: private val backend = FetchBackend( FetchOptions( Some(dom.RequestCredentials.`same-origin`), @@ -14,5 +21,6 @@ ) ) private val baseUri = base.map(b => uri"${b}") - val alive: Unit => Future[DecodeResult[Either[Unit, String]]] = - toClient(Endpoints.alive, baseUri, backend) + private val aliveClient = toClient(Endpoints.alive, baseUri, backend) + override def alive(): Future[DecodeResult[Either[Unit, String]]] = + aliveClient(()) diff --git a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala index 151e08d..13719b0 100644 --- a/app/src/main/scala/mdr/pdb/app/LaminarApp.scala +++ b/app/src/main/scala/mdr/pdb/app/LaminarApp.scala @@ -11,13 +11,13 @@ def renderApp: Task[Unit] object LaminarApp: - def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWith(_.renderApp) + def renderApp: RIO[LaminarApp, Unit] = ZIO.serviceWithZIO(_.renderApp) object LaminarAppLive: - val layer: URLayer[Router[Page], LaminarApp] = - (LaminarAppLive(_)).toLayer[LaminarApp] + val layer: URLayer[AppState & Router[Page], LaminarApp] = + (LaminarAppLive(_, _)).toLayer[LaminarApp] -class LaminarAppLive(router: Router[Page]) extends LaminarApp: +class LaminarAppLive(state: AppState, router: Router[Page]) extends LaminarApp: given Router[Page] = router def renderApp: Task[Unit] = @@ -31,7 +31,7 @@ val appContainer = dom.document.querySelector("#app") render( appContainer, - renderPage(state.MockAppState(using unsafeWindowOwner, router)) + renderPage ) } @@ -47,9 +47,7 @@ ) } - private def renderPage(state: AppState)(using - router: Router[Page] - ): HtmlElement = + private def renderPage: HtmlElement = val pageSplitter = SplitRender[Page, HtmlElement](router.$currentPage) .collectSignal[Page.Detail]( connectors @@ -73,13 +71,13 @@ connectors.DashboardPageConnector(state).apply ) .collect[Page.NotFound](pg => - pages.errors.NotFoundPage(Routes.homePage, pg.url, state.actionBus) + pages.errors.NotFoundPage(Page.homePage, pg.url, state.actionBus) ) .collect[Page.UnhandledError](pg => pages.errors .UnhandledErrorPage( pages.errors.UnhandledErrorPage - .ViewModel(Routes.homePage, pg.errorName, pg.errorMessage), + .ViewModel(Page.homePage, pg.errorName, pg.errorMessage), state.actionBus ) ) diff --git a/app/src/main/scala/mdr/pdb/app/Main.scala b/app/src/main/scala/mdr/pdb/app/Main.scala index 25582c1..733278c 100644 --- a/app/src/main/scala/mdr/pdb/app/Main.scala +++ b/app/src/main/scala/mdr/pdb/app/Main.scala @@ -31,35 +31,29 @@ @JSExportTopLevel("app") object Main extends ZIOApp: - override type Environment = ZEnv & LaminarApp + override type Environment = ZEnv & Router[Page] & AppState & Api & LaminarApp override val tag: EnvironmentTag[Environment] = EnvironmentTag[Environment] + // TODO: config override val layer: ZLayer[ZIOAppArgs, Any, Environment] = - ZEnv.live ++ (Routes.layer >>> LaminarAppLive.layer) + ZEnv.live ++ (Routes.router >+> ApiLive.layer( + Some("/mdr/pdb/api") + ) >+> state.AppStateLive.layer( + unsafeWindowOwner + ) >+> LaminarAppLive.layer) override def run = for - _ <- RIO.async[LaminarApp, Unit](cb => + _ <- RIO.async[Environment, Unit](cb => documentEvents.onDomContentLoaded .foreach(_ => cb(program))(unsafeWindowOwner) ) yield () private def program: RIO[LaminarApp, Unit] = - import Routes.given - for - _ <- testApi - _ <- LaminarApp.renderApp + for _ <- LaminarApp.renderApp yield () - private val testApi: Task[Unit] = Task.attempt { - Api(Some("/mdr/pdb/api")) - .alive(()) - .foreach(org.scalajs.dom.console.log(_))(using - scala.concurrent.ExecutionContext.global - ) - } - // Pull in the stylesheet val css: Css.type = Css diff --git a/app/src/main/scala/mdr/pdb/app/Page.scala b/app/src/main/scala/mdr/pdb/app/Page.scala index 7e067a2..8ac73d3 100644 --- a/app/src/main/scala/mdr/pdb/app/Page.scala +++ b/app/src/main/scala/mdr/pdb/app/Page.scala @@ -21,6 +21,8 @@ object Page: + val homePage: Page = Page.Directory + case class Titled[V](value: V, title: Option[String] = None): val show: String = title.getOrElse(value.toString) diff --git a/app/src/main/scala/mdr/pdb/app/Routes.scala b/app/src/main/scala/mdr/pdb/app/Routes.scala index f81c9d4..46db170 100644 --- a/app/src/main/scala/mdr/pdb/app/Routes.scala +++ b/app/src/main/scala/mdr/pdb/app/Routes.scala @@ -10,9 +10,9 @@ object Routes: - val layer: ULayer[Router[Page]] = ZLayer.succeed(Routes().router) + val layer: ULayer[Routes] = ZLayer.succeed(Routes()) - val homePage: Page = Page.Directory + val router: ULayer[Router[Page]] = layer.project(_.router) class Routes(): import Page.* @@ -33,7 +33,7 @@ given router: Router[Page] = Router[Page]( routes = List( - Route.static(homePage, root / endOfSegments, basePath = base), + Route.static(Page.homePage, root / endOfSegments, basePath = base), Route.static( Dashboard, root / "dashboard" / endOfSegments, diff --git a/app/src/main/scala/mdr/pdb/app/state/AppState.scala b/app/src/main/scala/mdr/pdb/app/state/AppState.scala index 945a313..4d82d99 100644 --- a/app/src/main/scala/mdr/pdb/app/state/AppState.scala +++ b/app/src/main/scala/mdr/pdb/app/state/AppState.scala @@ -1,8 +1,9 @@ package mdr.pdb.app package state +import zio.* import com.raquo.airstream.core.{EventStream, Signal} -import com.raquo.airstream.state.Val +import com.raquo.airstream.state.{Val, Var} import mdr.pdb.{UserInfo, OsobniCislo} import com.raquo.airstream.core.Observer import scala.scalajs.js @@ -16,6 +17,7 @@ import mdr.pdb.UserFunction import mdr.pdb.UserContract import fiftyforms.services.files.File +import sttp.tapir.DecodeResult trait AppState extends components.AppPage.AppState @@ -31,7 +33,11 @@ def parameters: EventStream[List[Parameter]] def actionBus: Observer[Action] -class MockAppState(implicit owner: Owner, router: Router[Page]) +object AppStateLive: + def layer(owner: Owner): URLayer[Api & Router[Page], AppState] = + (AppStateLive(owner, _, _)).toLayer[AppState] + +class AppStateLive(owner: Owner, api: Api, router: Router[Page]) extends AppState: given JsonDecoder[OsobniCislo] = JsonDecoder.string.map(OsobniCislo.apply) @@ -49,6 +55,7 @@ EventStream.withCallback[List[UserInfo]] private val (detailsStream, pushDetails) = EventStream.withCallback[UserInfo] private val (filesStream, pushFiles) = EventStream.withCallback[List[File]] + private val isOnline = Var(false) private val mockData: List[UserInfo] = mockUsers @@ -69,6 +76,18 @@ .collect { case Right(p) => p } .toList + EventStream + .periodic(1000, false, false) + .flatMap(_ => + EventStream + .fromFuture(api.alive()) + .map { + case DecodeResult.Value(_) => true + case _ => false + } + ) + .foreach(isOnline.set)(using owner) + // TODO: Extract to separate event handler actions.events.foreach { case FetchDirectory => pushUsers(mockData) @@ -103,9 +122,9 @@ File("https://tc163.cmi.cz/here", "Example file") ) ) - } + }(using owner) - override def online: Signal[Boolean] = Val(false) + override def online: Signal[Boolean] = isOnline.signal override def users: EventStream[List[UserInfo]] = usersStream.debugWithName("users")