more coach form WIP

coach
Thibault Duplessis 2016-08-22 14:04:01 +02:00
parent 6ab672ffa6
commit a9153fd2b4
9 changed files with 77 additions and 12 deletions

View File

@ -1,13 +1,22 @@
@(c: lila.coach.Coach.WithUser, form: Form[_])(implicit ctx: Context)
@group(field: play.api.data.Field, name: Html, half: Boolean = false)(html: Html) = {
<div class="form-group@if(half){ half}@if(field.hasErrors){ has-error}">
@import play.api.data.Field
@import lila.coach.CoachForm.booleanChoices
@group(field: Field, name: Html, half: Boolean = false, largeLabel: Boolean = false)(html: Html) = {
<div class="form-group@if(half){ half}@if(field.hasErrors){ has-error}@if(largeLabel){ large-label}">
@html
<label for="@field.id" class="control-label">@name</label>
<i class="bar"></i>
</div>
}
@markdown(field: Field, name: Html) = {
@group(field, name, largeLabel = true) {
<textarea name="@field.name" id="@field.id">@field.value</textarea>
}
}
@moreCss = {
@cssTag("material.form.css")
@cssTag("coach.css")
@ -17,12 +26,26 @@
evenMoreCss = Some(cssTag("material.form.css"))) {
<div class="coach_edit content_box small_box no_padding">
<h1 class="lichess_title">
Coach @userLink(c.user)
@userLink(c.user) coach page
</h1>
<form class="content_box_content material form" action="@routes.Coach.edit" method="POST">
@group(form("headline"), Html("Headline")) {
@base.input(form("headline"))
<div>
@group(form("enabledByUser"), Html("Published in lichess coaches list"), half = true) {
@base.select(form("enabledByUser"), booleanChoices)
}
@group(form("available"), Html("Currently available for lessons"), half = true) {
@base.select(form("available"), booleanChoices)
}
</div>
@group(form("profile.headline"), Html("Short and inspiring headline")) {
@base.input(form("profile.headline"))
}
@markdown(form("profile.description"), Html("Who are you? <em>age, profession, country... let your students know you</em>"))
@markdown(form("profile.playingExperience"), Html("Playing experience <em>tournaments played, best wins, other achievements</em>"))
@markdown(form("profile.teachingExperience"), Html("Teaching experience <em>diplomas, years of practice, best student results</em>"))
@markdown(form("profile.otherExperience"), Html("Other experiences <em>e.g. as chess commentator, or teaching other domains</em>"))
@markdown(form("profile.skills"), Html("Best skills in chess and teaching"))
@markdown(form("profile.methodology"), Html("Teaching methodology <em>How you prepare and run lessons. How you follow up with students.</em>"))
<div class="button-container">
<button type="submit" class="submit button text" data-icon="E">Save now</button>
</div>

View File

@ -370,9 +370,9 @@ POST /inbox/$id<\w{8}>/delete controllers.Message.delete(id: String)
# Coach
GET /coach controllers.Coach.index
GET /coach/:username controllers.Coach.show(username: String)
GET /coach/edit controllers.Coach.edit
POST /coach/edit controllers.Coach.editApply
GET /coach/:username controllers.Coach.show(username: String)
# Paste
GET /paste controllers.Importer.importGame

View File

@ -48,5 +48,6 @@ private[api] final class Cli(bus: lila.common.Bus, renderer: ActorSelection) ext
lila.blog.Env.current.cli.process orElse
lila.study.Env.current.cli.process orElse
lila.studySearch.Env.current.cli.process orElse
lila.coach.Env.current.cli.process orElse
process
}

View File

@ -13,5 +13,5 @@ private[coach] object BsonHandlers {
implicit val CoachProfileMarkdownBSONHandler = stringAnyValHandler[CoachProfile.Markdown](_.value, CoachProfile.Markdown.apply)
implicit val CoachProfileBSONHandler = Macros.handler[CoachProfile]
implicit val CoachBSONHandler = Macros.handler[Coach]
implicit val CoachBSONHandler = lila.db.BSON.LoggingHandler(logger)(Macros.handler[Coach])
}

View File

@ -25,6 +25,14 @@ final class CoachApi(coll: Coll) {
def update(c: Coach.WithUser, data: CoachForm.Data): Funit =
coll.update($id(c.coach.id), data(c.coach)).void
def init(username: String): Fu[String] = find(username) flatMap {
case Some(_) => fuccess(s"Coach $username already exists.")
case None => UserRepo named username flatMap {
case None => fuccess(s"No such username $username")
case Some(user) => coll.insert(Coach make user) inject "Done!"
}
}
private def withUser(user: User)(coach: Coach): Coach.WithUser =
Coach.WithUser(coach, user)
}

View File

@ -9,25 +9,31 @@ object CoachForm {
def edit(coach: Coach) = Form(mapping(
"hourlyRate" -> optional(number(min = 5, max = 500)),
"available" -> optional(number),
"enabledByUser" -> boolean,
"available" -> boolean,
"profile" -> profileMapping
)(Data.apply)(Data.unapply)) fill Data(
hourlyRate = coach.hourlyRate.map(_.value),
available = coach.available.value option 1,
enabledByUser = coach.enabledByUser.value,
available = coach.available.value,
profile = coach.profile)
case class Data(
hourlyRate: Option[Int],
available: Option[Int],
enabledByUser: Boolean,
available: Boolean,
profile: CoachProfile) {
def apply(coach: Coach) = coach.copy(
hourlyRate = hourlyRate.map(_ * 100) map Coach.Cents.apply,
available = Coach.Available(available.isDefined),
enabledByUser = Coach.Enabled(enabledByUser),
available = Coach.Available(available),
profile = profile,
updatedAt = DateTime.now)
}
val booleanChoices = Seq("true" -> "Yes", "false" -> "No")
private def profileMapping = mapping(
"headline" -> optional(nonEmptyText(minLength = 5, maxLength = 140)),
"description" -> optional(markdown),

View File

@ -16,6 +16,12 @@ final class Env(
lazy val api = new CoachApi(
coll = coachColl)
def cli = new lila.common.Cli {
def process = {
case "coach" :: "init" :: username :: Nil => api init username
}
}
}
object Env {

View File

@ -0,0 +1,17 @@
.coach_edit .material.form {
margin: 30px 20px 20px 20px;
}
.coach_edit .material.form .form-group textarea {
height: 8em;
}
.coach_edit .material.form .form-group.large-label {
margin-top: 4.25rem;
}
.coach_edit .material.form .form-group.large-label .control-label {
opacity: 0.8!important;
top: -2rem!important;
}
.coach_edit .material.form .form-group.large-label .control-label em {
opacity: 0.8;
display: block;
}

View File

@ -92,6 +92,9 @@
font-weight: normal;
transition: all 0.28s ease;
}
.material.form .form-group .control-label em {
transition: all 0.28s ease;
}
.material.form .form-group.no-label {
margin-top: -1.5em;
}
@ -157,7 +160,8 @@ body.dark .material.form .form-group select option {
outline: none;
}
.material.form .form-group *:focus ~ .control-label,
.material.form .form-group *:focus ~ .control-label strong {
.material.form .form-group *:focus ~ .control-label strong,
.material.form .form-group *:focus ~ .control-label em {
color: #3893E8;
}
.material.form .form-group *:focus ~ .bar::before {