diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala index 5b78503b105b..95488cbe1a13 100644 --- a/modules/relay/src/main/RelayApi.scala +++ b/modules/relay/src/main/RelayApi.scala @@ -69,7 +69,7 @@ final class RelayApi( targetRound <- officialTarget(rt.round) yield ( rt.round, - nav.copy(round = rt.round.id.some, sourceRound = sourceRound, targetRound = targetRound) + nav.copy(roundId = rt.round.id.some, sourceRound = sourceRound, targetRound = targetRound) ) def formNavigation(tour: RelayTour): Fu[ui.FormNavigation] = for diff --git a/modules/relay/src/main/RelayRound.scala b/modules/relay/src/main/RelayRound.scala index a9c72981da34..c655e1ae1798 100644 --- a/modules/relay/src/main/RelayRound.scala +++ b/modules/relay/src/main/RelayRound.scala @@ -118,6 +118,9 @@ object RelayRound: case Url(url: URL) extends Upstream case Urls(urls: List[URL]) extends Upstream case Ids(ids: List[GameId]) extends Upstream + def isUrl = this match + case Url(_) => true + case _ => false def lcc: Option[Lcc] = this match case Url(url) => url.toString match diff --git a/modules/relay/src/main/ui/FormUi.scala b/modules/relay/src/main/ui/FormUi.scala index ab02c8facdc9..90df6140cf80 100644 --- a/modules/relay/src/main/ui/FormUi.scala +++ b/modules/relay/src/main/ui/FormUi.scala @@ -11,13 +11,18 @@ case class FormNavigation( group: Option[RelayGroup.WithTours], tour: RelayTour, rounds: List[RelayRound], - round: Option[RelayRoundId], + roundId: Option[RelayRoundId], sourceRound: Option[RelayRound.WithTour] = none, targetRound: Option[RelayRound.WithTour] = none, newRound: Boolean = false ): def tourWithGroup = RelayTour.WithGroupTours(tour, group) def tourWithRounds = RelayTour.WithRounds(tour, rounds) + def round = roundId.flatMap(id => rounds.find(_.id == id)) + def featurableRound = round + .ifTrue(targetRound.isEmpty) + .filter: r => + r.sync.upstream.forall(up => up.isUrl && !up.hasLcc) final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): import helpers.{ *, given } @@ -40,7 +45,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): nav.rounds.map: r => a( href := routes.RelayRound.edit(r.id), - cls := List("subnav__subitem text" -> true, "active" -> nav.round.has(r.id)), + cls := List("subnav__subitem text" -> true, "active" -> nav.roundId.has(r.id)), dataIcon := ( if r.finished then Icon.Checkmark else if r.hasStarted then Icon.DiscBig @@ -106,7 +111,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): ) ), standardFlash, - inner(form, routes.RelayRound.create(nav.tour.id), nav.tour, round = none) + inner(form, routes.RelayRound.create(nav.tour.id), nav) ) def edit( @@ -126,7 +131,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): strong(a(href := tr.path, cls := "text", dataIcon := Icon.RadioTower)(tr.fullName)), "." ), - inner(form, routes.RelayRound.update(r.id), nav.tour, round = r.some, nav.sourceRound), + inner(form, routes.RelayRound.update(r.id), nav), div(cls := "relay-form__actions")( postForm(action := routes.RelayRound.reset(r.id))( submitButton( @@ -147,15 +152,13 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): private def inner( form: Form[RelayRoundForm.Data], url: play.api.mvc.Call, - t: RelayTour, - round: Option[RelayRound], - sourceRound: Option[RelayRound.WithTour] = none + nav: FormNavigation )(using ctx: Context) = - val lccWarning = round + val lccWarning = nav.round .flatMap(_.sync.upstream) .exists(_.hasLcc) - .option( - flashMessage("box")( + .option: + flashMessage("box relay-form__lcc-deprecated")( p(strong("Please use the ", a(href := broadcasterUrl)("Lichess Broadcaster App"))), p( "LiveChessCloud support is deprecated and will be removed soon.", @@ -163,12 +166,22 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): "If you need help, please contact us at broadcast@lichess.org." ) ) - ) + val contactUsForOfficial = nav.featurableRound.isDefined + .option: + flashMessage("box relay-form__contact-us")( + p( + "Is this a tournament you organize? Do you want Lichess to feature it on the ", + a(href := routes.RelayTour.index(1))("broadcast page"), + "?" + ), + p(trans.contact.sendEmailAt("broadcast@lichess.org")) + ) + .pp postForm(cls := "form3", action := url)( (!Granter.opt(_.StudyAdmin)).option: div(cls := "form-group")( div(cls := "form-group")(ui.howToUse), - (round.isEmpty && t.createdAt.isBefore(nowInstant.minusMinutes(1))).option: + (nav.round.isEmpty && nav.tour.createdAt.isBefore(nowInstant.minusMinutes(1))).option: p(dataIcon := Icon.InfoCircle, cls := "text"): trb.theNewRoundHelp() ) @@ -189,13 +202,13 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): "Where do the games come from?" )(form3.select(_, RelayRoundForm.sourceTypes)), div(cls := "relay-form__sync relay-form__sync-url")( - lccWarning, + lccWarning.orElse(contactUsForOfficial), form3.group( form("syncUrl"), trb.sourceSingleUrl(), help = trb.sourceUrlHelp().some )(form3.input(_)), - sourceRound.map: source => + nav.sourceRound.map: source => flashMessage("round-push")( "Getting real-time updates from ", strong(a(href := source.path)(source.fullName)), @@ -235,6 +248,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): half = false )(form3.input(_))(cls := "relay-form__sync relay-form__sync-ids none"), div(cls := "form-group relay-form__sync relay-form__sync-push none")( + contactUsForOfficial, p( "Send your local games to Lichess using the ", a(href := broadcasterUrl)("Lichess Broadcaster App"), @@ -280,7 +294,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): )(form3.input(_)) ) ), - form3.fieldset("Advanced", toggle = round.exists(r => r.sync.delay.isDefined).some)( + form3.fieldset("Advanced", toggle = nav.round.exists(r => r.sync.delay.isDefined).some)( form3.split( form3.group( form("delay"), @@ -323,7 +337,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi): ) ), form3.actions( - a(href := routes.RelayTour.show(t.slug, t.id))(trans.site.cancel()), + a(href := routes.RelayTour.show(nav.tour.slug, nav.tour.id))(trans.site.cancel()), form3.submit(trans.site.apply()) ) ) diff --git a/modules/web/src/main/ui/contact.scala b/modules/web/src/main/ui/contact.scala index 05dab2c9c2b7..50e12a301cec 100644 --- a/modules/web/src/main/ui/contact.scala +++ b/modules/web/src/main/ui/contact.scala @@ -222,18 +222,6 @@ object contact: ) ) ), - Leaf( - "broadcast", - wantBroadcastTournament(), - frag( - p(a(href := routes.RelayTour.help)(learnHowToMakeBroadcasts()), "."), - p( - contactAboutOfficialBroadcasts(), - " ", - sendEmailAt(contactEmailLink("broadcast@lichess.org")) - ) - ) - ), frag( p(doNotMessageModerators()), p(sendAppealTo(a(href := routes.Appeal.home)(routes.Appeal.home.url))), diff --git a/translation/source/contact.xml b/translation/source/contact.xml index 40c918c23816..58165b14468f 100644 --- a/translation/source/contact.xml +++ b/translation/source/contact.xml @@ -55,9 +55,7 @@ In certain circumstances when playing against a bot account, a rated game may not award points if it is determined that the player is abusing the bot for rating points. Error page If you faced an error page, you may report it: - I want to broadcast a tournament Learn how to make your own broadcasts on Lichess - You can also contact the broadcast team about official broadcasts. Appeal for a ban or IP restriction Engine or cheat mark You may send an appeal to %s. diff --git a/ui/bits/css/relay/_form.scss b/ui/bits/css/relay/_form.scss index 1e239316b9ad..d0868ef5073c 100644 --- a/ui/bits/css/relay/_form.scss +++ b/ui/bits/css/relay/_form.scss @@ -29,7 +29,7 @@ } } -.flash-box { +.relay-form__lcc-deprecated { border: 5px solid $m-brag_bg--mix-70; &::before { @@ -39,6 +39,16 @@ } } +.relay-form__contact-us.flash-box { + border: 5px solid $m-secondary_bg--mix-70; + + &::before { + color: $c-secondary; + content: $licon-UploadCloud; + font-size: 4em; + } +} + .flash-round-push { border: 5px solid $c-good; background: $c-bg-box;