main frontend functionality working
This commit is contained in:
parent
8377743d1b
commit
d791332b9f
3 changed files with 122 additions and 56 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import org.scalajs.linker.interface.ModuleSplitStyle
|
||||
|
||||
lazy val fahrtenbuch = project.in(file("."))
|
||||
lazy val fahrtenbuch = project
|
||||
.in(file("."))
|
||||
.enablePlugins(ScalaJSPlugin) // Enable the Scala.js plugin in this project
|
||||
.settings(
|
||||
scalaVersion := "3.7.1",
|
||||
|
|
@ -18,12 +19,14 @@ lazy val fahrtenbuch = project.in(file("."))
|
|||
scalaJSLinkerConfig ~= {
|
||||
_.withModuleKind(ModuleKind.ESModule)
|
||||
.withModuleSplitStyle(
|
||||
ModuleSplitStyle.SmallModulesFor(List("fahrtenbuch")))
|
||||
ModuleSplitStyle.SmallModulesFor(List("fahrtenbuch"))
|
||||
)
|
||||
},
|
||||
|
||||
/* Depend on the scalajs-dom library.
|
||||
* It provides static types for the browser DOM APIs.
|
||||
*/
|
||||
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0",
|
||||
libraryDependencies += "com.raquo" %%% "laminar" % "17.2.1"
|
||||
libraryDependencies += "com.raquo" %%% "laminar" % "17.2.1",
|
||||
libraryDependencies += "de.tu-darmstadt.stg" %%% "rdts" % "0.37.0"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package fahrtenbuch
|
||||
|
||||
import rdts.base.Uid
|
||||
import scala.scalajs.js.Date
|
||||
import com.raquo.laminar.api.L.{*, given}
|
||||
import com.raquo.laminar.api.features.unitArrows
|
||||
import org.scalajs.dom.HTMLTableRowElement
|
||||
import com.raquo.laminar.nodes.ReactiveHtmlElement
|
||||
|
||||
type Id = String
|
||||
import fahrtenbuch.Main.editClickBus
|
||||
import scala.annotation.threadUnsafe
|
||||
import fahrtenbuch.Main.entryEditBus
|
||||
|
||||
case class EntryComponent(
|
||||
entry: Entry,
|
||||
|
|
@ -13,18 +16,39 @@ case class EntryComponent(
|
|||
):
|
||||
def render: ReactiveHtmlElement[HTMLTableRowElement] = {
|
||||
if editMode then
|
||||
val driverInput = input(cls := "input", value := entry.driver)
|
||||
val startKmInput =
|
||||
input(cls := "input", value := entry.startKm.toString())
|
||||
val endKmInput = input(cls := "input", value := entry.endKm.toString())
|
||||
val animalInput = input(cls := "input", value := entry.animal)
|
||||
val costWearInput =
|
||||
input(cls := "input", value := entry.costWear.toString())
|
||||
val costTotalInput =
|
||||
input(cls := "input", value := entry.costTotal.toString())
|
||||
val paidCheckbox = input(`type` := "checkbox", checked := entry.paid)
|
||||
tr(
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
// td(input(cls := "input", value := entry.date.toDateString())),
|
||||
td(driverInput),
|
||||
td(startKmInput),
|
||||
td(endKmInput),
|
||||
td(animalInput),
|
||||
td(),
|
||||
td(),
|
||||
td(paidCheckbox),
|
||||
td(
|
||||
button(
|
||||
cls := "button is-success",
|
||||
onClick --> {
|
||||
editClickBus.emit(entry.id, false)
|
||||
entryEditBus.emit(
|
||||
entry.copy(
|
||||
startKm = startKmInput.ref.value.toDouble,
|
||||
endKm = endKmInput.ref.value.toDouble,
|
||||
animal = animalInput.ref.value,
|
||||
paid = paidCheckbox.ref.checked
|
||||
)
|
||||
)
|
||||
},
|
||||
span(
|
||||
cls := "icon edit",
|
||||
i(cls := "mdi mdi-18px mdi-check-bold")
|
||||
|
|
@ -34,17 +58,18 @@ case class EntryComponent(
|
|||
)
|
||||
else
|
||||
tr(
|
||||
td(entry.date.toDateString()),
|
||||
// td(entry.date.toDateString()),
|
||||
td(entry.driver),
|
||||
td(entry.startKm),
|
||||
td(entry.endKm),
|
||||
td(entry.animal),
|
||||
td(entry.costWear),
|
||||
td(entry.costTotal),
|
||||
td(entry.paid),
|
||||
td(s"${entry.costWear}€"),
|
||||
td(s"${entry.costTotal}€"),
|
||||
td(if entry.paid then "Ja" else "Nein"),
|
||||
td(
|
||||
button(
|
||||
cls := "button is-link",
|
||||
onClick --> editClickBus.emit(entry.id, true),
|
||||
span(cls := "icon edit", i(cls := "mdi mdi-18px mdi-pencil"))
|
||||
)
|
||||
)
|
||||
|
|
@ -52,13 +77,13 @@ case class EntryComponent(
|
|||
}
|
||||
|
||||
case class Entry(
|
||||
id: Id,
|
||||
id: Uid,
|
||||
startKm: Double,
|
||||
endKm: Double,
|
||||
date: Date,
|
||||
animal: String,
|
||||
paid: Boolean,
|
||||
driver: String
|
||||
driver: String,
|
||||
date: Option[Date] = None
|
||||
):
|
||||
val distance = endKm - startKm
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import scala.scalajs.js
|
|||
import scala.scalajs.js.annotation.*
|
||||
import org.scalajs.dom
|
||||
import com.raquo.laminar.api.L.{*, given}
|
||||
import com.raquo.laminar.api.features.unitArrows
|
||||
import scala.scalajs.js.Date
|
||||
import rdts.base.Uid
|
||||
|
||||
// import javascriptLogo from "/javascript.svg"
|
||||
//@js.native @JSImport("/javascript.svg", JSImport.Default)
|
||||
|
|
@ -20,27 +22,75 @@ def Fahrtenbuch(): Unit =
|
|||
|
||||
object Main {
|
||||
|
||||
val entries = Var(
|
||||
List(
|
||||
Entry("0", 100.0, 200.0, new Date(), "🐷", true, "Gesine"),
|
||||
Entry("1", 200.0, 300.0, new Date(), "Dog", false, "Bob")
|
||||
)
|
||||
)
|
||||
val entriesSignal = entries.signal
|
||||
// tracks whenever a user clicks on an edit button
|
||||
val editClickBus = new EventBus[(Uid, Boolean)]
|
||||
val editStateSignal: Signal[Map[Uid, Boolean]] =
|
||||
editClickBus.stream.foldLeft(Map.empty[Uid, Boolean]) {
|
||||
case (acc, (id, value)) =>
|
||||
acc + (id -> value)
|
||||
}
|
||||
|
||||
val editState = Var(Map.empty[Id, Boolean])
|
||||
val editStateSignal = editState.signal
|
||||
// track changes to entries
|
||||
val entryEditBus = new EventBus[Entry]
|
||||
val allEntries = entryEditBus.stream.foldLeft(Map.empty[Uid, Entry]) {
|
||||
case (acc, entry) =>
|
||||
acc + (entry.id -> entry)
|
||||
}
|
||||
|
||||
val entryComponents: Signal[List[EntryComponent]] =
|
||||
entriesSignal
|
||||
allEntries
|
||||
.combineWith(editStateSignal)
|
||||
.map { case (entries, editState) =>
|
||||
entries.map(entry =>
|
||||
EntryComponent(entry, editState.getOrElse(entry.id, false))
|
||||
)
|
||||
entries.values.toList
|
||||
.sortBy(_.id)
|
||||
.map(entry =>
|
||||
EntryComponent(entry, editState.getOrElse(entry.id, false))
|
||||
)
|
||||
}
|
||||
|
||||
val editClickBus = new EventBus[(Id, Boolean)]
|
||||
val showNewEntryField = Var(false)
|
||||
|
||||
val newEntryInput =
|
||||
val newEntryDriver = input(cls := "input")
|
||||
val newEntryStartKm = input(cls := "input")
|
||||
val newEntryEndKm = input(cls := "input")
|
||||
val newEntryAnimal = input(cls := "input")
|
||||
val newEntryPaid = input(`type` := "checkbox")
|
||||
tr(
|
||||
td(newEntryDriver),
|
||||
td(newEntryStartKm),
|
||||
td(newEntryEndKm),
|
||||
td(newEntryAnimal),
|
||||
td(),
|
||||
td(),
|
||||
td(newEntryPaid),
|
||||
td(
|
||||
button(
|
||||
cls := "button is-success",
|
||||
onClick --> {
|
||||
val id = Uid.gen()
|
||||
val driver = newEntryDriver.ref.value
|
||||
val startKm = newEntryStartKm.ref.value.toDouble
|
||||
val endKm = newEntryEndKm.ref.value.toDouble
|
||||
val animal = newEntryAnimal.ref.value
|
||||
val paid = newEntryPaid.ref.checked
|
||||
entryEditBus.emit(
|
||||
Entry(id, startKm, endKm, animal, paid, driver)
|
||||
)
|
||||
showNewEntryField.set(false)
|
||||
newEntryDriver.ref.value = ""
|
||||
newEntryStartKm.ref.value = ""
|
||||
newEntryEndKm.ref.value = ""
|
||||
newEntryAnimal.ref.value = ""
|
||||
newEntryPaid.ref.checked = false
|
||||
},
|
||||
span(
|
||||
cls := "icon edit",
|
||||
i(cls := "mdi mdi-18px mdi-check-bold")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def appElement(): HtmlElement =
|
||||
div(
|
||||
|
|
@ -50,7 +100,7 @@ object Main {
|
|||
cls := "table",
|
||||
thead(
|
||||
tr(
|
||||
th("Date"),
|
||||
// th("Date"),
|
||||
th("Fahrer*in"),
|
||||
th("Start Km"),
|
||||
th("Ende Km"),
|
||||
|
|
@ -62,28 +112,16 @@ object Main {
|
|||
)
|
||||
),
|
||||
tbody(
|
||||
children <-- entryComponents.map(_.map(_.render))
|
||||
),
|
||||
tr(
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(input(cls := "input")),
|
||||
td(
|
||||
button(
|
||||
cls := "button is-success",
|
||||
span(
|
||||
cls := "icon edit",
|
||||
i(cls := "mdi mdi-18px mdi-check-bold")
|
||||
)
|
||||
)
|
||||
)
|
||||
children <-- entryComponents.map(_.map(_.render)),
|
||||
child(newEntryInput) <-- showNewEntryField
|
||||
)
|
||||
),
|
||||
button(cls := "button is-primary", "Eintrag hinzufügen")
|
||||
button(
|
||||
cls := "button is-primary",
|
||||
onClick --> { _ =>
|
||||
showNewEntryField.set(true)
|
||||
},
|
||||
"Eintrag hinzufügen"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue