add date and turn entry into CRDT

This commit is contained in:
Julian 2025-07-11 23:01:13 +02:00
parent 1091fa9ddb
commit b856d31fcc
5 changed files with 47 additions and 33 deletions

View file

@ -30,13 +30,19 @@ object Main {
println("test") println("test")
val allEntriesVar = Var(Set.empty[Entry]) val allEntriesVar = Var(Set.empty[Entry])
// update entries whenever db updates
entriesObservable.subscribe(entries => entriesObservable.subscribe(entries =>
entries.onComplete { entries.onComplete {
case Failure(exception) => println("failed to get entries from db") case Failure(exception) => println("failed to get entries from db")
case Success(value) => allEntriesVar.set(value.toSet) case Success(value) => allEntriesVar.set(value.toSet)
} }
) )
val allEntries: Signal[List[Entry]] = allEntriesVar.signal.map(_.toList)
// update db when edit events happen
entryEditBus.stream.addObserver(entryDbObserver)(using unsafeWindowOwner) entryEditBus.stream.addObserver(entryDbObserver)(using unsafeWindowOwner)
val allEntries: Signal[Set[Entry]] =
allEntriesVar.signal
} }

View file

@ -5,7 +5,7 @@ import fahrtenbuch.model.Entry
import fahrtenbuch.Main.entryEditBus import fahrtenbuch.Main.entryEditBus
import rdts.base.Uid import rdts.base.Uid
class AppComponent(allEntries: Signal[List[Entry]]): class AppComponent(allEntries: Signal[Set[Entry]]):
// tracks whenever a user clicks on an edit button // tracks whenever a user clicks on an edit button
val editClickBus = new EventBus[(Uid, Boolean)] val editClickBus = new EventBus[(Uid, Boolean)]
@ -21,7 +21,7 @@ class AppComponent(allEntries: Signal[List[Entry]]):
.combineWith(editStateSignal) .combineWith(editStateSignal)
.map { case (entries, editState) => .map { case (entries, editState) =>
entries.toList entries.toList
.sortBy(_.id) .sortBy(_.date.payload.getTime())
.map(entry => .map(entry =>
EntryComponent( EntryComponent(
entry, entry,
@ -42,7 +42,7 @@ class AppComponent(allEntries: Signal[List[Entry]]):
cls := "table", cls := "table",
thead( thead(
tr( tr(
// th("Date"), th("Datum"),
th("Fahrer*in"), th("Fahrer*in"),
th("Start Km"), th("Start Km"),
th("Ende Km"), th("Ende Km"),

View file

@ -14,18 +14,20 @@ class EntryComponent(
): ):
def render: ReactiveHtmlElement[HTMLTableRowElement] = { def render: ReactiveHtmlElement[HTMLTableRowElement] = {
if editMode then if editMode then
val driverInput = input(cls := "input", value := entry.driver) val driverInput = input(cls := "input", value := entry.driver.payload)
val startKmInput = val startKmInput =
input(cls := "input", value := entry.startKm.toString()) input(cls := "input", value := entry.startKm.payload.toString())
val endKmInput = input(cls := "input", value := entry.endKm.toString()) val endKmInput =
val animalInput = input(cls := "input", value := entry.animal) input(cls := "input", value := entry.endKm.payload.toString())
val animalInput = input(cls := "input", value := entry.animal.payload)
val costWearInput = val costWearInput =
input(cls := "input", value := entry.costWear.toString()) input(cls := "input", value := entry.costWear.toString())
val costTotalInput = val costTotalInput =
input(cls := "input", value := entry.costTotal.toString()) input(cls := "input", value := entry.costTotal.toString())
val paidCheckbox = input(`type` := "checkbox", checked := entry.paid) val paidCheckbox =
input(`type` := "checkbox", checked := entry.paid.payload)
tr( tr(
// td(input(cls := "input", value := entry.date.toDateString())), td(),
td(driverInput), td(driverInput),
td(startKmInput), td(startKmInput),
td(endKmInput), td(endKmInput),
@ -40,10 +42,11 @@ class EntryComponent(
editClickBus.emit(entry.id, false) editClickBus.emit(entry.id, false)
entryEditBus.emit( entryEditBus.emit(
entry.copy( entry.copy(
startKm = startKmInput.ref.value.toDouble, startKm =
endKm = endKmInput.ref.value.toDouble, entry.startKm.write(startKmInput.ref.value.toDouble),
animal = animalInput.ref.value, endKm = entry.endKm.write(endKmInput.ref.value.toDouble),
paid = paidCheckbox.ref.checked animal = entry.animal.write(animalInput.ref.value),
paid = entry.paid.write(paidCheckbox.ref.checked)
) )
) )
}, },
@ -56,14 +59,14 @@ class EntryComponent(
) )
else else
tr( tr(
// td(entry.date.toDateString()), td(entry.date.payload.toISOString()),
td(entry.driver), td(entry.driver.payload),
td(entry.startKm), td(entry.startKm.payload),
td(entry.endKm), td(entry.endKm.payload),
td(entry.animal), td(entry.animal.payload),
td(s"${entry.costWear}"), td(s"${entry.costWear}"),
td(s"${entry.costTotal}"), td(s"${entry.costTotal}"),
td(if entry.paid then "Ja" else "Nein"), td(if entry.paid.payload then "Ja" else "Nein"),
td( td(
button( button(
cls := "button is-link", cls := "button is-link",

View file

@ -7,6 +7,8 @@ import com.raquo.laminar.api.features.unitArrows
import fahrtenbuch.Main.entryEditBus import fahrtenbuch.Main.entryEditBus
import fahrtenbuch.model.Entry import fahrtenbuch.model.Entry
import rdts.base.Uid import rdts.base.Uid
import rdts.datatypes.LastWriterWins
import scala.scalajs.js.Date
class NewEntryInput(showNewEntryField: Var[Boolean]): class NewEntryInput(showNewEntryField: Var[Boolean]):
val newEntryDriver = input(cls := "input") val newEntryDriver = input(cls := "input")
@ -17,6 +19,7 @@ class NewEntryInput(showNewEntryField: Var[Boolean]):
def render = def render =
tr( tr(
td(),
td(newEntryDriver), td(newEntryDriver),
td(newEntryStartKm), td(newEntryStartKm),
td(newEntryEndKm), td(newEntryEndKm),
@ -29,13 +32,14 @@ class NewEntryInput(showNewEntryField: Var[Boolean]):
cls := "button is-success", cls := "button is-success",
onClick --> { onClick --> {
val id = Uid.gen() val id = Uid.gen()
val driver = newEntryDriver.ref.value val driver = LastWriterWins.now(newEntryDriver.ref.value)
val startKm = newEntryStartKm.ref.value.toDouble val startKm = LastWriterWins.now(newEntryStartKm.ref.value.toDouble)
val endKm = newEntryEndKm.ref.value.toDouble val endKm = LastWriterWins.now(newEntryEndKm.ref.value.toDouble)
val animal = newEntryAnimal.ref.value val animal = LastWriterWins.now(newEntryAnimal.ref.value)
val paid = newEntryPaid.ref.checked val paid = LastWriterWins.now(newEntryPaid.ref.checked)
val date = LastWriterWins.now(new Date(Date.now()))
entryEditBus.emit( entryEditBus.emit(
Entry(id, startKm, endKm, animal, paid, driver) Entry(id, startKm, endKm, animal, paid, driver, date)
) )
showNewEntryField.set(false) showNewEntryField.set(false)
newEntryDriver.ref.value = "" newEntryDriver.ref.value = ""

View file

@ -5,17 +5,18 @@ import scala.scalajs.js.Date
import org.getshaka.nativeconverter.NativeConverter import org.getshaka.nativeconverter.NativeConverter
import org.getshaka.nativeconverter.ParseState import org.getshaka.nativeconverter.ParseState
import scala.scalajs.js import scala.scalajs.js
import rdts.datatypes.LastWriterWins
case class Entry( case class Entry(
id: Uid, id: Uid,
startKm: Double, startKm: LastWriterWins[Double],
endKm: Double, endKm: LastWriterWins[Double],
animal: String, animal: LastWriterWins[String],
paid: Boolean, paid: LastWriterWins[Boolean],
driver: String, driver: LastWriterWins[String],
date: Option[Date] = None date: LastWriterWins[Date]
) derives NativeConverter: ) derives NativeConverter:
val distance = endKm - startKm val distance = endKm.payload - startKm.payload
// 13 cent pro km, 5 cent Abnutzung // 13 cent pro km, 5 cent Abnutzung
def costGas: Double = distance * 0.13 def costGas: Double = distance * 0.13