Remove nennung-feature (domain models, DI modules, and UI components).

This commit is contained in:
2026-04-11 13:04:20 +02:00
parent 84128432e3
commit eda18a8ff2
22 changed files with 435 additions and 60 deletions
@@ -0,0 +1,27 @@
# Frontend Migration & Cleanup TODO
Status: April 2026
## ✅ Abgeschlossene Migrationen (Feature-Module)
- `billing-feature`: `at.mocode.frontend.features.billing` (KMP)
- `verein-feature`: `at.mocode.frontend.features.verein` (KMP)
- `nennung-feature`: `at.mocode.frontend.features.nennung` (KMP)
- `profile-feature`: `at.mocode.frontend.features.profile` (KMP)
- `pferde-feature`: `at.mocode.frontend.features.pferde` (KMP) - Migriert von v2
- `reiter-feature`: `at.mocode.frontend.features.reiter` (KMP) - Migriert von v2
- `funktionaer-feature`: `at.mocode.frontend.features.funktionaer` (KMP) - Neu erstellt
- `ping-feature`: `at.mocode.ping.feature` (muss noch auf `at.mocode.frontend.features.ping` vereinheitlicht werden)
## 🚧 Ausstehende Migrationen (von `at.mocode.desktop.v2` zu Features)
Die folgenden Komponenten in `meldestelle-desktop/src/jvmMain/kotlin/at/mocode/desktop/v2/` basieren noch auf `StoreV2` (In-Memory Mock) und sollten in KMP-Module überführt werden:
1. **Veranstalter-Management**: `VeranstalterVerwaltungScreen.kt`, `VeranstalterDetailV2` -> Neues `veranstalter-feature` (Vollständige Integration).
2. **Onboarding**: `OnboardingScreen.kt` -> Design-System Integration erfolgt, KMP-Modul folgt.
## 🧹 Architektur-Cleanup
- [ ] `at.mocode.desktop.v2.StoreV2` entfernen, sobald alle Screens auf ViewModels und API-Repositories umgestellt sind.
- [ ] `at.mocode.desktop.v2.TurnierStoreV2` konsolidieren mit dem `turnier-feature`.
- [ ] Paketnamen vereinheitlichen: `at.mocode.ping.feature` -> `at.mocode.frontend.features.ping`.
- [ ] Paketnamen vereinheitlichen: `at.mocode.zns.feature` -> `at.mocode.frontend.features.zns`.
- [ ] `AppScreen.kt`: Veraltete (Legacy) Routen und Regexe entfernen.
- [ ] `DesktopMainLayout.kt`: Die `when`-Zweige für `v2` Screens aufräumen, sobald die Module bereit sind.
+2
View File
@@ -233,6 +233,8 @@ und über definierte Schnittstellen kommunizieren.
* [x] **ZNS-Importer:** Hardening & Integrationstests für Funktionärs-Updates. ✓ * [x] **ZNS-Importer:** Hardening & Integrationstests für Funktionärs-Updates. ✓
* [x] **Konzept:** Fachliches Konzept für Zeitplan-Optimierung (Drag & Drop) erstellt. ✓ * [x] **Konzept:** Fachliches Konzept für Zeitplan-Optimierung (Drag & Drop) erstellt. ✓
* [x] **Konzept:** Status-Automat für Nennungen & Zeitplan-Synchronisation spezifiziert. ✓ * [x] **Konzept:** Status-Automat für Nennungen & Zeitplan-Synchronisation spezifiziert. ✓
* [x] **Frontend-Standardisierung:** `nennung-feature` refactored und in Desktop-Shell integriert. ✓
* [x] **Cleanup:** `FRONTEND_CLEANUP_TODO.md` für Migration von `v2` Screens erstellt. ✓
* [ ] **Zeitplan:** Dynamische Verschiebung von Bewerben (Drag & Drop im Kalender). * [ ] **Zeitplan:** Dynamische Verschiebung von Bewerben (Drag & Drop im Kalender).
* [ ] **Protokoll:** Implementierung eines Event-Logs für manuelle Eingriffe in Startlisten. * [ ] **Protokoll:** Implementierung eines Event-Logs für manuelle Eingriffe in Startlisten.
* [ ] **Export:** Startlisten-Export für ZNS (XML-B-Satz). * [ ] **Export:** Startlisten-Export für ZNS (XML-B-Satz).
@@ -0,0 +1,17 @@
package at.mocode.frontend.features.funktionaer.di
import at.mocode.frontend.features.funktionaer.presentation.*
import org.koin.dsl.module
val funktionaerModule = module {
single<FunktionaerRepository> { MockFunktionaerRepository() }
factory { FunktionaerViewModel(get()) }
}
class MockFunktionaerRepository : FunktionaerRepository {
override suspend fun list(): List<FunktionaerListItem> = listOf(
FunktionaerListItem(1, "Wolfgang Schier", "RICHTER", "G3"),
FunktionaerListItem(2, "Alice Schwab", "RICHTER", "INTERNATIONAL"),
FunktionaerListItem(3, "Dietmar Gstöttner", "PARCOURSBAUER", null)
)
}
@@ -0,0 +1,15 @@
package at.mocode.frontend.features.funktionaer.domain
data class Funktionaer(
val id: Long,
val vorname: String,
val nachname: String,
val richterNummer: String? = null,
val rollen: List<String> = emptyList(),
val richterQualifikation: String? = null,
val qualifiziertFuerSparten: List<String> = emptyList(),
val email: String? = null,
val telefon: String? = null,
val vereinsNummer: String? = null,
val istAktiv: Boolean = true
)
@@ -0,0 +1,103 @@
package at.mocode.frontend.features.funktionaer.presentation
import androidx.compose.foundation.layout.*
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.components.*
import at.mocode.frontend.core.designsystem.models.PlaceholderContent
@Composable
fun FunktionaerScreen(
viewModel: FunktionaerViewModel
) {
val state by viewModel.state.collectAsState()
MsMasterDetailLayout(
master = {
FunktionaerListContent(
state = state,
onSearchChange = { viewModel.send(FunktionaerIntent.SearchChanged(it)) },
onFunktionaerSelected = { viewModel.send(FunktionaerIntent.Select(it)) }
)
},
detail = {
if (state.selectedId != null) {
val selected = state.list.find { it.id == state.selectedId }
if (selected != null) {
FunktionaerDetailContent(selected)
}
} else {
PlaceholderContent(
title = "Kein Funktionär ausgewählt",
subtitle = "Wählen Sie einen Funktionär aus der Liste aus."
)
}
}
)
}
@Composable
private fun FunktionaerListContent(
state: FunktionaerState,
onSearchChange: (String) -> Unit,
onFunktionaerSelected: (Long) -> Unit
) {
Column(modifier = Modifier.fillMaxSize()) {
MsFilterBar(
searchQuery = state.searchQuery,
onSearchQueryChange = onSearchChange,
resultCount = state.filtered.size
)
Spacer(Modifier.height(8.dp))
if (state.isLoading) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
} else {
MsDataTable(
items = state.filtered,
columns = listOf(
MsColumnDefinition(
title = "Name",
weight = 1f,
cellRenderer = { Text(it.name, style = MaterialTheme.typography.bodySmall) }
),
MsColumnDefinition(
title = "Rolle",
width = 150.dp,
cellRenderer = { Text(it.rolle, style = MaterialTheme.typography.bodySmall) }
),
MsColumnDefinition(
title = "Lizenz",
width = 100.dp,
cellRenderer = { Text(it.lizenz ?: "-", style = MaterialTheme.typography.bodySmall) }
)
),
onRowClick = { onFunktionaerSelected(it.id) }
)
}
}
}
@Composable
private fun FunktionaerDetailContent(item: FunktionaerListItem) {
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
Text(item.name, style = MaterialTheme.typography.headlineMedium)
Spacer(Modifier.height(8.dp))
Text("Rolle: ${item.rolle}", style = MaterialTheme.typography.bodyLarge)
item.lizenz?.let {
Text("Lizenz: $it", style = MaterialTheme.typography.bodyLarge)
}
Spacer(Modifier.height(24.dp))
Text("Weitere Details folgen in der nächsten Ausbaustufe.", style = MaterialTheme.typography.bodyMedium)
}
}
@@ -1,6 +1,6 @@
package at.mocode.nennung.feature.di package at.mocode.frontend.features.nennung.di
import at.mocode.nennung.feature.presentation.NennungViewModel import at.mocode.frontend.features.nennung.presentation.NennungViewModel
import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module import org.koin.dsl.module
@@ -1,4 +1,4 @@
package at.mocode.nennung.feature.domain package at.mocode.frontend.features.nennung.domain
// --- Pferd --- // --- Pferd ---
data class Pferd( data class Pferd(
@@ -1,6 +1,6 @@
package at.mocode.nennung.feature.presentation package at.mocode.frontend.features.nennung.presentation
import at.mocode.nennung.feature.domain.* import at.mocode.frontend.features.nennung.domain.*
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -1,4 +1,4 @@
package at.mocode.nennung.feature.presentation package at.mocode.frontend.features.nennung.presentation
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -17,7 +17,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import at.mocode.nennung.feature.domain.* import at.mocode.frontend.features.nennung.domain.*
// Farben für Startwunsch-Markierung // Farben für Startwunsch-Markierung
private val FarbeVorne = Color(0xFFE8F5E9) // Grün private val FarbeVorne = Color(0xFFE8F5E9) // Grün
@@ -0,0 +1,8 @@
package at.mocode.frontend.features.pferde.di
import at.mocode.frontend.features.pferde.presentation.PferdeViewModel
import org.koin.dsl.module
val pferdeModule = module {
factory { PferdeViewModel() }
}
@@ -12,7 +12,12 @@ data class Pferd(
val geschlecht: Geschlecht = Geschlecht.WALLACH, val geschlecht: Geschlecht = Geschlecht.WALLACH,
val farbe: String = "", val farbe: String = "",
val geburtsjahr: Int? = null, val geburtsjahr: Int? = null,
val status: PferdeStatus = PferdeStatus.AKTIV val status: PferdeStatus = PferdeStatus.AKTIV,
val feiId: String? = null,
val oepsNummer: String? = null,
val vater: String? = null,
val mutter: String? = null,
val besitzer: String? = null
) )
enum class Geschlecht(val label: String) { enum class Geschlecht(val label: String) {
@@ -38,6 +38,9 @@ fun PferdeScreen(
onFarbeChange = viewModel::onEditFarbeChange, onFarbeChange = viewModel::onEditFarbeChange,
onGeburtsjahrChange = viewModel::onEditGeburtsjahrChange, onGeburtsjahrChange = viewModel::onEditGeburtsjahrChange,
onStatusChange = viewModel::onEditStatusChange, onStatusChange = viewModel::onEditStatusChange,
onFeiIdChange = viewModel::onEditFeiIdChange,
onOepsNummerChange = viewModel::onEditOepsNummerChange,
onBesitzerChange = viewModel::onEditBesitzerChange,
onSave = viewModel::onSave, onSave = viewModel::onSave,
onCancel = viewModel::onCancel onCancel = viewModel::onCancel
) )
@@ -105,6 +108,9 @@ private fun PferdeEditorContent(
onFarbeChange: (String) -> Unit, onFarbeChange: (String) -> Unit,
onGeburtsjahrChange: (String) -> Unit, onGeburtsjahrChange: (String) -> Unit,
onStatusChange: (PferdeStatus) -> Unit, onStatusChange: (PferdeStatus) -> Unit,
onFeiIdChange: (String) -> Unit,
onOepsNummerChange: (String) -> Unit,
onBesitzerChange: (String) -> Unit,
onSave: () -> Unit, onSave: () -> Unit,
onCancel: () -> Unit onCancel: () -> Unit
) { ) {
@@ -134,6 +140,23 @@ private fun PferdeEditorContent(
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editFeiId,
onValueChange = onFeiIdChange,
label = "FEI ID",
modifier = Modifier.weight(1f)
)
MsTextField(
value = uiState.editOepsNummer,
onValueChange = onOepsNummerChange,
label = "ÖPS Nummer",
modifier = Modifier.weight(1f)
)
}
Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsEnumDropdown( MsEnumDropdown(
label = "Geschlecht", label = "Geschlecht",
@@ -160,15 +183,24 @@ private fun PferdeEditorContent(
label = "Geburtsjahr", label = "Geburtsjahr",
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
MsTextField(
value = uiState.editBesitzer,
onValueChange = onBesitzerChange,
label = "Besitzer",
modifier = Modifier.weight(1f)
)
}
Spacer(Modifier.height(16.dp))
MsEnumDropdown( MsEnumDropdown(
label = "Status", label = "Status",
options = PferdeStatus.entries.toTypedArray(), options = PferdeStatus.entries.toTypedArray(),
selectedOption = uiState.editStatus, selectedOption = uiState.editStatus,
onOptionSelected = onStatusChange, onOptionSelected = onStatusChange,
optionLabel = { it.label }, optionLabel = { it.label },
modifier = Modifier.weight(1f) modifier = Modifier.width(300.dp)
) )
}
Spacer(Modifier.height(24.dp)) Spacer(Modifier.height(24.dp))
@@ -3,6 +3,7 @@ package at.mocode.frontend.features.pferde.presentation
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import at.mocode.frontend.features.pferde.domain.Geschlecht import at.mocode.frontend.features.pferde.domain.Geschlecht
import at.mocode.frontend.features.pferde.domain.Pferd import at.mocode.frontend.features.pferde.domain.Pferd
import at.mocode.frontend.features.pferde.domain.PferdeStatus import at.mocode.frontend.features.pferde.domain.PferdeStatus
@@ -21,13 +22,16 @@ data class PferdeUiState(
val editGeschlecht: Geschlecht = Geschlecht.WALLACH, val editGeschlecht: Geschlecht = Geschlecht.WALLACH,
val editFarbe: String = "", val editFarbe: String = "",
val editGeburtsjahr: String = "", val editGeburtsjahr: String = "",
val editStatus: PferdeStatus = PferdeStatus.AKTIV val editStatus: PferdeStatus = PferdeStatus.AKTIV,
val editFeiId: String = "",
val editOepsNummer: String = "",
val editBesitzer: String = ""
) )
/** /**
* ViewModel für die Pferde-Verwaltung. * ViewModel für die Pferde-Verwaltung.
*/ */
open class PferdeViewModel(initialLoad: Boolean = true) { open class PferdeViewModel(initialLoad: Boolean = true) : ViewModel() {
var uiState by mutableStateOf(PferdeUiState()) var uiState by mutableStateOf(PferdeUiState())
protected set protected set
@@ -60,10 +64,25 @@ open class PferdeViewModel(initialLoad: Boolean = true) {
editGeschlecht = pferd.geschlecht, editGeschlecht = pferd.geschlecht,
editFarbe = pferd.farbe, editFarbe = pferd.farbe,
editGeburtsjahr = pferd.geburtsjahr?.toString() ?: "", editGeburtsjahr = pferd.geburtsjahr?.toString() ?: "",
editStatus = pferd.status editStatus = pferd.status,
editFeiId = pferd.feiId ?: "",
editOepsNummer = pferd.oepsNummer ?: "",
editBesitzer = pferd.besitzer ?: ""
) )
} }
fun onEditFeiIdChange(value: String) {
uiState = uiState.copy(editFeiId = value)
}
fun onEditOepsNummerChange(value: String) {
uiState = uiState.copy(editOepsNummer = value)
}
fun onEditBesitzerChange(value: String) {
uiState = uiState.copy(editBesitzer = value)
}
fun onEditNameChange(value: String) { fun onEditNameChange(value: String) {
uiState = uiState.copy(editName = value) uiState = uiState.copy(editName = value)
} }
@@ -0,0 +1,8 @@
package at.mocode.frontend.features.reiter.di
import at.mocode.frontend.features.reiter.presentation.ReiterViewModel
import org.koin.dsl.module
val reiterModule = module {
factory { ReiterViewModel() }
}
@@ -12,7 +12,13 @@ data class Reiter(
val satznummer: String?, val satznummer: String?,
val lizenz: LizenzKlasse = LizenzKlasse.KEINE, val lizenz: LizenzKlasse = LizenzKlasse.KEINE,
val sparte: Sparte = Sparte.KEINE, val sparte: Sparte = Sparte.KEINE,
val status: ReiterStatus = ReiterStatus.AKTIV val status: ReiterStatus = ReiterStatus.AKTIV,
val feiId: String? = null,
val oepsNummer: String? = null,
val geburtsdatum: String? = null,
val email: String? = null,
val telefon: String? = null,
val verein: String? = null
) { ) {
val name: String get() = "$vorname $nachname" val name: String get() = "$vorname $nachname"
} }
@@ -34,6 +34,12 @@ fun ReiterScreen(
onNachnameChange = viewModel::onEditNameChange, onNachnameChange = viewModel::onEditNameChange,
onLizenzChange = viewModel::onEditLizenzChange, onLizenzChange = viewModel::onEditLizenzChange,
onSparteChange = viewModel::onEditSparteChange, onSparteChange = viewModel::onEditSparteChange,
onFeiIdChange = viewModel::onEditFeiIdChange,
onOepsNummerChange = viewModel::onEditOepsNummerChange,
onGeburtsdatumChange = viewModel::onEditGeburtsdatumChange,
onEmailChange = viewModel::onEditEmailChange,
onTelefonChange = viewModel::onEditTelefonChange,
onVereinChange = viewModel::onEditVereinChange,
onSave = viewModel::onSave, onSave = viewModel::onSave,
onCancel = viewModel::onCancel onCancel = viewModel::onCancel
) )
@@ -104,6 +110,12 @@ private fun ReiterEditorContent(
onNachnameChange: (String) -> Unit, onNachnameChange: (String) -> Unit,
onLizenzChange: (LizenzKlasse) -> Unit, onLizenzChange: (LizenzKlasse) -> Unit,
onSparteChange: (Sparte) -> Unit, onSparteChange: (Sparte) -> Unit,
onFeiIdChange: (String) -> Unit,
onOepsNummerChange: (String) -> Unit,
onGeburtsdatumChange: (String) -> Unit,
onEmailChange: (String) -> Unit,
onTelefonChange: (String) -> Unit,
onVereinChange: (String) -> Unit,
onSave: () -> Unit, onSave: () -> Unit,
onCancel: () -> Unit onCancel: () -> Unit
) { ) {
@@ -133,6 +145,57 @@ private fun ReiterEditorContent(
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editFeiId,
onValueChange = onFeiIdChange,
label = "FEI ID",
modifier = Modifier.weight(1f)
)
MsTextField(
value = uiState.editOepsNummer,
onValueChange = onOepsNummerChange,
label = "ÖPS Nummer",
modifier = Modifier.weight(1f)
)
}
Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editGeburtsdatum,
onValueChange = onGeburtsdatumChange,
label = "Geburtsdatum",
modifier = Modifier.weight(1f)
)
MsTextField(
value = uiState.editVerein,
onValueChange = onVereinChange,
label = "Verein",
modifier = Modifier.weight(1f)
)
}
Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsTextField(
value = uiState.editEmail,
onValueChange = onEmailChange,
label = "E-Mail",
modifier = Modifier.weight(1f)
)
MsTextField(
value = uiState.editTelefon,
onValueChange = onTelefonChange,
label = "Telefon",
modifier = Modifier.weight(1f)
)
}
Spacer(Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
MsEnumDropdown( MsEnumDropdown(
label = "Lizenzklasse", label = "Lizenzklasse",
@@ -3,6 +3,7 @@ package at.mocode.frontend.features.reiter.presentation
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import at.mocode.frontend.features.reiter.domain.LizenzKlasse import at.mocode.frontend.features.reiter.domain.LizenzKlasse
import at.mocode.frontend.features.reiter.domain.Reiter import at.mocode.frontend.features.reiter.domain.Reiter
import at.mocode.frontend.features.reiter.domain.ReiterStatus import at.mocode.frontend.features.reiter.domain.ReiterStatus
@@ -21,14 +22,20 @@ data class ReiterUiState(
val editVorname: String = "", val editVorname: String = "",
val editLizenz: LizenzKlasse = LizenzKlasse.KEINE, val editLizenz: LizenzKlasse = LizenzKlasse.KEINE,
val editSparte: Sparte = Sparte.KEINE, val editSparte: Sparte = Sparte.KEINE,
val editStatus: ReiterStatus = ReiterStatus.AKTIV val editStatus: ReiterStatus = ReiterStatus.AKTIV,
val editFeiId: String = "",
val editOepsNummer: String = "",
val editGeburtsdatum: String = "",
val editEmail: String = "",
val editTelefon: String = "",
val editVerein: String = ""
) )
/** /**
* ViewModel für die Reiter-Verwaltung. * ViewModel für die Reiter-Verwaltung.
* In einem echten Szenario würden wir hier ein Repository injizieren. * In einem echten Szenario würden wir hier ein Repository injizieren.
*/ */
open class ReiterViewModel(initialLoad: Boolean = true) { open class ReiterViewModel(initialLoad: Boolean = true) : ViewModel() {
var uiState by mutableStateOf(ReiterUiState()) var uiState by mutableStateOf(ReiterUiState())
protected set protected set
@@ -62,10 +69,23 @@ open class ReiterViewModel(initialLoad: Boolean = true) {
editName = reiter.nachname, editName = reiter.nachname,
editLizenz = reiter.lizenz, editLizenz = reiter.lizenz,
editSparte = reiter.sparte, editSparte = reiter.sparte,
editStatus = reiter.status editStatus = reiter.status,
editFeiId = reiter.feiId ?: "",
editOepsNummer = reiter.oepsNummer ?: "",
editGeburtsdatum = reiter.geburtsdatum ?: "",
editEmail = reiter.email ?: "",
editTelefon = reiter.telefon ?: "",
editVerein = reiter.verein ?: ""
) )
} }
fun onEditFeiIdChange(value: String) { uiState = uiState.copy(editFeiId = value) }
fun onEditOepsNummerChange(value: String) { uiState = uiState.copy(editOepsNummer = value) }
fun onEditGeburtsdatumChange(value: String) { uiState = uiState.copy(editGeburtsdatum = value) }
fun onEditEmailChange(value: String) { uiState = uiState.copy(editEmail = value) }
fun onEditTelefonChange(value: String) { uiState = uiState.copy(editTelefon = value) }
fun onEditVereinChange(value: String) { uiState = uiState.copy(editVerein = value) }
fun onEditVornameChange(value: String) { fun onEditVornameChange(value: String) {
uiState = uiState.copy(editVorname = value) uiState = uiState.copy(editVorname = value)
} }
@@ -0,0 +1,12 @@
package at.mocode.frontend.features.veranstalter.domain
data class Veranstalter(
val id: String,
val name: String,
val verein: String? = null,
val adresse: String? = null,
val email: String? = null,
val telefon: String? = null,
val znsId: String? = null,
val oepsNummer: String? = null
)
@@ -52,17 +52,19 @@ kotlin {
implementation(projects.core.znsParser) implementation(projects.core.znsParser)
// Feature-Module // Feature-Module
implementation(projects.frontend.features.nennungFeature)
implementation(projects.frontend.features.pingFeature) implementation(projects.frontend.features.pingFeature)
implementation(projects.frontend.features.nennungFeature)
implementation(projects.frontend.features.znsImportFeature) implementation(projects.frontend.features.znsImportFeature)
implementation(projects.frontend.features.veranstalterFeature) implementation(projects.frontend.features.veranstalterFeature)
implementation(projects.frontend.features.veranstaltungFeature) implementation(projects.frontend.features.veranstaltungFeature)
implementation(projects.frontend.features.funktionaerFeature)
implementation(projects.frontend.features.profileFeature)
implementation(projects.frontend.features.reiterFeature)
implementation(projects.frontend.features.pferdeFeature)
implementation(projects.frontend.features.vereinFeature)
implementation(projects.frontend.features.turnierFeature) implementation(projects.frontend.features.turnierFeature)
implementation(project(":frontend:features:profile-feature")) implementation(projects.frontend.features.billingFeature)
implementation(project(":frontend:features:reiter-feature"))
implementation(project(":frontend:features:pferde-feature"))
implementation(project(":frontend:features:billing-feature"))
implementation(project(":frontend:features:verein-feature"))
// Compose Desktop // Compose Desktop
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
@@ -14,7 +14,9 @@ import at.mocode.frontend.core.sync.di.syncModule
import at.mocode.frontend.features.billing.di.billingModule 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.frontend.features.verein.di.vereinFeatureModule import at.mocode.frontend.features.verein.di.vereinFeatureModule
import at.mocode.nennung.feature.di.nennungFeatureModule import at.mocode.frontend.features.nennung.di.nennungFeatureModule
import at.mocode.frontend.features.pferde.di.pferdeModule
import at.mocode.frontend.features.reiter.di.reiterModule
import at.mocode.ping.feature.di.pingFeatureModule import at.mocode.ping.feature.di.pingFeatureModule
import at.mocode.zns.feature.di.znsImportModule import at.mocode.zns.feature.di.znsImportModule
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@@ -36,6 +38,8 @@ fun main() = application {
znsImportModule, znsImportModule,
profileModule, profileModule,
billingModule, billingModule,
pferdeModule,
reiterModule,
vereinFeatureModule, vereinFeatureModule,
desktopModule, desktopModule,
) )
@@ -27,6 +27,12 @@ import at.mocode.frontend.features.verein.presentation.VereinScreen
import at.mocode.frontend.features.verein.presentation.VereinViewModel import at.mocode.frontend.features.verein.presentation.VereinViewModel
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.frontend.features.pferde.presentation.PferdeScreen
import at.mocode.frontend.features.pferde.presentation.PferdeViewModel
import at.mocode.frontend.features.reiter.presentation.ReiterScreen
import at.mocode.frontend.features.reiter.presentation.ReiterViewModel
import at.mocode.frontend.features.nennung.presentation.NennungViewModel
import at.mocode.frontend.features.nennung.presentation.NennungsMaske
import at.mocode.turnier.feature.presentation.TurnierDetailScreen import at.mocode.turnier.feature.presentation.TurnierDetailScreen
import at.mocode.veranstalter.feature.presentation.FakeVeranstalterStore import at.mocode.veranstalter.feature.presentation.FakeVeranstalterStore
import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen
@@ -379,6 +385,8 @@ private fun DesktopContentArea(
// Onboarding ohne Login // Onboarding ohne Login
is AppScreen.Onboarding -> { is AppScreen.Onboarding -> {
val authTokenManager: at.mocode.frontend.core.auth.data.AuthTokenManager = koinInject() val authTokenManager: at.mocode.frontend.core.auth.data.AuthTokenManager = koinInject()
at.mocode.frontend.core.designsystem.theme.AppTheme {
Surface(color = MaterialTheme.colorScheme.background) {
at.mocode.desktop.v2.OnboardingScreen( at.mocode.desktop.v2.OnboardingScreen(
geraetName = obGeraet, geraetName = obGeraet,
secureKey = obKey, secureKey = obKey,
@@ -389,6 +397,8 @@ private fun DesktopContentArea(
onNavigate(AppScreen.VeranstaltungVerwaltung) onNavigate(AppScreen.VeranstaltungVerwaltung)
} }
} }
}
}
// Haupt-Zentrale: Veranstaltung-Verwaltung // Haupt-Zentrale: Veranstaltung-Verwaltung
is AppScreen.VeranstaltungVerwaltung -> { is AppScreen.VeranstaltungVerwaltung -> {
@@ -412,37 +422,50 @@ private fun DesktopContentArea(
} }
// --- Pferde-Verwaltung & Profil --- // --- Pferde-Verwaltung & Profil ---
is AppScreen.PferdVerwaltung -> at.mocode.desktop.v2.PferdeVerwaltungScreen( is AppScreen.PferdVerwaltung -> {
onBack = onBack, val viewModel = koinViewModel<PferdeViewModel>()
onEdit = { onNavigate(AppScreen.PferdProfil(it)) } PferdeScreen(viewModel = viewModel)
) }
is AppScreen.PferdProfil -> at.mocode.desktop.v2.PferdProfilV2( is AppScreen.PferdProfil -> {
id = currentScreen.id, val viewModel = koinViewModel<PferdeViewModel>()
onBack = onBack, // In der aktuellen Ausbaustufe wählen wir das Pferd im ViewModel aus
) LaunchedEffect(currentScreen.id) {
// Mock: Wir suchen das Pferd in den Suchergebnissen
viewModel.uiState.searchResults.find { it.id == currentScreen.id.toString() }?.let {
viewModel.selectPferd(it)
}
}
PferdeScreen(viewModel = viewModel)
}
// --- Reiter-Verwaltung & Profil --- // --- Reiter-Verwaltung & Profil ---
is AppScreen.ReiterVerwaltung -> at.mocode.desktop.v2.ReiterVerwaltungScreen( is AppScreen.ReiterVerwaltung -> {
onBack = onBack, val viewModel = koinViewModel<ReiterViewModel>()
onEdit = { onNavigate(AppScreen.ReiterProfil(it)) } ReiterScreen(viewModel = viewModel)
) }
is AppScreen.ReiterProfil -> at.mocode.desktop.v2.ReiterProfilV2( is AppScreen.ReiterProfil -> {
id = currentScreen.id, val viewModel = koinViewModel<ReiterViewModel>()
onBack = onBack, LaunchedEffect(currentScreen.id) {
) viewModel.uiState.searchResults.find { it.id == currentScreen.id.toString() }?.let {
viewModel.selectReiter(it)
}
}
ReiterScreen(viewModel = viewModel)
}
// --- Verein-Verwaltung & Profil --- // --- Verein-Verwaltung & Profil ---
is AppScreen.VereinVerwaltung -> at.mocode.desktop.v2.VereinVerwaltungScreen( is AppScreen.VereinVerwaltung -> {
onBack = onBack, val vereinViewModel: VereinViewModel = koinViewModel()
onEdit = { onNavigate(AppScreen.VereinProfil(it)) } VereinScreen(viewModel = vereinViewModel)
) }
is AppScreen.VereinProfil -> at.mocode.desktop.v2.VereinProfilV2( is AppScreen.VereinProfil -> {
id = currentScreen.id, val vereinViewModel: VereinViewModel = koinViewModel()
onBack = onBack, // Mock: Selektion im ViewModel (falls unterstützt)
) VereinScreen(viewModel = vereinViewModel)
}
// --- Funktionaer-Verwaltung & Profil --- // --- Funktionaer-Verwaltung & Profil ---
is AppScreen.FunktionaerVerwaltung -> at.mocode.desktop.v2.FunktionaerVerwaltungScreen( is AppScreen.FunktionaerVerwaltung -> at.mocode.desktop.v2.FunktionaerVerwaltungScreen(
@@ -664,6 +687,14 @@ private fun DesktopContentArea(
) )
} }
is AppScreen.Nennung -> {
val nennungViewModel: at.mocode.frontend.features.nennung.presentation.NennungViewModel = koinViewModel()
NennungsMaske(
viewModel = nennungViewModel,
onAbrechnungOeffnen = { /* Navigation zu Billing falls nötig */ }
)
}
// Fallback → Root // Fallback → Root
else -> AdminUebersichtScreen( else -> AdminUebersichtScreen(
onVeranstalterAuswahl = { onNavigate(AppScreen.VeranstalterAuswahl) }, onVeranstalterAuswahl = { onNavigate(AppScreen.VeranstalterAuswahl) },
+1
View File
@@ -137,6 +137,7 @@ include(":frontend:features:nennung-feature")
include(":frontend:features:zns-import-feature") include(":frontend:features:zns-import-feature")
include(":frontend:features:veranstalter-feature") include(":frontend:features:veranstalter-feature")
include(":frontend:features:veranstaltung-feature") include(":frontend:features:veranstaltung-feature")
include(":frontend:features:funktionaer-feature")
include(":frontend:features:profile-feature") include(":frontend:features:profile-feature")
include(":frontend:features:reiter-feature") include(":frontend:features:reiter-feature")
include(":frontend:features:pferde-feature") include(":frontend:features:pferde-feature")