package com.weEat.modules import com.raquo.laminar.api.L._ import org.scalajs.dom.document import scala.concurrent.ExecutionContext import scala.concurrent.Future import scala.concurrent.Promise import scala.util.Try object Overlay { implicit val ctx = org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits.global object Closed extends Throwable() private class _PromiseWrapper[T](promise: Promise[T], root: RootNode)(implicit ctx: ExecutionContext) extends Promise[T] { lazy val future = { val result = promise.future result.onComplete((_) => root.unmount()) result } def isCompleted = promise.isCompleted def tryComplete(result: Try[T]) = promise.tryComplete(result) } private def _toLoadingNode(content: Future[Node]) = Signal.fromFuture(content) map { case Some(node) => node case None => div(cls := "loader", span(), span(), span(), span(), span(), span() ) } private val _backgroundStyle = Seq( backgroundColor := "rgba(0, 0, 0, 0.5)", position := "fixed", textAlign := "center", top := "0", left := "0", bottom := "0", right := "0", zIndex := 99 ) private val _popupWindowStyle = Seq( cls := "p-4 position-relative", backgroundColor := "#ffffff", borderRadius := "1em", top := "50%", transform := "translateY(-50%)", maxHeight := "80%", overflowY := "auto", display := "inline-block", verticalAlign := "middle", maxWidth := "50%" ) private def _internal[T](content: Node)(implicit ctx: ExecutionContext) = { val promise = Promise[T]() val overlay = div( _backgroundStyle, div( _popupWindowStyle, content ) ) overlay.amend(onClick.stopPropagation --> ((event) => if (event.target == overlay.ref) { promise.failure(Closed) } )) new _PromiseWrapper(promise, render(document.body, overlay)) } def confirm[T]( content: Node, readyToSubmit: Signal[Boolean] = Val(true) )(confirmFn: () => T) = { val cancelBtn = button( typ := "button", cls := "btn btn-light", "Cancel" ) val submitBtn = button( typ := "button", cls := "btn btn-success", disabled <-- readyToSubmit.map(!_), "Submit" ) val promise = _internal[T](div( content, div( cls := "pt-2 pb-2", textAlign := "right", cancelBtn, submitBtn ) )) cancelBtn.amend( onClick.stopPropagation --> ((_) => promise.failure(Closed)) ) submitBtn.amend( onClick.stopPropagation --> ((_) => promise.success(confirmFn())) ) promise.future } def confirmFuture[T]( content: Future[Node], readyToSubmit: Signal[Boolean] = Val(true) )(confirmFn: () => Future[T])(implicit ctx: ExecutionContext) = { val cancelBtn = button( typ := "button", cls := "btn btn-light", "Cancel" ) val submitBtn = button( typ := "button", cls := "btn btn-success", disabled <-- readyToSubmit.map(!_), "Submit" ) val promise = _internal[T](div( child <-- _toLoadingNode(content), div( cls := "pt-2 pb-2", textAlign := "right", cancelBtn, submitBtn ) )) cancelBtn.amend( onClick.stopPropagation --> ((_) => {promise.failure(Closed)}) ) submitBtn.amend( onClick.stopPropagation --> ((_) => {promise.completeWith(confirmFn())}) ) promise.future } }