Remove nennung-feature (domain models, DI modules, and UI components).
This commit is contained in:
@@ -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.
|
||||||
@@ -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).
|
||||||
|
|||||||
+17
@@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
+15
@@ -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
|
||||||
|
)
|
||||||
+103
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -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
-1
@@ -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(
|
||||||
+2
-2
@@ -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
|
||||||
+2
-2
@@ -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
|
||||||
+8
@@ -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() }
|
||||||
|
}
|
||||||
+6
-1
@@ -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) {
|
||||||
|
|||||||
+34
-2
@@ -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))
|
||||||
|
|
||||||
|
|||||||
+22
-3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -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() }
|
||||||
|
}
|
||||||
+7
-1
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
+63
@@ -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",
|
||||||
|
|||||||
+23
-3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -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,
|
||||||
)
|
)
|
||||||
|
|||||||
+55
-24
@@ -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) },
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user