83 lines
2.9 KiB
Scala
83 lines
2.9 KiB
Scala
package industries.sunshine.planningpoker
|
|
|
|
import scala.scalajs.js
|
|
import com.raquo.laminar.api.L.{*, given}
|
|
import scala.scalajs.js.Dynamic.{global => g}
|
|
import industries.sunshine.planningpoker.common.Models.*
|
|
|
|
object TableView {
|
|
// new plan. map to players, split by playerId, map into specific card
|
|
// have single funciton that calculates the card from the state.
|
|
// but, can't have map to player, because overall state is required.
|
|
// but can i split full state into several observables by that key? i think i should be able to
|
|
// so, it's more efficient to share an observable, than to create multiple copies...
|
|
def renderTable(roomStateSignal: Signal[RoomStateView]): Element = {
|
|
val playerIdToCardTypeSignal =
|
|
roomStateSignal
|
|
.map(state =>
|
|
state.players.map(p => p.id -> getPlayerCardType(p.id, state.round, p.name, state.me))
|
|
)
|
|
|
|
div(
|
|
className := "w-full h-full border-2 border-amber-700 flex flex-col justify-center items-center bg-green-100",
|
|
div(
|
|
className := "w-full border-2 border-amber-600 flex flex-row justify-center items-center bg-green-100",
|
|
children <-- playerIdToCardTypeSignal.split(_._1) { (id, initial, cardTypeSignal) =>
|
|
renderPlayerCard(cardTypeSignal.map(_._2))
|
|
}
|
|
),
|
|
child <-- roomStateSignal.map { state =>
|
|
if (state.canCloseRound) TableControls.render(roomStateSignal.map(_.round)) else emptyNode
|
|
}
|
|
)
|
|
}
|
|
|
|
trait CardState
|
|
case class NoCard(name: String) extends CardState
|
|
case object CardBack extends CardState
|
|
case class Open(value: String) extends CardState
|
|
|
|
def getPlayerCardType(
|
|
id: PlayerID,
|
|
state: RoundStateView,
|
|
name: String,
|
|
myId: PlayerID
|
|
): CardState = {
|
|
state match {
|
|
case isOpen: RoundStateView.Voting =>
|
|
if (myId == id) {
|
|
isOpen.myCard.fold(NoCard(name))(vote => Open(vote))
|
|
} else isOpen.alreadyVoted.find(_ == id).fold(NoCard(name))(_ => CardBack)
|
|
case isClosed: RoundStateView.Viewing =>
|
|
isClosed.votes
|
|
.find(_._1 == id)
|
|
.fold {
|
|
g.console.error(s"missing vote for player $name")
|
|
Open("error")
|
|
} { case (_, vote) => Open(vote) }
|
|
}
|
|
}
|
|
|
|
def renderPlayerCard(state: Signal[CardState]): Element = {
|
|
val cardTypeStyle = state.map {
|
|
case NoCard(_) => "bg-green-100 text-black border-2 border-black"
|
|
case CardBack => "bg-green-500 border-4 border-green-700"
|
|
case Open(_) => "text-black bg-gray-50 border-black border-2"
|
|
}
|
|
|
|
div(
|
|
className := "w-20 h-40 m-1 rounded flex justify-center items-center m-3",
|
|
className <-- cardTypeStyle,
|
|
div(
|
|
className := "-rotate-45 text-xl",
|
|
child.text <-- state.map {
|
|
case NoCard(name) => name
|
|
case CardBack => ""
|
|
case Open(vote) => vote
|
|
}
|
|
)
|
|
)
|
|
}
|
|
|
|
}
|