feat(billing-feature): introduce billing module with Money class, calculation logic, and DI setup
- Added `Money` value class for precise monetary operations. - Implemented `BillingCalculator` to handle fee calculations, including ÖTO-compliant contributions and prize distribution rules. - Created `BillingModule` for dependency injection using Koin. - Integrated `billing-feature` into the desktop shell and project dependencies. - Introduced `TurnierWizardV2` and `VeranstalterAuswahlV2` screens with improved UI and billing synchronization support. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Dieses Modul kapselt die Gebühren-Logik und Abrechnungs-Features (Billing-Sync).
|
||||||
|
*/
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
|
alias(libs.plugins.composeMultiplatform)
|
||||||
|
alias(libs.plugins.composeCompiler)
|
||||||
|
alias(libs.plugins.kotlinSerialization)
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "at.mocode.clients"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvm()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain.dependencies {
|
||||||
|
implementation(projects.frontend.core.designSystem)
|
||||||
|
implementation(projects.frontend.core.network)
|
||||||
|
implementation(projects.frontend.core.domain)
|
||||||
|
implementation(projects.core.coreDomain)
|
||||||
|
|
||||||
|
implementation(compose.foundation)
|
||||||
|
implementation(compose.runtime)
|
||||||
|
implementation(compose.material3)
|
||||||
|
implementation(compose.ui)
|
||||||
|
implementation(compose.components.resources)
|
||||||
|
implementation(compose.materialIconsExtended)
|
||||||
|
|
||||||
|
implementation(libs.bundles.kmp.common)
|
||||||
|
implementation(libs.bundles.compose.common)
|
||||||
|
|
||||||
|
implementation(libs.koin.core)
|
||||||
|
implementation(libs.koin.compose)
|
||||||
|
}
|
||||||
|
|
||||||
|
commonTest.dependencies {
|
||||||
|
implementation(libs.kotlin.test)
|
||||||
|
implementation(libs.kotlinx.coroutines.test)
|
||||||
|
}
|
||||||
|
|
||||||
|
jvmMain.dependencies {
|
||||||
|
implementation(compose.uiTooling)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package at.mocode.frontend.features.billing.di
|
||||||
|
|
||||||
|
import at.mocode.frontend.features.billing.domain.BillingCalculator
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
val billingModule = module {
|
||||||
|
single { BillingCalculator() }
|
||||||
|
}
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
package at.mocode.frontend.features.billing.domain
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repräsentiert einen Geldbetrag in Cent zur Vermeidung von Floating-Point-Fehlern.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
@JvmInline
|
||||||
|
value class Money(val cents: Long) {
|
||||||
|
operator fun plus(other: Money) = Money(this.cents + other.cents)
|
||||||
|
operator fun times(factor: Int) = Money(this.cents * factor)
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val euros = cents / 100
|
||||||
|
val rest = cents % 100
|
||||||
|
return "%d,%02d €".format(euros, if (rest < 0) -rest else rest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class GebuehrTyp {
|
||||||
|
NENN_GEBUEHR,
|
||||||
|
START_GEBUEHR,
|
||||||
|
SPORTFOERDERBEITRAG,
|
||||||
|
BOXEN_GEBUEHR,
|
||||||
|
SYSTEM_GEBUEHR,
|
||||||
|
SONSTIGES
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logik für die Gebührenberechnung gemäß ÖTO.
|
||||||
|
*/
|
||||||
|
class BillingCalculator {
|
||||||
|
/**
|
||||||
|
* Berechnet die Gesamtsumme für eine Nennung.
|
||||||
|
* @param basisNenngeld Das Nenngeld des Bewerbs.
|
||||||
|
* @param sportfoerderbeitrag Der Sportförderbeitrag (standardmäßig 1,00 € gemäß ÖTO).
|
||||||
|
*/
|
||||||
|
fun berechneNennsumme(
|
||||||
|
basisNenngeld: Money,
|
||||||
|
sportfoerderbeitrag: Money = Money(100)
|
||||||
|
): Money {
|
||||||
|
return basisNenngeld + sportfoerderbeitrag
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Berechnet das Preisgeld gemäß § 30 ÖTO (Verteilungsschlüssel).
|
||||||
|
* Einfache Implementierung für den Anfang.
|
||||||
|
*/
|
||||||
|
fun berechnePreisgeld(gesamtSumme: Money, platzierung: Int): Money {
|
||||||
|
return when (platzierung) {
|
||||||
|
1 -> Money((gesamtSumme.cents * 0.25).toLong())
|
||||||
|
2 -> Money((gesamtSumme.cents * 0.20).toLong())
|
||||||
|
3 -> Money((gesamtSumme.cents * 0.15).toLong())
|
||||||
|
else -> Money(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+152
@@ -0,0 +1,152 @@
|
|||||||
|
package at.mocode.turnier.feature.presentation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import at.mocode.frontend.core.designsystem.models.PlaceholderContent
|
||||||
|
|
||||||
|
private val PrimaryBlue = Color(0xFF1E3A8A)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TurnierWizardV2 - Der neue Wizard für die Turnieranlage (Vision_03).
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun TurnierWizardV2(
|
||||||
|
veranstaltungId: Long,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
onSave: () -> Unit,
|
||||||
|
) {
|
||||||
|
var currentStep by remember { mutableIntStateOf(0) }
|
||||||
|
val steps = listOf("Stammdaten", "Organisation", "Bewerbe ⭐", "Preisliste")
|
||||||
|
|
||||||
|
Column(modifier = Modifier.fillMaxSize().background(Color.White)) {
|
||||||
|
// Wizard Header
|
||||||
|
Surface(shadowElevation = 4.dp, color = Color.White) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
IconButton(onClick = onBack) { Icon(Icons.Default.ArrowBack, null) }
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text("Neues Turnier anlegen", style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = onSave,
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = PrimaryBlue),
|
||||||
|
enabled = currentStep == steps.size - 1
|
||||||
|
) {
|
||||||
|
Text("Turnier finalisieren")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Stepper UI
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 32.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
steps.forEachIndexed { index, title ->
|
||||||
|
StepItem(
|
||||||
|
title = title,
|
||||||
|
isActive = index == currentStep,
|
||||||
|
isCompleted = index < currentStep,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
if (index < steps.size - 1) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.height(2.dp).weight(0.5f)
|
||||||
|
.background(if (index < currentStep) PrimaryBlue else Color.LightGray)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content Area
|
||||||
|
Box(modifier = Modifier.weight(1f).padding(32.dp)) {
|
||||||
|
when (currentStep) {
|
||||||
|
0 -> PlaceholderContent("Stammdaten", "Hier werden OEPS-Nummer, Kategorie und Sparte konfiguriert.")
|
||||||
|
1 -> PlaceholderContent("Organisation", "Zuweisung von Richtern, Parcourschefs und Tierärzten.")
|
||||||
|
2 -> PlaceholderContent("Bewerbe", "Konfiguration der Bewerbe und Abteilungen gemäß § 39 ÖTO.")
|
||||||
|
3 -> PlaceholderContent("Preisliste", "Einstellung der Nenngebühren und Sportförderbeiträge (Billing-Sync).")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wizard Navigation
|
||||||
|
Surface(shadowElevation = 8.dp, color = Color.White) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(24.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
onClick = { if (currentStep > 0) currentStep-- else onBack() }
|
||||||
|
) {
|
||||||
|
Text(if (currentStep == 0) "Abbrechen" else "Zurück")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStep < steps.size - 1) {
|
||||||
|
Button(
|
||||||
|
onClick = { currentStep++ },
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = PrimaryBlue)
|
||||||
|
) {
|
||||||
|
Text("Weiter")
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Icon(Icons.Default.ArrowForward, null, modifier = Modifier.size(16.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun StepItem(title: String, isActive: Boolean, isCompleted: Boolean, modifier: Modifier = Modifier) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(32.dp)
|
||||||
|
.background(
|
||||||
|
color = when {
|
||||||
|
isCompleted -> PrimaryBlue
|
||||||
|
isActive -> PrimaryBlue
|
||||||
|
else -> Color.LightGray
|
||||||
|
},
|
||||||
|
shape = androidx.compose.foundation.shape.CircleShape
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (isCompleted) {
|
||||||
|
Icon(Icons.Default.Check, null, tint = Color.White, modifier = Modifier.size(16.dp))
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
text = "", // Or step number
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
fontWeight = if (isActive) FontWeight.Bold else FontWeight.Normal,
|
||||||
|
color = if (isActive || isCompleted) PrimaryBlue else Color.Gray,
|
||||||
|
modifier = Modifier.padding(top = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
package at.mocode.veranstalter.feature.presentation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material.icons.filled.Search
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import at.mocode.frontend.core.designsystem.models.LoginStatus
|
||||||
|
import at.mocode.frontend.core.designsystem.models.LoginStatusBadge
|
||||||
|
|
||||||
|
private val PrimaryBlue = Color(0xFF1E3A8A)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen: "Admin - Verwaltung / Veranstalter auswählen V2"
|
||||||
|
* Optimiert für Vision_03 mit verbesserter UI und echtem DDD-Mapping Vorbereitung.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun VeranstalterAuswahlV2(
|
||||||
|
onZurueck: () -> Unit,
|
||||||
|
onWeiter: (Long) -> Unit,
|
||||||
|
onNeuerVeranstalter: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
var selectedId by remember { mutableStateOf<Long?>(null) }
|
||||||
|
var suchtext by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
// Placeholder-Daten gemäß Figma
|
||||||
|
val veranstalter = remember {
|
||||||
|
listOf(
|
||||||
|
VeranstalterUiModel(
|
||||||
|
1L,
|
||||||
|
"Reit- und Fahrverein Wels",
|
||||||
|
"V-OOE-1234",
|
||||||
|
"4600 Wels",
|
||||||
|
"Maria Huber",
|
||||||
|
"office@rfv-wels.at",
|
||||||
|
LoginStatus.AKTIV
|
||||||
|
),
|
||||||
|
VeranstalterUiModel(
|
||||||
|
2L,
|
||||||
|
"Pferdesportverein Linz",
|
||||||
|
"V-OOE-5678",
|
||||||
|
"4020 Linz",
|
||||||
|
"Thomas Maier",
|
||||||
|
"kontakt@psv-linz.at",
|
||||||
|
LoginStatus.AKTIV
|
||||||
|
),
|
||||||
|
VeranstalterUiModel(
|
||||||
|
3L,
|
||||||
|
"Reitclub Eferding",
|
||||||
|
"V-OOE-9012",
|
||||||
|
"4070 Eferding",
|
||||||
|
"Anna Schmid",
|
||||||
|
"info@rc-eferding.at",
|
||||||
|
LoginStatus.AUSSTEHEND
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val gefiltert = veranstalter.filter {
|
||||||
|
suchtext.isBlank() ||
|
||||||
|
it.name.contains(suchtext, ignoreCase = true) ||
|
||||||
|
it.oepsNummer.contains(suchtext, ignoreCase = true) ||
|
||||||
|
it.ort.contains(suchtext, ignoreCase = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(modifier = Modifier.fillMaxSize().background(Color.White)) {
|
||||||
|
// Top Bar
|
||||||
|
Surface(shadowElevation = 4.dp, color = Color.White) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text("Veranstalter auswählen", style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||||
|
Text(
|
||||||
|
"Wählen Sie den Verein für die Veranstaltung aus.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = Color.Gray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
IconButton(onClick = onZurueck) {
|
||||||
|
Icon(Icons.Default.Close, contentDescription = "Schließen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suche & Aktionen
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(24.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = suchtext,
|
||||||
|
onValueChange = { suchtext = it },
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
placeholder = { Text("Suche nach Name, OEPS-Nummer oder Ort...") },
|
||||||
|
leadingIcon = { Icon(Icons.Default.Search, null) },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = onNeuerVeranstalter,
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = PrimaryBlue),
|
||||||
|
shape = MaterialTheme.shapes.medium
|
||||||
|
) {
|
||||||
|
Icon(Icons.Default.Add, null)
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text("Neuer Veranstalter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liste
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.weight(1f).padding(horizontal = 24.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
items(gefiltert) { item ->
|
||||||
|
val isSelected = selectedId == item.id
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { selectedId = item.id }
|
||||||
|
.border(
|
||||||
|
width = 2.dp,
|
||||||
|
color = if (isSelected) PrimaryBlue else Color.Transparent,
|
||||||
|
shape = MaterialTheme.shapes.medium
|
||||||
|
),
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = if (isSelected) Color(0xFFEFF6FF) else Color(0xFFF9FAFB)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
RadioButton(selected = isSelected, onClick = { selectedId = item.id })
|
||||||
|
Spacer(Modifier.width(16.dp))
|
||||||
|
Column(Modifier.weight(1f)) {
|
||||||
|
Text(item.name, fontWeight = FontWeight.Bold)
|
||||||
|
Text("${item.oepsNummer} | ${item.ort}", style = MaterialTheme.typography.bodySmall)
|
||||||
|
}
|
||||||
|
LoginStatusBadge(item.loginStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
Surface(shadowElevation = 8.dp, color = Color.White) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(24.dp),
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
TextButton(onClick = onZurueck) { Text("Abbrechen") }
|
||||||
|
Spacer(Modifier.width(16.dp))
|
||||||
|
Button(
|
||||||
|
onClick = { selectedId?.let { onWeiter(it) } },
|
||||||
|
enabled = selectedId != null,
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = PrimaryBlue)
|
||||||
|
) {
|
||||||
|
Text("Weiter zur Turnier-Konfiguration")
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Icon(Icons.Default.ArrowForward, null, modifier = Modifier.size(16.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ kotlin {
|
|||||||
implementation(projects.frontend.features.veranstaltungFeature)
|
implementation(projects.frontend.features.veranstaltungFeature)
|
||||||
implementation(projects.frontend.features.turnierFeature)
|
implementation(projects.frontend.features.turnierFeature)
|
||||||
implementation(project(":frontend:features:profile-feature"))
|
implementation(project(":frontend:features:profile-feature"))
|
||||||
|
implementation(project(":frontend:features:billing-feature"))
|
||||||
|
|
||||||
// Compose Desktop
|
// Compose Desktop
|
||||||
implementation(compose.desktop.currentOs)
|
implementation(compose.desktop.currentOs)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import at.mocode.frontend.core.localdb.DatabaseProvider
|
|||||||
import at.mocode.frontend.core.localdb.localDbModule
|
import at.mocode.frontend.core.localdb.localDbModule
|
||||||
import at.mocode.frontend.core.network.networkModule
|
import at.mocode.frontend.core.network.networkModule
|
||||||
import at.mocode.frontend.core.sync.di.syncModule
|
import at.mocode.frontend.core.sync.di.syncModule
|
||||||
|
import at.mocode.frontend.features.billing.di.billingModule
|
||||||
import at.mocode.frontend.features.profile.di.profileModule
|
import at.mocode.frontend.features.profile.di.profileModule
|
||||||
import at.mocode.nennung.feature.di.nennungFeatureModule
|
import at.mocode.nennung.feature.di.nennungFeatureModule
|
||||||
import at.mocode.ping.feature.di.pingFeatureModule
|
import at.mocode.ping.feature.di.pingFeatureModule
|
||||||
@@ -33,6 +34,7 @@ fun main() = application {
|
|||||||
nennungFeatureModule,
|
nennungFeatureModule,
|
||||||
znsImportModule,
|
znsImportModule,
|
||||||
profileModule,
|
profileModule,
|
||||||
|
billingModule,
|
||||||
desktopModule,
|
desktopModule,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-9
@@ -23,8 +23,10 @@ import at.mocode.frontend.features.profile.presentation.ProfileViewModel
|
|||||||
import at.mocode.ping.feature.presentation.PingScreen
|
import at.mocode.ping.feature.presentation.PingScreen
|
||||||
import at.mocode.ping.feature.presentation.PingViewModel
|
import at.mocode.ping.feature.presentation.PingViewModel
|
||||||
import at.mocode.turnier.feature.presentation.TurnierDetailScreen
|
import at.mocode.turnier.feature.presentation.TurnierDetailScreen
|
||||||
|
import at.mocode.turnier.feature.presentation.TurnierWizardV2
|
||||||
import at.mocode.veranstalter.feature.presentation.FakeVeranstalterStore
|
import at.mocode.veranstalter.feature.presentation.FakeVeranstalterStore
|
||||||
import at.mocode.veranstalter.feature.presentation.FakeVeranstaltungStore
|
import at.mocode.veranstalter.feature.presentation.FakeVeranstaltungStore
|
||||||
|
import at.mocode.veranstalter.feature.presentation.VeranstalterAuswahlV2
|
||||||
import at.mocode.veranstalter.feature.presentation.VeranstalterNeuScreen
|
import at.mocode.veranstalter.feature.presentation.VeranstalterNeuScreen
|
||||||
import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen
|
import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen
|
||||||
import at.mocode.veranstaltung.feature.presentation.VeranstaltungDetailScreen
|
import at.mocode.veranstaltung.feature.presentation.VeranstaltungDetailScreen
|
||||||
@@ -300,18 +302,18 @@ private fun DesktopContentArea(
|
|||||||
// Root-Screen: Leitet in V2-Fluss ab
|
// Root-Screen: Leitet in V2-Fluss ab
|
||||||
is AppScreen.Veranstaltungen -> {
|
is AppScreen.Veranstaltungen -> {
|
||||||
// Direkt zur Veranstalter-Auswahl V2
|
// Direkt zur Veranstalter-Auswahl V2
|
||||||
at.mocode.desktop.v2.VeranstalterAuswahlV2(
|
VeranstalterAuswahlV2(
|
||||||
onBack = { /* bleibt root */ },
|
onZurueck = { /* bleibt root */ },
|
||||||
onWeiter = { vId -> onNavigate(AppScreen.VeranstalterDetail(vId)) },
|
onWeiter = { vId -> onNavigate(AppScreen.VeranstalterDetail(vId)) },
|
||||||
onNeu = { onNavigate(AppScreen.VeranstalterNeu) },
|
onNeuerVeranstalter = { onNavigate(AppScreen.VeranstalterNeu) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuer Flow: Veranstalter auswählen → Detail → Veranstaltung-Übersicht
|
// Neuer Flow: Veranstalter auswählen → Detail → Veranstaltung-Übersicht
|
||||||
is AppScreen.VeranstalterAuswahl -> at.mocode.desktop.v2.VeranstalterAuswahlV2(
|
is AppScreen.VeranstalterAuswahl -> VeranstalterAuswahlV2(
|
||||||
onBack = { onNavigate(AppScreen.Veranstaltungen) },
|
onZurueck = { onNavigate(AppScreen.Veranstaltungen) },
|
||||||
onWeiter = { veranstalterId -> onNavigate(AppScreen.VeranstalterDetail(veranstalterId)) },
|
onWeiter = { veranstalterId -> onNavigate(AppScreen.VeranstalterDetail(veranstalterId)) },
|
||||||
onNeu = { onNavigate(AppScreen.VeranstalterNeu) },
|
onNeuerVeranstalter = { onNavigate(AppScreen.VeranstalterNeu) },
|
||||||
)
|
)
|
||||||
|
|
||||||
is AppScreen.VeranstalterNeu -> VeranstalterNeuScreen(
|
is AppScreen.VeranstalterNeu -> VeranstalterNeuScreen(
|
||||||
@@ -414,11 +416,10 @@ private fun DesktopContentArea(
|
|||||||
onBack = { onNavigate(AppScreen.Veranstaltungen) }
|
onBack = { onNavigate(AppScreen.Veranstaltungen) }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
at.mocode.desktop.v2.TurnierWizardV2(
|
TurnierWizardV2(
|
||||||
veranstalterId = parent.id,
|
|
||||||
veranstaltungId = evtId,
|
veranstaltungId = evtId,
|
||||||
onBack = { onNavigate(AppScreen.VeranstaltungUebersicht(parent.id, evtId)) },
|
onBack = { onNavigate(AppScreen.VeranstaltungUebersicht(parent.id, evtId)) },
|
||||||
onSaved = { _ -> onNavigate(AppScreen.VeranstaltungUebersicht(parent.id, evtId)) },
|
onSave = { onNavigate(AppScreen.VeranstaltungUebersicht(parent.id, evtId)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ include(":frontend:features:veranstalter-feature")
|
|||||||
include(":frontend:features:veranstaltung-feature")
|
include(":frontend:features:veranstaltung-feature")
|
||||||
include(":frontend:features:profile-feature")
|
include(":frontend:features:profile-feature")
|
||||||
include(":frontend:features:turnier-feature")
|
include(":frontend:features:turnier-feature")
|
||||||
|
include(":frontend:features:billing-feature")
|
||||||
|
|
||||||
// --- SHELLS ---
|
// --- SHELLS ---
|
||||||
include(":frontend:shells:meldestelle-desktop")
|
include(":frontend:shells:meldestelle-desktop")
|
||||||
|
|||||||
Reference in New Issue
Block a user