All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lucuma.ui.components.LinkIfValid.scala Maven / Gradle / Ivy

There is a newer version: 0.123.0
Show newest version
// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause

package lucuma.ui.components

import cats.effect.IO
import cats.effect.Temporal
import cats.syntax.all.*
import crystal.react.hooks.*
import crystal.react.syntax.all.*
import japgolly.scalajs.react.*
import japgolly.scalajs.react.vdom.html_<^.*
import lucuma.react.common.*
import org.http4s.Method
import org.http4s.Request
import org.http4s.Uri
import org.http4s.client.Client
import org.typelevel.log4cats.Logger

import scala.concurrent.duration.*
import scala.concurrent.duration.FiniteDuration

/**
 * A component that renders a link if the link is valid, otherwise it just renders the children.
 */
case class LinkIfValid(client: Client[IO])(val href: String, val mods: TagMod*)(
  val children: VdomNode*
)(using
  val logger:   Logger[IO],
  val F:        Temporal[IO]
) extends ReactFnProps(LinkIfValid.component)

object LinkIfValid:
  private type Props = LinkIfValid

  private val PollInterval: FiniteDuration = 5.seconds

  private val ProxyUri: String = "https://cors-proxy.lucuma.xyz" // Avoid CORS

  private val component =
    ScalaFnComponent
      .withHooks[Props]
      .useState(false) // isValid
      .useEffectStreamWithDepsBy((_, isValid) => isValid.value): (props, isValid) =>
        isValidValue =>
          import props.F

          Option
            .when(!isValidValue):
              Uri
                .fromString(s"$ProxyUri/${props.href}")
                .bimap(
                  parseError =>
                    fs2.Stream.eval(props.logger.error(s"Error parsing URI: $parseError")),
                  uri =>
                    fs2.Stream
                      .eval:
                        props.logger.trace(s"Checking URI: $uri") >>
                          props.client
                            .successful(Request[IO](Method.HEAD, uri))
                            .flatMap: valid => // If valid is true, this will cancel the stream
                              props.logger.trace(s"Checked URI: $uri, isValid: $valid") >>
                                isValid.setStateAsync(valid)
                      .repeat
                      .spaced[IO](PollInterval, startImmediately = true)
                )
                .bisequence
                .void
            .orEmpty
      .render: (props, isValid) =>
        if isValid.value
        then <.a(^.href := props.href)(props.mods*)(React.Fragment(props.children*))
        else React.Fragment(props.children*)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy