feat: integriere Live-Daten in NennungsEingangScreen, erweitere NennungRemoteRepository um holeNennungen und markiereAlsGelesen, aktualisiere Port-Konfiguration

Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-15 22:59:20 +02:00
parent 6d631acce6
commit 67d7b38d79
4 changed files with 124 additions and 8 deletions
@@ -13,7 +13,7 @@ actual object PlatformConfig {
actual fun resolveMailServiceUrl(): String {
val env = System.getenv("MAIL_SERVICE_URL")?.trim().orEmpty()
if (env.isNotEmpty()) return env.removeSuffix("/")
return "http://localhost:8085"
return "http://localhost:8083"
}
actual fun resolveKeycloakUrl(): String {
@@ -3,10 +3,27 @@ package at.mocode.frontend.features.nennung.domain
import at.mocode.frontend.core.network.PlatformConfig
import at.mocode.frontend.features.nennung.presentation.web.NennungPayload
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.http.*
import kotlinx.serialization.Serializable
@Serializable
data class NennungResponse(
val id: String,
val turnierNr: String,
val status: String,
val vorname: String,
val nachname: String,
val lizenz: String,
val pferdName: String,
val pferdAlter: String,
val email: String,
val telefon: String?,
val bewerbe: String,
val bemerkungen: String?
)
@Serializable
data class NennungApiRequest(
val turnierNr: String,
@@ -24,6 +41,25 @@ data class NennungApiRequest(
class NennungRemoteRepository(private val client: HttpClient) {
private val mailServiceUrl = PlatformConfig.resolveMailServiceUrl()
suspend fun holeNennungen(): Result<List<NennungResponse>> {
return try {
val response = client.get("$mailServiceUrl/api/mail/nennungen")
Result.success(response.body())
} catch (e: Exception) {
Result.failure(e)
}
}
suspend fun markiereAlsGelesen(id: String): Result<Unit> {
return try {
// Endpunkt müsste im Backend noch implementiert werden, falls gewünscht.
// Für jetzt simuliert:
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
suspend fun sendeNennung(turnierNr: String, payload: NennungPayload): Result<Unit> {
return try {
val request = NennungApiRequest(
@@ -18,8 +18,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.milliseconds
import at.mocode.frontend.features.nennung.domain.NennungRemoteRepository
import at.mocode.frontend.features.nennung.domain.NennungResponse
import kotlinx.coroutines.launch
import org.koin.compose.koinInject
data class OnlineNennungMail(
val id: String,
@@ -38,14 +40,47 @@ data class OnlineNennungMail(
var status: String = "NEU"
)
fun NennungResponse.toMail() = OnlineNennungMail(
id = id,
sender = email,
empfaenger = "Meldestelle",
datum = "-", // Datum ist in Entity nicht direkt drin, könnte man ergänzen
turnierNr = turnierNr,
vorname = vorname,
nachname = nachname,
lizenz = lizenz,
pferd = pferdName,
pferdAlter = pferdAlter,
telefon = telefon,
bewerbe = bewerbe,
bemerkungen = bemerkungen,
status = if (status == "GELESEN") "GELESEN" else "NEU"
)
@Composable
fun NennungsEingangScreen(onBack: () -> Unit) {
val repository: NennungRemoteRepository = koinInject()
val scope = rememberCoroutineScope()
DesktopThemeV2 {
var mails by remember { mutableStateOf<List<OnlineNennungMail>>(emptyList()) }
var searchQuery by remember { mutableStateOf("") }
var selectedMail by remember { mutableStateOf<OnlineNennungMail?>(null) }
var isRefreshing by remember { mutableStateOf(false) }
val refresh = {
scope.launch {
isRefreshing = true
repository.holeNennungen().onSuccess { response ->
mails = response.map { it.toMail() }
}.onFailure {
// Fallback oder Fehleranzeige
if (mails.isEmpty()) mails = getMockMails()
}
isRefreshing = false
}
}
val filteredMails = remember(mails, searchQuery) {
if (searchQuery.isBlank()) mails
else mails.filter {
@@ -58,10 +93,7 @@ fun NennungsEingangScreen(onBack: () -> Unit) {
// Initiales Laden
LaunchedEffect(Unit) {
isRefreshing = true
delay(800.milliseconds)
mails = getMockMails()
isRefreshing = false
refresh()
}
if (selectedMail != null) {
@@ -69,9 +101,12 @@ fun NennungsEingangScreen(onBack: () -> Unit) {
mail = selectedMail!!,
onDismiss = { selectedMail = null },
onMarkProcessed = {
scope.launch {
repository.markiereAlsGelesen(selectedMail!!.id)
val updated = mails.map { if (it.id == selectedMail!!.id) it.copy(status = "GELESEN") else it }
mails = updated
selectedMail = null
}
}
)
}
@@ -85,7 +120,7 @@ fun NennungsEingangScreen(onBack: () -> Unit) {
Spacer(Modifier.weight(1f))
if (isRefreshing) CircularProgressIndicator(modifier = Modifier.size(24.dp), strokeWidth = 2.dp)
Button(
onClick = { /* Refresh Logik */ },
onClick = { refresh() },
enabled = !isRefreshing
) {
Icon(Icons.Default.Refresh, null)