From f7d11ccf9700ff6c66165c8d9e4ed2fcee781bc2 Mon Sep 17 00:00:00 2001 From: StefanMoCoAt Date: Thu, 23 Apr 2026 09:06:20 +0200 Subject: [PATCH] ### feat: verbessere Feedback- und Fehlerhandling im Nennformular MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - **OnlineNennungFormular:** Ladeindikator und Fehleranzeige bei API-Fehlermeldungen hinzugefügt. - **WebMainScreen:** Navigation zum Erfolgsscreen erfolgt erst nach erfolgreicher API-Bestätigung. - **UI:** Aktualisiere Versionsmarker auf `v2026-04-23.11 - NETWORK STATUS FIX`. --- .../03_Journal/2026-04-23_Plan-B-Formulare.md | 10 ++-- .../presentation/web/OnlineNennungFormular.kt | 50 ++++++++++++++++--- .../frontend/shell/web/WebMainScreen.kt | 10 ++-- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/docs/03_Journal/2026-04-23_Plan-B-Formulare.md b/docs/03_Journal/2026-04-23_Plan-B-Formulare.md index c6800f67..97934a53 100644 --- a/docs/03_Journal/2026-04-23_Plan-B-Formulare.md +++ b/docs/03_Journal/2026-04-23_Plan-B-Formulare.md @@ -30,9 +30,9 @@ Die "Hallo Du!" Test-UI wurde durch produktive, fachlich korrekte Formulare erse **Status:** Bereit für den Live-Einsatz am Wochenende. 🚀 -### 2026-04-23 08:30 - Version 10: HTTPS & CORS FIX -- **Problem**: Mixed Content Fehler (HTTPS -> HTTP) und CORS-Blockade auf `app.mo-code.at`. +### 2026-04-23 09:10 - Version 11: Netzwerk-Status & Error-Handling Fix +- **Problem**: Kein Feedback beim Absenden, Mixed Content trotz V10, sofortiger Navigations-Reset. - **Lösung**: - - `MailController.kt`: Whitelist für `https://app.mo-code.at` in `@CrossOrigin` hinzugefügt. - - `dc-planb.yaml`: API-URLs auf `https://api.mo-code.at` umgestellt. - - UI-Marker auf `v2026-04-23.10 - HTTPS FIX` aktualisiert. + - `OnlineNennungFormular.kt`: Ladeindikator und dynamische Fehleranzeige implementiert. + - `WebMainScreen.kt`: Navigation zum Erfolgsscreen erfolgt nun erst nach Bestätigung durch die API. + - UI-Marker auf `v2026-04-23.11 - NETWORK STATUS FIX` aktualisiert. diff --git a/frontend/features/nennung-feature/src/commonMain/kotlin/at/mocode/frontend/features/nennung/presentation/web/OnlineNennungFormular.kt b/frontend/features/nennung-feature/src/commonMain/kotlin/at/mocode/frontend/features/nennung/presentation/web/OnlineNennungFormular.kt index 8b472f02..980ac2e0 100644 --- a/frontend/features/nennung-feature/src/commonMain/kotlin/at/mocode/frontend/features/nennung/presentation/web/OnlineNennungFormular.kt +++ b/frontend/features/nennung-feature/src/commonMain/kotlin/at/mocode/frontend/features/nennung/presentation/web/OnlineNennungFormular.kt @@ -40,7 +40,7 @@ data class NennungPayload( @Composable fun OnlineNennungFormular( turnierNr: String, - onNennenAbgeschickt: (NennungPayload) -> Unit, + onNennenAbgeschickt: (NennungPayload, (Boolean, String?) -> Unit) -> Unit, onBack: () -> Unit ) { var vorname by remember { mutableStateOf("") } @@ -52,6 +52,9 @@ fun OnlineNennungFormular( val ausgewaehlteBewerbe = remember { mutableStateListOf() } val focusManager = LocalFocusManager.current + var isLoading by remember { mutableStateOf(false) } + var errorMessage by remember { mutableStateOf(null) } + val bewerbeListe = remember(turnierNr) { if (turnierNr == "26128") { listOf( @@ -381,7 +384,7 @@ fun OnlineNennungFormular( shape = RoundedCornerShape(12.dp), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { - if (canSubmit) { + if (canSubmit && !isLoading) { val payload = NennungPayload( vorname = vorname, nachname = nachname, @@ -393,11 +396,33 @@ fun OnlineNennungFormular( bewerbe = ausgewaehlteBewerbe.toList(), bemerkungen = bemerkungen ) - onNennenAbgeschickt(payload) + isLoading = true + errorMessage = null + onNennenAbgeschickt(payload) { success, error -> + isLoading = false + if (!success) { + errorMessage = error ?: "Ein unbekannter Fehler ist aufgetreten." + } + } } }) ) + if (errorMessage != null) { + Card( + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.errorContainer), + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) + ) { + Text( + text = errorMessage!!, + color = MaterialTheme.colorScheme.onErrorContainer, + modifier = Modifier.padding(12.dp), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold + ) + } + } + Spacer(Modifier.height(24.dp)) Button( @@ -413,9 +438,16 @@ fun OnlineNennungFormular( bewerbe = ausgewaehlteBewerbe.toList(), bemerkungen = bemerkungen ) - onNennenAbgeschickt(payload) + isLoading = true + errorMessage = null + onNennenAbgeschickt(payload) { success, error -> + isLoading = false + if (!success) { + errorMessage = error ?: "Ein unbekannter Fehler ist aufgetreten." + } + } }, - enabled = canSubmit, + enabled = canSubmit && !isLoading, modifier = Modifier.fillMaxWidth().height(if (isMobile) 56.dp else 64.dp), shape = RoundedCornerShape(12.dp), colors = ButtonDefaults.buttonColors( @@ -424,11 +456,15 @@ fun OnlineNennungFormular( ), elevation = ButtonDefaults.buttonElevation(defaultElevation = 4.dp, pressedElevation = 8.dp) ) { + if (isLoading) { + CircularProgressIndicator(modifier = Modifier.size(24.dp), color = Color.Black) + Spacer(Modifier.width(12.dp)) + } Text( - "Jetzt nennen", + text = if (isLoading) "Wird gesendet..." else "Jetzt nennen", fontWeight = FontWeight.ExtraBold, fontSize = if (isMobile) 18.sp else 20.sp, - color = if (canSubmit) Color.Black else Color.DarkGray + color = if (canSubmit && !isLoading) Color.Black else Color.DarkGray ) } diff --git a/frontend/shells/meldestelle-web/src/wasmJsMain/kotlin/at/mocode/frontend/shell/web/WebMainScreen.kt b/frontend/shells/meldestelle-web/src/wasmJsMain/kotlin/at/mocode/frontend/shell/web/WebMainScreen.kt index e6228e69..332d068a 100644 --- a/frontend/shells/meldestelle-web/src/wasmJsMain/kotlin/at/mocode/frontend/shell/web/WebMainScreen.kt +++ b/frontend/shells/meldestelle-web/src/wasmJsMain/kotlin/at/mocode/frontend/shell/web/WebMainScreen.kt @@ -99,14 +99,16 @@ fun MainAppContent() { is WebScreen.Nennung -> OnlineNennungFormular( turnierNr = screen.turnierId.toString(), - onNennenAbgeschickt = { payload -> + onNennenAbgeschickt = { payload, onResult -> scope.launch { val result = nennungRepository.sendeNennung(screen.turnierId.toString(), payload) if (result.isSuccess) { + onResult(true, null) currentScreen = WebScreen.Erfolg(payload.email) } else { - // Hier könnte man eine Fehlermeldung anzeigen - println("Fehler beim Senden der Nennung: ${result.exceptionOrNull()?.message}") + val error = result.exceptionOrNull()?.message + onResult(false, error) + println("Fehler beim Senden der Nennung: $error") } } }, @@ -122,7 +124,7 @@ fun MainAppContent() { // Dezentraler Versions-Marker in der unteren rechten Ecke Box(modifier = Modifier.fillMaxSize().padding(8.dp), contentAlignment = Alignment.BottomEnd) { Text( - text = "v2026-04-23.10 - HTTPS FIX", + text = "v2026-04-23.11 - NETWORK STATUS FIX", style = MaterialTheme.typography.labelSmall, color = Color.LightGray.copy(alpha = 0.5f) )