### feat: optimiere Online-Nennformular und Turnier-Integration
Build and Publish Docker Images / build-and-push (., backend/services/mail/Dockerfile, mail-service, mail-service) (push) Successful in 6m27s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 4m18s

- **`OnlineNennungFormular.kt`:**
  - Erweiterung um Felder für Telefon und Pferdename.
  - Dynamische Validierung und UI-Anpassungen für mobile Geräte.
  - Zusätzliche Bewerbslisten und Auswahlbeschränkungen hinzugefügt.
- **`WebMainScreen.kt`:**
  - Aktualisierte Turniermetadata und verbesserte Responsivität.
This commit is contained in:
2026-04-23 04:48:46 +02:00
parent f620f46d15
commit 568d9dbb32
3 changed files with 494 additions and 130 deletions
@@ -1,14 +1,24 @@
package at.mocode.frontend.features.nennung.presentation.web
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import at.mocode.frontend.core.designsystem.theme.AppColors
@@ -16,112 +26,402 @@ import at.mocode.frontend.features.nennung.domain.Bewerb
import at.mocode.frontend.features.nennung.domain.Sparte
data class NennungPayload(
val vorname: String,
val nachname: String,
val lizenz: String,
val pferdName: String,
val pferdAlter: String,
val email: String,
val telefon: String,
val bewerbe: List<Bewerb>,
val bemerkungen: String
val vorname: String,
val nachname: String,
val lizenz: String,
val pferdName: String,
val pferdAlter: String,
val email: String,
val telefon: String,
val bewerbe: List<Bewerb>,
val bemerkungen: String
)
@Composable
fun OnlineNennungFormular(
turnierNr: String,
onNennenAbgeschickt: (NennungPayload) -> Unit,
onBack: () -> Unit
turnierNr: String,
onNennenAbgeschickt: (NennungPayload) -> Unit,
onBack: () -> Unit
) {
var vorname by remember { mutableStateOf("") }
var nachname by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
var vorname by remember { mutableStateOf("") }
var nachname by remember { mutableStateOf("") }
var telefon by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
var pferdName by remember { mutableStateOf("") }
var bemerkungen by remember { mutableStateOf("") }
val ausgewaehlteBewerbe = remember { mutableStateListOf<Bewerb>() }
val focusManager = LocalFocusManager.current
val isEmailValid = email.contains("@") && email.contains(".")
val canSubmit = vorname.isNotBlank() && nachname.isNotBlank() && isEmailValid
Box(
modifier = Modifier.fillMaxSize().background(Color(0xFFF8F9FA)),
contentAlignment = Alignment.Center
) {
Card(
modifier = Modifier.width(400.dp).padding(16.dp),
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = "Hallo Du! 👋",
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.ExtraBold,
color = AppColors.Primary
)
Text(
text = "Lass uns Plan-B testen. Turnier: $turnierNr",
style = MaterialTheme.typography.bodyMedium,
color = Color.Gray
)
OutlinedTextField(
value = vorname,
onValueChange = { vorname = it },
label = { Text("Vorname") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = nachname,
onValueChange = { nachname = it },
label = { Text("Nachname") },
singleLine = true,
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("E-Mail Adresse") },
singleLine = true,
isError = email.isNotEmpty() && !isEmailValid,
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(8.dp))
Button(
onClick = {
// Wir füllen den Rest mit Dummy-Daten für den Test
val payload = NennungPayload(
vorname = vorname,
nachname = nachname,
lizenz = "Lizenzfrei",
pferdName = "Test-Pferd (Plan-B)",
pferdAlter = "2020",
email = email,
telefon = "0123456789",
bewerbe = listOf(Bewerb(1, "Tag 1", 1, "08:00", "Test-Bewerb", Sparte.SPRINGEN, "A")),
bemerkungen = "Dies ist ein automatischer Test für Plan-B."
)
onNennenAbgeschickt(payload)
},
enabled = canSubmit,
modifier = Modifier.fillMaxWidth().height(50.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(containerColor = AppColors.Primary)
) {
Text("Jetzt schicken!", fontWeight = FontWeight.Bold, fontSize = 16.sp)
}
TextButton(onClick = onBack) {
Text("Zurück", color = Color.Gray)
}
}
}
val bewerbeListe = remember(turnierNr) {
if (turnierNr == "26128") {
listOf(
Bewerb(1, "Sa", 1, "", "Pony Stilspringprüfung (60 cm)", Sparte.SPRINGEN, "Pony"),
Bewerb(
2,
"Sa",
1,
"",
"Einlaufspringprüfung (60 cm) - Abt. 1: liz.frei / Abt. 2: mit Lizenz",
Sparte.SPRINGEN,
"E"
),
Bewerb(3, "Sa", 1, "", "Pony Stilspringprüfung (70 cm)", Sparte.SPRINGEN, "Pony"),
Bewerb(
4,
"Sa",
1,
"",
"Einlaufspringprüfung (70 cm) - Abt. 1: liz.frei / Abt. 2: mit Lizenz",
Sparte.SPRINGEN,
"E"
),
Bewerb(5, "Sa", 1, "", "Pony Stilspringprüfung (80 cm)", Sparte.SPRINGEN, "Pony"),
Bewerb(
6,
"Sa",
1,
"",
"Stilspringprüfung (80 cm) - Abt. 1: liz.frei / Abt. 2: R1 & 5-6j. Pf.",
Sparte.SPRINGEN,
"E"
),
Bewerb(7, "Sa", 1, "", "Pony Stilspringprüfung (95 cm)", Sparte.SPRINGEN, "Pony"),
Bewerb(8, "Sa", 1, "", "Springreiterbewerb liz.frei (95 cm)", Sparte.SPRINGEN, "E"),
Bewerb(9, "Sa", 1, "", "Standardspringprüfung (95 cm) - Abt. 1: R1 / Abt. 2: R2+", Sparte.SPRINGEN, "A1"),
Bewerb(
10,
"Sa",
1,
"",
"Springpferdeprüfung (105 cm) - Abt. 1: 4j. / Abt. 2: 5-6j.",
Sparte.SPRINGEN,
"A"
),
Bewerb(11, "Sa", 1, "", "Stilspringprüfung (105 cm) - Abt. 1: R1", Sparte.SPRINGEN, "A2"),
Bewerb(
12,
"Sa",
1,
"",
"Standardspringprüfung (105 cm) - Abt. 1: R1 / Abt. 2: R2/RS2+",
Sparte.SPRINGEN,
"A2"
),
Bewerb(13, "Sa", 1, "", "Stilspringprüfung (115 cm) - Abt. 1: R1", Sparte.SPRINGEN, "L"),
Bewerb(
14,
"Sa",
1,
"",
"Standardspringprüfung (115 cm) - Abt. 1: R1 / Abt. 2: R2/RS2+",
Sparte.SPRINGEN,
"L"
),
)
} else {
listOf(
Bewerb(1, "So", 1, "", "Dressurreiterprüfung Reiterpass (Aufg. R1)", Sparte.DRESSUR, "RP"),
Bewerb(2, "So", 1, "", "Dressurreiterprüfung Reiternadel (Aufg. R4)", Sparte.DRESSUR, "RN"),
Bewerb(3, "So", 1, "", "Dressurreiterprüfung lizenzfrei (Aufg. LF1)", Sparte.DRESSUR, "LF"),
Bewerb(4, "So", 1, "", "Dressurreiterprüfung lizenzfrei (Aufg. LF3)", Sparte.DRESSUR, "LF"),
Bewerb(5, "So", 1, "", "First Ridden", Sparte.DRESSUR, "FR"),
Bewerb(6, "So", 1, "", "Führzügelklasse", Sparte.DRESSUR, "FZ"),
Bewerb(7, "So", 1, "", "Pony Dressurprüfung Kl. A (Aufg. P1)", Sparte.DRESSUR, "A"),
Bewerb(
8,
"So",
1,
"",
"Dressurreiterprüfung Kl. A (Aufg. DRA1) - Abt. 1: R1/RD1 / Abt. 2: R2/RD2+",
Sparte.DRESSUR,
"A"
),
Bewerb(
9,
"So",
1,
"",
"Dressurprüfung Kl. A (Aufg. A5) - Abt. 1: R1/RD1 / Abt. 2: R2/RD2+",
Sparte.DRESSUR,
"A"
),
Bewerb(
13,
"So",
1,
"",
"Dressurpferdeprüfung Kl. A (Aufg. DPA1) - Abt. 1: 4j. / Abt. 2: 5-6j.",
Sparte.DRESSUR,
"DP-A"
),
Bewerb(14, "So", 1, "", "Dressurpferdprüfung Kl. L (Aufg. DPL1) - 5-6j. Pferde", Sparte.DRESSUR, "DP-L"),
Bewerb(10, "So", 1, "", "Pony Dressurprüfung Kl. L (Aufg. P6)", Sparte.DRESSUR, "L"),
Bewerb(
11,
"So",
1,
"",
"Dressurreiterprüfung Kl. L (Aufg. DRL1) - Abt. 1: R1/RD1 / Abt. 2: R2/RD2+",
Sparte.DRESSUR,
"L"
),
Bewerb(
12,
"So",
1,
"",
"Dressurprüfung Kl. L (Aufg. L3) - Abt. 1: R1/RD1 / Abt. 2: R2/RD2+",
Sparte.DRESSUR,
"L"
),
)
}
}
val isEmailValid = email.contains("@") && email.contains(".")
val canSubmit =
vorname.isNotBlank() && nachname.isNotBlank() && isEmailValid && pferdName.isNotBlank() && ausgewaehlteBewerbe.isNotEmpty()
BoxWithConstraints(
modifier = Modifier.fillMaxSize().background(Color(0xFFF0F2F5)),
contentAlignment = Alignment.TopCenter
) {
val isMobile = maxWidth < 600.dp
Column(
modifier = Modifier
.widthIn(max = 800.dp)
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.padding(if (isMobile) 4.dp else 12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(if (isMobile) 0.dp else 16.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = if (isMobile) 2.dp else 6.dp)
) {
Column(
modifier = Modifier.padding(if (isMobile) 16.dp else 24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = if (turnierNr == "26128") "Online-Nennung: Springturnier Neumarkt" else "Online-Nennung: Dressurturnier Neumarkt",
style = if (isMobile) MaterialTheme.typography.headlineSmall else MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.ExtraBold,
color = AppColors.Primary
)
Text(
text = "Turnier-Nr: $turnierNr | Datum: ${if (turnierNr == "26128") "25. April 2026" else "26. April 2026"}",
style = MaterialTheme.typography.titleMedium,
color = Color.Gray
)
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp), thickness = 1.dp, color = Color.LightGray)
Text("Reiter & Kontakt", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
if (isMobile) {
OutlinedTextField(
value = vorname,
onValueChange = { vorname = it },
label = { Text("Vorname*") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
OutlinedTextField(
value = nachname,
onValueChange = { nachname = it },
label = { Text("Nachname*") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
} else {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedTextField(
value = vorname,
onValueChange = { vorname = it },
label = { Text("Vorname*") },
modifier = Modifier.weight(1f),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
OutlinedTextField(
value = nachname,
onValueChange = { nachname = it },
label = { Text("Nachname*") },
modifier = Modifier.weight(1f),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
}
}
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("E-Mail Adresse* (für Bestätigung)") },
isError = email.isNotEmpty() && !isEmailValid,
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
OutlinedTextField(
value = telefon,
onValueChange = { telefon = it },
label = { Text("Telefon-Nr.") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone, imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
)
Spacer(Modifier.height(4.dp))
Text("Pferd", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
OutlinedTextField(
value = pferdName,
onValueChange = { pferdName = it },
label = { Text("Pferdename / Kopfnummer*") },
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) })
)
Spacer(Modifier.height(8.dp))
Text("Bewerbe auswählen*", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
bewerbeListe.forEach { bewerb ->
val selected = ausgewaehlteBewerbe.contains(bewerb)
val parts = bewerb.name.split(" - ", limit = 2)
val mainName = parts[0]
val abteilung = if (parts.size > 1) parts[1] else ""
Surface(
color = if (selected) AppColors.PrimaryContainer.copy(alpha = 0.7f) else Color.Transparent,
shape = RoundedCornerShape(12.dp),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 2.dp)
) {
Row(
modifier = Modifier
.clickable {
if (selected) ausgewaehlteBewerbe.remove(bewerb)
else ausgewaehlteBewerbe.add(bewerb)
}
.padding(horizontal = 8.dp, vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = selected,
onCheckedChange = { checked ->
if (checked == true) ausgewaehlteBewerbe.add(bewerb)
else ausgewaehlteBewerbe.remove(bewerb)
},
colors = CheckboxDefaults.colors(checkedColor = AppColors.Primary)
)
Spacer(Modifier.width(8.dp))
Column {
Text(
"${bewerb.nr}. $mainName",
fontWeight = if (selected) FontWeight.Bold else FontWeight.SemiBold,
fontSize = if (isMobile) 14.sp else 16.sp
)
if (abteilung.isNotBlank()) {
Text(
abteilung,
style = MaterialTheme.typography.bodySmall,
fontSize = if (isMobile) 11.sp else 12.sp,
color = if (selected) Color.Black.copy(alpha = 0.8f) else Color.Gray,
modifier = Modifier.padding(start = if (isMobile) 8.dp else 12.dp)
)
}
}
}
}
}
if (ausgewaehlteBewerbe.size > 3) {
Text(
"⚠️ Hinweis: Ein Pferd darf maximal 3x pro Tag starten.",
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 4.dp)
)
}
Spacer(Modifier.height(8.dp))
Text("Wünsche / Anmerkungen", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
OutlinedTextField(
value = bemerkungen,
onValueChange = { bemerkungen = it },
placeholder = { Text("z.B. Startzeit-Wünsche, Stallnachbarn...") },
modifier = Modifier.fillMaxWidth(),
minLines = 3,
shape = RoundedCornerShape(12.dp)
)
Spacer(Modifier.height(24.dp))
Button(
onClick = {
val payload = NennungPayload(
vorname = vorname,
nachname = nachname,
lizenz = "N/A",
pferdName = pferdName,
pferdAlter = "N/A",
email = email,
telefon = telefon,
bewerbe = ausgewaehlteBewerbe.toList(),
bemerkungen = bemerkungen
)
onNennenAbgeschickt(payload)
},
enabled = canSubmit,
modifier = Modifier.fillMaxWidth().height(if (isMobile) 56.dp else 64.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFFFFBF00),
disabledContainerColor = Color(0xFFFFBF00).copy(alpha = 0.4f)
),
elevation = ButtonDefaults.buttonElevation(defaultElevation = 4.dp, pressedElevation = 8.dp)
) {
Text(
"Jetzt nennen",
fontWeight = FontWeight.ExtraBold,
fontSize = if (isMobile) 18.sp else 20.sp,
color = if (canSubmit) Color.Black else Color.DarkGray
)
}
Text(
text = "Mit dem Absenden akzeptiere ich die Speicherung meiner Daten für die Turnierabwicklung.\nSchutz gegen automatisierte Eingaben ist aktiv.",
style = MaterialTheme.typography.labelSmall,
color = Color.Gray,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
lineHeight = 16.sp
)
TextButton(onClick = onBack, modifier = Modifier.fillMaxWidth()) {
Text("Abbrechen", color = Color.Gray, fontSize = 16.sp)
}
}
}
}
}
}
@@ -120,12 +120,12 @@ fun LandingPage(
listOf(
VeranstaltungWebModel(
id = 1,
name = "CSN-B* Neumarkt",
ort = "Neumarkt am Wallersee",
datum = "24. - 26. April 2026",
name = "Turniere in Neumarkt",
ort = "Reitanlage Stroblmair",
datum = "25. - 26. April 2026",
turniere = listOf(
TurnierWebModel(101, "Springturnier Neumarkt", "Ausschreibung_Neumarkt.pdf"),
TurnierWebModel(102, "Dressurturnier Neumarkt", "Ausschreibung_Dressur.pdf")
TurnierWebModel(26128, "Springturnier (CSN-C NEU)", "26128.pdf"),
TurnierWebModel(26129, "Dressurturnier (CDN-C NEU)", "26129.pdf")
)
)
)
@@ -207,33 +207,66 @@ fun TurnierCardWeb(
turnier: TurnierWebModel,
onNennenClick: () -> Unit
) {
OutlinedCard(
modifier = Modifier.fillMaxWidth().padding(top = 8.dp),
colors = CardDefaults.outlinedCardColors(containerColor = AppColors.BackgroundLight)
) {
Row(
modifier = Modifier.padding(12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
BoxWithConstraints {
val isMobile = maxWidth < 500.dp
OutlinedCard(
modifier = Modifier.fillMaxWidth().padding(top = 8.dp),
colors = CardDefaults.outlinedCardColors(containerColor = AppColors.BackgroundLight)
) {
Column(modifier = Modifier.weight(1f)) {
Text(turnier.name, fontWeight = FontWeight.Bold)
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
TextButton(onClick = { /* PDF öffnen Logik */ }) {
Icon(Icons.Default.Description, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Ausschreibung")
if (isMobile) {
Column(modifier = Modifier.padding(12.dp)) {
Text(turnier.name, fontWeight = FontWeight.Bold)
Spacer(Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
TextButton(
onClick = { /* PDF öffnen Logik */ },
modifier = Modifier.weight(1f)
) {
Icon(Icons.Default.Description, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Ausschreibung")
}
Button(
onClick = onNennenClick,
colors = ButtonDefaults.buttonColors(containerColor = AppColors.Success),
modifier = Modifier.weight(1f)
) {
Icon(Icons.AutoMirrored.Filled.OpenInNew, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Nennen")
}
}
}
Button(
onClick = onNennenClick,
colors = ButtonDefaults.buttonColors(containerColor = AppColors.Success)
} else {
Row(
modifier = Modifier.padding(12.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Icon(Icons.AutoMirrored.Filled.OpenInNew, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Online-Nennen")
Column(modifier = Modifier.weight(1f)) {
Text(turnier.name, fontWeight = FontWeight.Bold)
}
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
TextButton(onClick = { /* PDF öffnen Logik */ }) {
Icon(Icons.Default.Description, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Ausschreibung")
}
Button(
onClick = onNennenClick,
colors = ButtonDefaults.buttonColors(containerColor = AppColors.Success)
) {
Icon(Icons.AutoMirrored.Filled.OpenInNew, contentDescription = null)
Spacer(Modifier.width(4.dp))
Text("Online-Nennen")
}
}
}
}
}