feat(frontend+billing): integrate billing UI and navigation into Turnier module

- **Navigation Updates:**
  - Added `AppScreen.Billing` route for participant billing linked to an event and tournament.

- **UI Additions:**
  - Introduced `BillingScreen` and `BillingViewModel` for participant account management and manual transactions.
  - Updated `TurnierAbrechnungTab` to include `BillingScreen` and enable account interaction.

- **Turnier Enhancements:**
  - Enhanced `NennungenTabContent` to support navigation to billing via a new interaction.
  - Added billing feature as a dependency to `turnier-feature`.

- **Billing Domain:**
  - Extended `Money` to include subtraction operation and improved formatting for negative amounts.
  - Added DTOs (`TeilnehmerKontoDto`, `BuchungDto`, `BuchungRequest`) for seamless data exchange with backend.

- **Test Improvements:**
  - Updated `PreviewTurnierAbrechnungTab` to include interactive billing placeholder.

- **Misc Updates:**
  - Enhanced breadcrumb navigation for billing in `DesktopMainLayout` for better user experience.
This commit is contained in:
2026-04-10 14:30:50 +02:00
parent a7e1872d10
commit 1ba4845f6c
13 changed files with 487 additions and 31 deletions
@@ -10,12 +10,8 @@ import androidx.compose.material.icons.filled.Devices
import androidx.compose.material.icons.filled.Wifi
import androidx.compose.material.icons.filled.WifiOff
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -23,6 +19,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import at.mocode.frontend.core.navigation.AppScreen
import at.mocode.frontend.features.billing.presentation.BillingScreen
import at.mocode.frontend.features.billing.presentation.BillingViewModel
import at.mocode.frontend.features.profile.presentation.ProfileScreen
import at.mocode.frontend.features.profile.presentation.ProfileViewModel
import at.mocode.frontend.features.verein.presentation.VereinScreen
@@ -31,7 +29,6 @@ import at.mocode.ping.feature.presentation.PingScreen
import at.mocode.ping.feature.presentation.PingViewModel
import at.mocode.turnier.feature.presentation.TurnierDetailScreen
import at.mocode.veranstalter.feature.presentation.FakeVeranstalterStore
import at.mocode.veranstalter.feature.presentation.VeranstalterNeuScreen
import at.mocode.veranstaltung.feature.presentation.AdminUebersichtScreen
import at.mocode.veranstaltung.feature.presentation.VeranstaltungDetailScreen
import at.mocode.veranstaltung.feature.presentation.VeranstaltungNeuScreen
@@ -237,6 +234,33 @@ private fun DesktopTopBar(
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.Billing -> {
BreadcrumbSeparator()
Text(
text = "Veranstaltung #${currentScreen.veranstaltungId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.VeranstaltungProfil(0, currentScreen.veranstaltungId))
},
)
BreadcrumbSeparator()
Text(
text = "Turnier ${currentScreen.turnierId}",
color = TopBarTextColor.copy(alpha = 0.75f),
fontSize = 14.sp,
modifier = Modifier.clickable {
onNavigate(AppScreen.TurnierDetail(currentScreen.veranstaltungId, currentScreen.turnierId))
},
)
BreadcrumbSeparator()
Text(
text = "Abrechnung",
color = TopBarTextColor,
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
)
}
is AppScreen.TurnierNeu -> {
BreadcrumbSeparator()
Text(
@@ -630,6 +654,16 @@ private fun DesktopContentArea(
)
}
// --- Billing ---
is AppScreen.Billing -> {
val billingViewModel: BillingViewModel = koinViewModel()
BillingScreen(
viewModel = billingViewModel,
veranstaltungId = currentScreen.veranstaltungId,
onBack = onBack
)
}
// Fallback → Root
else -> AdminUebersichtScreen(
onVeranstalterAuswahl = { onNavigate(AppScreen.VeranstalterAuswahl) },
@@ -151,7 +151,7 @@ fun PreviewTurnierArtikelTab() {
@Composable
fun PreviewTurnierAbrechnungTab() {
MaterialTheme {
AbrechnungTabContent()
AbrechnungTabContent(veranstaltungId = 1L)
}
}