chore: enhance Stammdaten-Verwaltung and refine desktop UX across multiple features, fix typo in settings.json, enable WASM builds, and add Master-Detail layout for Funktionäre
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
This commit is contained in:
+138
-21
@@ -1,9 +1,9 @@
|
||||
package at.mocode.frontend.features.reiter.presentation
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import at.mocode.frontend.core.designsystem.components.*
|
||||
@@ -23,7 +23,8 @@ fun ReiterScreen(
|
||||
ReiterListContent(
|
||||
uiState = uiState,
|
||||
onSearchChange = viewModel::onSearchQueryChange,
|
||||
onReiterSelected = viewModel::selectReiter
|
||||
onReiterSelected = viewModel::selectReiter,
|
||||
onAddNew = { viewModel.addNewReiter() }
|
||||
)
|
||||
},
|
||||
detail = {
|
||||
@@ -43,6 +44,11 @@ fun ReiterScreen(
|
||||
onSave = viewModel::onSave,
|
||||
onCancel = viewModel::onCancel
|
||||
)
|
||||
} else if (uiState.selectedReiter != null) {
|
||||
ReiterCard(
|
||||
reiter = uiState.selectedReiter,
|
||||
onEdit = { viewModel.selectReiter(uiState.selectedReiter) }
|
||||
)
|
||||
} else {
|
||||
PlaceholderContent(
|
||||
title = "Kein Reiter ausgewählt",
|
||||
@@ -57,13 +63,20 @@ fun ReiterScreen(
|
||||
private fun ReiterListContent(
|
||||
uiState: ReiterUiState,
|
||||
onSearchChange: (String) -> Unit,
|
||||
onReiterSelected: (Reiter) -> Unit
|
||||
onReiterSelected: (Reiter) -> Unit,
|
||||
onAddNew: () -> Unit
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
MsFilterBar(
|
||||
searchQuery = uiState.searchQuery,
|
||||
onSearchQueryChange = onSearchChange,
|
||||
resultCount = uiState.searchResults.size
|
||||
resultCount = uiState.searchResults.size,
|
||||
actions = {
|
||||
MsButton(
|
||||
text = "Reiter anlegen",
|
||||
onClick = onAddNew
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@@ -72,14 +85,9 @@ private fun ReiterListContent(
|
||||
items = uiState.searchResults,
|
||||
columns = listOf(
|
||||
MsColumnDefinition(
|
||||
title = "Vorname",
|
||||
weight = 1f,
|
||||
cellRenderer = { Text(it.vorname, style = MaterialTheme.typography.bodySmall) }
|
||||
),
|
||||
MsColumnDefinition(
|
||||
title = "Nachname",
|
||||
weight = 1f,
|
||||
cellRenderer = { Text(it.nachname, style = MaterialTheme.typography.bodySmall) }
|
||||
title = "Name",
|
||||
weight = 1.5f,
|
||||
cellRenderer = { Text(it.name, style = MaterialTheme.typography.bodySmall) }
|
||||
),
|
||||
MsColumnDefinition(
|
||||
title = "Lizenz",
|
||||
@@ -103,6 +111,107 @@ private fun ReiterListContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReiterCard(
|
||||
reiter: Reiter,
|
||||
onEdit: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().padding(16.dp),
|
||||
verticalArrangement = Arrangement.Top,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth().wrapContentHeight(),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(24.dp)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Surface(
|
||||
modifier = Modifier.size(48.dp),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
|
||||
) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Text(
|
||||
text = (reiter.vorname.take(1) + reiter.nachname.take(1)).uppercase(),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(16.dp))
|
||||
Column {
|
||||
Text(
|
||||
reiter.name,
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
"ÖPS-Nr: ${reiter.oepsNummer ?: "-"}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MsStatusBadge(
|
||||
text = reiter.status.label,
|
||||
containerColor = reiter.status.color.copy(alpha = 0.1f),
|
||||
contentColor = reiter.status.color
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
ReiterDetailItem(label = "Lizenz", value = reiter.lizenz.label, modifier = Modifier.weight(1f))
|
||||
ReiterDetailItem(label = "Hauptsparte", value = reiter.sparte.label, modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
ReiterDetailItem(label = "E-Mail", value = reiter.email ?: "-", modifier = Modifier.weight(1f))
|
||||
ReiterDetailItem(label = "Telefon", value = reiter.telefon ?: "-", modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
ReiterDetailItem(label = "Verein", value = reiter.verein ?: "-", modifier = Modifier.weight(1f))
|
||||
ReiterDetailItem(label = "FEI-ID", value = reiter.feiId ?: "-", modifier = Modifier.weight(1f))
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(32.dp))
|
||||
|
||||
MsButton(
|
||||
text = "Reiterdaten bearbeiten",
|
||||
onClick = onEdit,
|
||||
fullWidth = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReiterDetailItem(label: String, value: String, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
Text(label, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||
Text(value, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurface)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReiterEditorContent(
|
||||
uiState: ReiterUiState,
|
||||
@@ -133,13 +242,15 @@ private fun ReiterEditorContent(
|
||||
value = uiState.editVorname,
|
||||
onValueChange = onVornameChange,
|
||||
label = "Vorname",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = uiState.editName,
|
||||
onValueChange = onNachnameChange,
|
||||
label = "Nachname",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -150,13 +261,15 @@ private fun ReiterEditorContent(
|
||||
value = uiState.editFeiId,
|
||||
onValueChange = onFeiIdChange,
|
||||
label = "FEI ID",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = uiState.editOepsNummer,
|
||||
onValueChange = onOepsNummerChange,
|
||||
label = "ÖPS Nummer",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -167,13 +280,15 @@ private fun ReiterEditorContent(
|
||||
value = uiState.editGeburtsdatum,
|
||||
onValueChange = onGeburtsdatumChange,
|
||||
label = "Geburtsdatum",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = uiState.editVerein,
|
||||
onValueChange = onVereinChange,
|
||||
label = "Verein",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,13 +299,15 @@ private fun ReiterEditorContent(
|
||||
value = uiState.editEmail,
|
||||
onValueChange = onEmailChange,
|
||||
label = "E-Mail",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
MsTextField(
|
||||
value = uiState.editTelefon,
|
||||
onValueChange = onTelefonChange,
|
||||
label = "Telefon",
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
compact = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+21
@@ -18,6 +18,7 @@ data class ReiterUiState(
|
||||
val selectedReiter: Reiter? = null,
|
||||
val isEditing: Boolean = false,
|
||||
val isLoading: Boolean = false,
|
||||
val editId: String = "",
|
||||
val editName: String = "",
|
||||
val editVorname: String = "",
|
||||
val editLizenz: LizenzKlasse = LizenzKlasse.KEINE,
|
||||
@@ -65,6 +66,7 @@ open class ReiterViewModel(initialLoad: Boolean = true) : ViewModel() {
|
||||
uiState = uiState.copy(
|
||||
selectedReiter = reiter,
|
||||
isEditing = true,
|
||||
editId = reiter.id,
|
||||
editVorname = reiter.vorname,
|
||||
editName = reiter.nachname,
|
||||
editLizenz = reiter.lizenz,
|
||||
@@ -79,6 +81,25 @@ open class ReiterViewModel(initialLoad: Boolean = true) : ViewModel() {
|
||||
)
|
||||
}
|
||||
|
||||
fun addNewReiter() {
|
||||
uiState = uiState.copy(
|
||||
selectedReiter = null,
|
||||
isEditing = true,
|
||||
editId = "",
|
||||
editVorname = "",
|
||||
editName = "",
|
||||
editLizenz = LizenzKlasse.KEINE,
|
||||
editSparte = Sparte.KEINE,
|
||||
editStatus = ReiterStatus.AKTIV,
|
||||
editFeiId = "",
|
||||
editOepsNummer = "",
|
||||
editGeburtsdatum = "",
|
||||
editEmail = "",
|
||||
editTelefon = "",
|
||||
editVerein = ""
|
||||
)
|
||||
}
|
||||
|
||||
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) }
|
||||
|
||||
Reference in New Issue
Block a user