Skip to content

Commit

Permalink
add proper not found page, update page titles on pushState
Browse files Browse the repository at this point in the history
  • Loading branch information
greg2010 committed Feb 25, 2021
1 parent d0241e8 commit d5e2ec9
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 18 deletions.
41 changes: 26 additions & 15 deletions frontend/src/main/scala/org/kys/athena/App.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,31 @@ import org.kys.athena.riot.api.dto.common.Platform
import org.kys.athena.util.CSSUtil
import org.kys.athena.components.LandingPage
import org.kys.athena.components.common.{AppBar, Footer}
import org.kys.athena.components.notfound.NotFoundPage
import org.kys.athena.components.ongoing.OngoingPage
import org.kys.athena.components.pregame.PregamePage
import org.scalajs.dom
import org.scalajs.dom.document
import urldsl.errors.DummyError
import urldsl.vocabulary.{FromString, Printer, UrlMatching}


object App {
implicit val fs = new FromString[Platform, DummyError] {
private implicit val platformDecoder: FromString[Platform, DummyError] = new FromString[Platform, DummyError] {
override def fromString(str: String): Either[DummyError, Platform] = {
Platform.withNameEither(str).left.map(_ => DummyError.dummyError)
}
}
implicit val pr = new Printer[Platform] {

private implicit val platformPrinter: Printer[Platform] = new Printer[Platform] {
override def print(t: Platform): String = t.entryName
}

implicit val ls = new FromString[List[String], DummyError] {
private implicit val listDecoder: FromString[List[String], DummyError] = new FromString[List[String], DummyError] {
override def fromString(str: String): Either[DummyError, List[String]] = Right(str.split(',').toList)
}

implicit val sl = new Printer[List[String]] {
private implicit val listPrinter: Printer[List[String]] = new Printer[List[String]] {
override def print(t: List[String]) = t.mkString(",")
}

Expand All @@ -44,34 +47,42 @@ object App {
Route[OngoingRoute, (Platform, String)](
encode = p => (p.realm, p.name),
decode = a => OngoingRoute(a._1, a._2),
pattern = root / segment[Platform] / segment[String] / endOfSegments)
)
pattern = root / segment[Platform] / segment[String] / endOfSegments),
// This must be last (catch-all to prevent the router from crashing)
Route[RouteNotFound, List[String]](
encode = p => p.restOfSegments,
decode = a => RouteNotFound(a),
pattern = root / remainingSegments))

private val router = new Router[PageRoute](
initialUrl = dom.document.location.href,
origin = dom.document.location.origin.get,
routes = routes,
owner = unsafeWindowOwner, // this router will live as long as the window
$popStateEvent = windowEvents.onPopState,
getPageTitle = _.title, // mock page title (displayed in the browser tab next to favicon)
getPageTitle = _.title, // Currently ignored by most browsers (per MDN api spec)
serializePage = page => page.asJson.noSpaces, // serialize page data for storage in History API log
deserializePage = pageStr => {
decode[PageRoute](pageStr).fold(e => ErrorRoute(e.getMessage), identity)
} // deserialize the above
)
decode[PageRoute](pageStr).fold(e => RouteNotFound(List("error")), identity)
})

// Currently title in pushState is ignored by most (all?) browsers. To fix, dispatch a custom event
// to update the title on route events
router.$currentPage.foreach { page =>
document.title = page.title
}(unsafeWindowOwner)

private val hideSearchBar = Var(false)

private val splitter: SplitRender[PageRoute, HtmlElement] =
SplitRender[PageRoute, HtmlElement](router.$currentPage)
.collectStatic(LandingRoute) {
LandingPage.render(windowEvents.onMouseMove)
}.collectStatic(RouteNotFound) {
LandingPage.render(windowEvents.onMouseMove)
SplitRender[PageRoute, HtmlElement](router.$currentPage).collectStatic(LandingRoute) {
LandingPage.render
}.collect[OngoingRoute] { page =>
OngoingPage.render(page, hideSearchBar.writer)
}.collect[PregameRoute] { page =>
PregamePage.render(page)
}.collect[RouteNotFound] { page =>
NotFoundPage.render(page.restOfSegments)
}

def render(): HtmlElement = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.kys.athena.components.notfound

import com.raquo.laminar.api.L._
import org.kys.athena.components.common.{AlephEye, Link}
import org.kys.athena.routes.LandingRoute
import org.kys.athena.util.CSSUtil.{paletteContainer, paperCls}


object NotFoundPage {
def render(segments: List[String]): HtmlElement = {
div(
cls := s"flex flex-col items-center justify-center p-4 lg:p-8 divide-y divide-gray-500 $paperCls",
backgroundColor := paletteContainer,
AlephEye(),
div(
cls := "flex flex-col justify-center items-center",
span(
cls := "text-xl my-2",
s"Oops! Page /${segments.mkString("/")} is not found. Make sure your URL is correct."
),
Link(
LandingRoute,
button(
cls := "px-4 py-2 border border-gray-500 rounded-lg mt-2",
"Go home"))))
}
}
7 changes: 4 additions & 3 deletions frontend/src/main/scala/org/kys/athena/routes/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ package object routes {
}

final case object LandingRoute extends PageRoute {
override val title = "Athena"
override val title = "Athena - Landing Page"
}
final case object RouteNotFound extends PageRoute {
final case class RouteNotFound(restOfSegments: List[String]) extends PageRoute {
override val title: String = "Athena - Page not Found"
}

final case class ErrorRoute(msg: String) extends PageRoute {
override val title: String = "Athena - Error"
}
final case class OngoingRoute(realm: Platform, name: String) extends PageRoute {
override val title: String = s"Athena - $realm/$name"
override val title: String = s"Athena - Current game of $realm/$name"
}

final case class PregameRoute(realm: Platform, names: List[String]) extends PageRoute {
Expand Down

0 comments on commit d5e2ec9

Please sign in to comment.