feat(Tournament): update tournament participation UI and localization
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 43s

- Changed the icon for tournament participations in the navigation to better represent the feature.
- Updated localization keys for tournament participations across multiple languages, enhancing clarity and user understanding.
- Introduced a new tab for official tournament participations in the mobile app, improving navigation and access to tournament details.
- Enhanced the TournamentsScreen to include options for creating and managing official tournaments, streamlining user interactions.
This commit is contained in:
Torsten Schulz (local)
2026-05-14 17:51:19 +02:00
parent 3d1dfe9a4c
commit 2f3f4fb275
24 changed files with 5472 additions and 58 deletions

View File

@@ -1,10 +1,17 @@
package de.tt_tagebuch.shared.api
import de.tt_tagebuch.shared.api.http.AuthedHttpClient
import de.tt_tagebuch.shared.api.models.ClubLeagueOptionDto
import de.tt_tagebuch.shared.api.models.ClubTeamCreateBody
import de.tt_tagebuch.shared.api.models.ClubTeamDto
import de.tt_tagebuch.shared.api.models.ClubTeamUpdateBody
import io.ktor.client.call.body
import io.ktor.client.request.delete
import io.ktor.client.request.get
import io.ktor.client.request.parameter
import io.ktor.client.request.post
import io.ktor.client.request.put
import io.ktor.client.request.setBody
class ClubTeamsApi(
private val client: AuthedHttpClient,
@@ -14,4 +21,30 @@ class ClubTeamsApi(
seasonId?.let { parameter("seasonid", it) }
}.body()
}
suspend fun listLeagues(clubId: Int, seasonId: Int? = null): List<ClubLeagueOptionDto> {
return client.http.get("/api/club-teams/leagues/$clubId") {
seasonId?.let { parameter("seasonid", it) }
}.body()
}
suspend fun getClubTeam(clubTeamId: Int): ClubTeamDto {
return client.http.get("/api/club-teams/$clubTeamId").body()
}
suspend fun createClubTeam(clubId: Int, body: ClubTeamCreateBody): ClubTeamDto {
return client.http.post("/api/club-teams/club/$clubId") {
setBody(body)
}.body()
}
suspend fun updateClubTeam(clubTeamId: Int, body: ClubTeamUpdateBody): ClubTeamDto {
return client.http.put("/api/club-teams/$clubTeamId") {
setBody(body)
}.body()
}
suspend fun deleteClubTeam(clubTeamId: Int) {
client.http.delete("/api/club-teams/$clubTeamId")
}
}

View File

@@ -2,9 +2,27 @@ package de.tt_tagebuch.shared.api
import de.tt_tagebuch.shared.api.http.AuthedHttpClient
import de.tt_tagebuch.shared.api.models.OfficialParticipationBucketDto
import de.tt_tagebuch.shared.api.models.OfficialParsedTournamentEnvelopeDto
import de.tt_tagebuch.shared.api.models.OfficialPatchTournamentBody
import de.tt_tagebuch.shared.api.models.OfficialParticipantStatusBody
import de.tt_tagebuch.shared.api.models.OfficialParticipantStatusResponseDto
import de.tt_tagebuch.shared.api.models.OfficialTournamentListRowDto
import de.tt_tagebuch.shared.api.models.OfficialTournamentUploadResultDto
import de.tt_tagebuch.shared.api.models.OfficialUpsertParticipationBody
import de.tt_tagebuch.shared.api.models.OfficialUpsertParticipationResponseDto
import io.ktor.client.call.body
import io.ktor.client.request.delete
import io.ktor.client.request.forms.MultiPartFormDataContent
import io.ktor.client.request.forms.formData
import io.ktor.client.request.get
import io.ktor.client.request.patch
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.Headers
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import kotlinx.serialization.json.JsonElement
class OfficialTournamentsApi(
private val client: AuthedHttpClient,
@@ -16,4 +34,65 @@ class OfficialTournamentsApi(
suspend fun listParticipationSummary(clubId: Int): List<OfficialParticipationBucketDto> {
return client.http.get("/api/official-tournaments/$clubId/participations/summary").body()
}
suspend fun uploadPdf(clubId: Int, pdfBytes: ByteArray, fileName: String = "turnier.pdf"): OfficialTournamentUploadResultDto {
return client.http.post("/api/official-tournaments/$clubId/upload") {
contentType(ContentType.MultiPart.FormData)
setBody(
MultiPartFormDataContent(
formData {
append(
"pdf",
pdfBytes,
Headers.build {
append(HttpHeaders.ContentType, "application/pdf")
append(
HttpHeaders.ContentDisposition,
"filename=\"${fileName.replace("\"", "")}\"",
)
},
)
},
),
)
}.body()
}
suspend fun getParsed(clubId: Int, tournamentId: Int): OfficialParsedTournamentEnvelopeDto {
return client.http.get("/api/official-tournaments/$clubId/$tournamentId").body()
}
suspend fun patchTournament(clubId: Int, tournamentId: Int, body: OfficialPatchTournamentBody): JsonElement {
return client.http.patch("/api/official-tournaments/$clubId/$tournamentId") {
setBody(body)
}.body()
}
suspend fun deleteTournament(clubId: Int, tournamentId: Int) {
client.http.delete("/api/official-tournaments/$clubId/$tournamentId")
}
suspend fun upsertParticipation(
clubId: Int,
tournamentId: Int,
body: OfficialUpsertParticipationBody,
): OfficialUpsertParticipationResponseDto {
return client.http.post("/api/official-tournaments/$clubId/$tournamentId/participation") {
setBody(body)
}.body()
}
suspend fun updateParticipantStatus(
clubId: Int,
tournamentId: Int,
body: OfficialParticipantStatusBody,
): OfficialParticipantStatusResponseDto {
return client.http.post("/api/official-tournaments/$clubId/$tournamentId/status") {
setBody(body)
}.body()
}
suspend fun autoRegister(clubId: Int, tournamentId: Int): JsonElement {
return client.http.post("/api/official-tournaments/$clubId/$tournamentId/auto-register").body()
}
}

View File

@@ -0,0 +1,18 @@
package de.tt_tagebuch.shared.api
import de.tt_tagebuch.shared.api.http.AuthedHttpClient
import de.tt_tagebuch.shared.api.models.SeasonDto
import io.ktor.client.call.body
import io.ktor.client.request.get
class SeasonsApi(
private val client: AuthedHttpClient,
) {
suspend fun listSeasons(): List<SeasonDto> {
return client.http.get("/api/seasons").body()
}
suspend fun getCurrentSeason(): SeasonDto {
return client.http.get("/api/seasons/current").body()
}
}

View File

@@ -1,12 +1,57 @@
package de.tt_tagebuch.shared.api
import de.tt_tagebuch.shared.api.http.AuthedHttpClient
import de.tt_tagebuch.shared.api.models.AddExternalTournamentParticipantBody
import de.tt_tagebuch.shared.api.models.AddMiniChampionshipBody
import de.tt_tagebuch.shared.api.models.AddStandardTournamentBody
import de.tt_tagebuch.shared.api.models.AddTournamentClassBody
import de.tt_tagebuch.shared.api.models.AssignParticipantToGroupBody
import de.tt_tagebuch.shared.api.models.CreateTournamentPairingBody
import de.tt_tagebuch.shared.api.models.GaveUpFlagBody
import de.tt_tagebuch.shared.api.models.InternalTournamentDetailDto
import de.tt_tagebuch.shared.api.models.InternalTournamentStatsDto
import de.tt_tagebuch.shared.api.models.InternalTournamentSummaryDto
import de.tt_tagebuch.shared.api.models.MergeTournamentPoolBody
import de.tt_tagebuch.shared.api.models.RemoveExternalTournamentParticipantBody
import de.tt_tagebuch.shared.api.models.ResetTournamentPoolBody
import de.tt_tagebuch.shared.api.models.SeededFlagBody
import de.tt_tagebuch.shared.api.models.SetTournamentModusBody
import de.tt_tagebuch.shared.api.models.TournamentAddInternalParticipantBody
import de.tt_tagebuch.shared.api.models.TournamentAddMatchResultBody
import de.tt_tagebuch.shared.api.models.TournamentAdvanceStageBody
import de.tt_tagebuch.shared.api.models.TournamentClassDto
import de.tt_tagebuch.shared.api.models.TournamentCleanupOrphanedBody
import de.tt_tagebuch.shared.api.models.TournamentClubTournamentBody
import de.tt_tagebuch.shared.api.models.TournamentCreateGroupMatchesBody
import de.tt_tagebuch.shared.api.models.TournamentCreateGroupsBody
import de.tt_tagebuch.shared.api.models.TournamentCreateGroupsPerClassBody
import de.tt_tagebuch.shared.api.models.TournamentDeleteKnockoutBody
import de.tt_tagebuch.shared.api.models.TournamentDeleteMatchResultBody
import de.tt_tagebuch.shared.api.models.TournamentExternalParticipantRowDto
import de.tt_tagebuch.shared.api.models.TournamentFinishMatchBody
import de.tt_tagebuch.shared.api.models.TournamentGetExternalParticipantsBody
import de.tt_tagebuch.shared.api.models.TournamentGetParticipantsBody
import de.tt_tagebuch.shared.api.models.TournamentManualAssignGroupsBody
import de.tt_tagebuch.shared.api.models.TournamentMatchActiveBody
import de.tt_tagebuch.shared.api.models.TournamentMatchDto
import de.tt_tagebuch.shared.api.models.TournamentMatchTableBody
import de.tt_tagebuch.shared.api.models.TournamentParticipantRowDto
import de.tt_tagebuch.shared.api.models.TournamentRemoveInternalParticipantBody
import de.tt_tagebuch.shared.api.models.TournamentReopenMatchBody
import de.tt_tagebuch.shared.api.models.TournamentStartKnockoutBody
import de.tt_tagebuch.shared.api.models.TournamentUpsertStagesBody
import de.tt_tagebuch.shared.api.models.UpdateParticipantClassBody
import de.tt_tagebuch.shared.api.models.UpdateTournamentClassBody
import de.tt_tagebuch.shared.api.models.UpdateTournamentMetaBody
import de.tt_tagebuch.shared.api.models.UpdateTournamentPairingBody
import io.ktor.client.call.body
import io.ktor.client.request.delete
import io.ktor.client.request.get
import io.ktor.client.request.parameter
import io.ktor.client.request.post
import io.ktor.client.request.put
import io.ktor.client.request.setBody
import kotlinx.serialization.json.JsonElement
class TournamentsApi(
private val client: AuthedHttpClient,
@@ -32,4 +77,303 @@ class TournamentsApi(
ageClassKeys?.let { parameter("ageClassKeys", it) }
}.body()
}
suspend fun addStandardTournament(body: AddStandardTournamentBody): InternalTournamentDetailDto {
return client.http.post("/api/tournament") {
setBody(body)
}.body()
}
suspend fun addMiniChampionship(body: AddMiniChampionshipBody): InternalTournamentDetailDto {
return client.http.post("/api/tournament/mini") {
setBody(body)
}.body()
}
suspend fun updateTournament(clubId: Int, tournamentId: Int, body: UpdateTournamentMetaBody): InternalTournamentDetailDto {
return client.http.put("/api/tournament/$clubId/$tournamentId") {
setBody(body)
}.body()
}
suspend fun setModus(body: SetTournamentModusBody) {
client.http.post("/api/tournament/modus") {
setBody(body)
}
}
suspend fun createEmptyGroups(body: TournamentCreateGroupsBody) {
client.http.put("/api/tournament/groups") {
setBody(body)
}
}
suspend fun createGroupsPerClass(body: TournamentCreateGroupsPerClassBody) {
client.http.post("/api/tournament/groups/create") {
setBody(body)
}
}
suspend fun fillGroups(body: TournamentClubTournamentBody): List<TournamentParticipantRowDto> {
return client.http.post("/api/tournament/groups") {
setBody(body)
}.body()
}
suspend fun createGroupMatches(body: TournamentCreateGroupMatchesBody) {
client.http.post("/api/tournament/matches/create") {
setBody(body)
}
}
suspend fun resetGroups(body: TournamentClubTournamentBody) {
client.http.post("/api/tournament/groups/reset") {
setBody(body)
}
}
suspend fun resetMatches(body: TournamentClubTournamentBody) {
client.http.post("/api/tournament/matches/reset") {
setBody(body)
}
}
suspend fun cleanupOrphanedMatches(body: TournamentCleanupOrphanedBody) {
client.http.post("/api/tournament/matches/cleanup-orphaned") {
setBody(body)
}
}
suspend fun getGroups(clubId: Int, tournamentId: Int): JsonElement {
return client.http.get("/api/tournament/groups") {
parameter("clubId", clubId)
parameter("tournamentId", tournamentId)
}.body()
}
suspend fun manualAssignGroups(body: TournamentManualAssignGroupsBody): JsonElement {
return client.http.post("/api/tournament/groups/manual") {
setBody(body)
}.body()
}
suspend fun assignParticipantToGroup(body: AssignParticipantToGroupBody) {
client.http.put("/api/tournament/participant/group") {
setBody(body)
}
}
suspend fun mergeClassesIntoPool(body: MergeTournamentPoolBody) {
client.http.post("/api/tournament/pools/merge") {
setBody(body)
}
}
suspend fun resetPool(body: ResetTournamentPoolBody) {
client.http.post("/api/tournament/pools/reset") {
setBody(body)
}
}
suspend fun listTournamentClasses(clubId: Int, tournamentId: Int): List<TournamentClassDto> {
return client.http.get("/api/tournament/classes/$clubId/$tournamentId").body()
}
suspend fun addTournamentClass(clubId: Int, tournamentId: Int, body: AddTournamentClassBody): TournamentClassDto {
return client.http.post("/api/tournament/class/$clubId/$tournamentId") {
setBody(body)
}.body()
}
suspend fun updateTournamentClass(
clubId: Int,
tournamentId: Int,
classId: Int,
body: UpdateTournamentClassBody,
): TournamentClassDto {
return client.http.put("/api/tournament/class/$clubId/$tournamentId/$classId") {
setBody(body)
}.body()
}
suspend fun deleteTournamentClass(clubId: Int, tournamentId: Int, classId: Int) {
client.http.delete("/api/tournament/class/$clubId/$tournamentId/$classId")
}
suspend fun listInternalParticipants(body: TournamentGetParticipantsBody): List<TournamentParticipantRowDto> {
return client.http.post("/api/tournament/participants") {
setBody(body)
}.body()
}
suspend fun addInternalParticipant(body: TournamentAddInternalParticipantBody): List<TournamentParticipantRowDto> {
return client.http.post("/api/tournament/participant") {
setBody(body)
}.body()
}
suspend fun removeInternalParticipant(body: TournamentRemoveInternalParticipantBody) {
client.http.delete("/api/tournament/participant") {
setBody(body)
}
}
suspend fun updateParticipantClass(
clubId: Int,
tournamentId: Int,
participantId: Int,
body: UpdateParticipantClassBody,
) {
client.http.put("/api/tournament/participant/$clubId/$tournamentId/$participantId/class") {
setBody(body)
}
}
suspend fun updateParticipantSeeded(clubId: Int, tournamentId: Int, participantId: Int, body: SeededFlagBody) {
client.http.put("/api/tournament/participant/$clubId/$tournamentId/$participantId/seeded") {
setBody(body)
}
}
suspend fun setParticipantGaveUp(clubId: Int, tournamentId: Int, participantId: Int, body: GaveUpFlagBody) {
client.http.put("/api/tournament/participant/$clubId/$tournamentId/$participantId/gave-up") {
setBody(body)
}
}
suspend fun listExternalParticipants(body: TournamentGetExternalParticipantsBody): List<TournamentExternalParticipantRowDto> {
return client.http.post("/api/tournament/external-participants") {
setBody(body)
}.body()
}
suspend fun addExternalParticipant(body: AddExternalTournamentParticipantBody) {
client.http.post("/api/tournament/external-participant") {
setBody(body)
}
}
suspend fun removeExternalParticipant(body: RemoveExternalTournamentParticipantBody) {
client.http.delete("/api/tournament/external-participant") {
setBody(body)
}
}
suspend fun updateExternalParticipantSeeded(
clubId: Int,
tournamentId: Int,
participantId: Int,
body: SeededFlagBody,
) {
client.http.put("/api/tournament/external-participant/$clubId/$tournamentId/$participantId/seeded") {
setBody(body)
}
}
suspend fun setExternalParticipantGaveUp(
clubId: Int,
tournamentId: Int,
participantId: Int,
body: GaveUpFlagBody,
) {
client.http.put("/api/tournament/external-participant/$clubId/$tournamentId/$participantId/gave-up") {
setBody(body)
}
}
suspend fun listMatches(clubId: Int, tournamentId: Int): List<TournamentMatchDto> {
return client.http.get("/api/tournament/matches/$clubId/$tournamentId").body()
}
suspend fun addMatchResult(body: TournamentAddMatchResultBody) {
client.http.post("/api/tournament/match/result") {
setBody(body)
}
}
suspend fun deleteMatchResult(body: TournamentDeleteMatchResultBody) {
client.http.delete("/api/tournament/match/result") {
setBody(body)
}
}
suspend fun finishMatch(body: TournamentFinishMatchBody) {
client.http.post("/api/tournament/match/finish") {
setBody(body)
}
}
suspend fun reopenMatch(body: TournamentReopenMatchBody) {
client.http.post("/api/tournament/match/reopen") {
setBody(body)
}
}
suspend fun setMatchActive(clubId: Int, tournamentId: Int, matchId: Int, body: TournamentMatchActiveBody) {
client.http.put("/api/tournament/match/$clubId/$tournamentId/$matchId/active") {
setBody(body)
}
}
suspend fun setMatchTable(clubId: Int, tournamentId: Int, matchId: Int, body: TournamentMatchTableBody) {
client.http.put("/api/tournament/match/$clubId/$tournamentId/$matchId/table") {
setBody(body)
}
}
suspend fun startKnockout(body: TournamentStartKnockoutBody) {
client.http.post("/api/tournament/knockout") {
setBody(body)
}
}
suspend fun deleteKnockoutMatches(body: TournamentDeleteKnockoutBody) {
client.http.delete("/api/tournament/matches/knockout") {
setBody(body)
}
}
suspend fun getStages(clubId: Int, tournamentId: Int): JsonElement {
return client.http.get("/api/tournament/stages") {
parameter("clubId", clubId)
parameter("tournamentId", tournamentId)
}.body()
}
suspend fun upsertStages(body: TournamentUpsertStagesBody): JsonElement {
return client.http.put("/api/tournament/stages") {
setBody(body)
}.body()
}
suspend fun advanceStage(body: TournamentAdvanceStageBody): JsonElement {
return client.http.post("/api/tournament/stages/advance") {
setBody(body)
}.body()
}
suspend fun listPairings(clubId: Int, tournamentId: Int, classId: Int): JsonElement {
return client.http.get("/api/tournament/pairings/$clubId/$tournamentId/$classId").body()
}
suspend fun createPairing(clubId: Int, tournamentId: Int, classId: Int, body: CreateTournamentPairingBody): JsonElement {
return client.http.post("/api/tournament/pairing/$clubId/$tournamentId/$classId") {
setBody(body)
}.body()
}
suspend fun updatePairing(
clubId: Int,
tournamentId: Int,
pairingId: Int,
body: UpdateTournamentPairingBody,
): JsonElement {
return client.http.put("/api/tournament/pairing/$clubId/$tournamentId/$pairingId") {
setBody(body)
}.body()
}
suspend fun deletePairing(clubId: Int, tournamentId: Int, pairingId: Int) {
client.http.delete("/api/tournament/pairing/$clubId/$tournamentId/$pairingId")
}
}

View File

@@ -0,0 +1,112 @@
package de.tt_tagebuch.shared.api.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
@Serializable
data class OfficialTournamentUploadResultDto(
val id: String,
)
@Serializable
data class OfficialPatchTournamentBody(
val title: String? = null,
)
@Serializable
data class OfficialUpsertParticipationBody(
val competitionId: Int,
val memberId: Int,
val wants: Boolean = false,
val registered: Boolean = false,
val participated: Boolean = false,
val placement: String? = null,
)
@Serializable
data class OfficialParticipantStatusBody(
val competitionId: Int,
val memberId: Int,
val action: String,
)
@Serializable
data class OfficialCompetitionMemberStateDto(
val id: Int? = null,
val tournamentId: Int? = null,
val competitionId: Int = 0,
val memberId: Int = 0,
val wants: Boolean = false,
val registered: Boolean = false,
val participated: Boolean = false,
val placement: String? = null,
)
@Serializable
data class OfficialParsedCompetitionDto(
val id: Int = 0,
val tournamentId: Int? = null,
val ageClassCompetition: String? = null,
val altersklasseWettbewerb: String? = null,
val performanceClass: String? = null,
val leistungsklasse: String? = null,
val startTime: String? = null,
val startzeit: String? = null,
val openTo: String? = null,
val offenFuer: String? = null,
val cutoffDate: String? = null,
val stichtag: String? = null,
val registrationDeadlineDate: String? = null,
val registrationDeadlineOnline: String? = null,
val meldeschlussDatum: String? = null,
val meldeschlussOnline: String? = null,
val preliminaryRound: String? = null,
val vorrunde: String? = null,
val finalRound: String? = null,
val endrunde: String? = null,
val entryFee: String? = null,
val startgeld: String? = null,
val ttrRelevant: String? = null,
val maxParticipants: Int? = null,
val maxTeilnehmer: Int? = null,
)
@Serializable
data class OfficialParsedDataDto(
val title: String? = null,
val termin: String? = null,
val austragungsorte: JsonElement? = null,
val konkurrenztypen: JsonElement? = null,
val meldeschluesse: JsonElement? = null,
val entryFees: JsonElement? = null,
val competitions: List<OfficialParsedCompetitionDto> = emptyList(),
)
@Serializable
data class OfficialParsedTournamentEnvelopeDto(
val id: String? = null,
val clubId: String? = null,
val parsedData: OfficialParsedDataDto? = null,
val participation: List<OfficialCompetitionMemberStateDto> = emptyList(),
)
@Serializable
data class OfficialUpsertParticipationResponseDto(
val success: Boolean = false,
val id: Int? = null,
)
@Serializable
data class OfficialParticipantStatusSnapshotDto(
val wants: Boolean = false,
val registered: Boolean = false,
val participated: Boolean = false,
val placement: String? = null,
)
@Serializable
data class OfficialParticipantStatusResponseDto(
val success: Boolean = false,
val id: Int? = null,
val status: OfficialParticipantStatusSnapshotDto? = null,
)

View File

@@ -14,9 +14,38 @@ data class ClubTeamLeagueDto(
@Serializable
data class ClubTeamSeasonDto(
val id: Int? = null,
val season: String = "",
)
/** Option aus `GET /api/club-teams/leagues/:clubId`. */
@Serializable
data class ClubLeagueOptionDto(
val id: Int,
val name: String = "",
val seasonId: Int? = null,
)
@Serializable
data class ClubTeamCreateBody(
val name: String,
val leagueId: Int? = null,
val seasonId: Int? = null,
val teamGender: String? = null,
val teamAgeGroup: String? = null,
val plannedLeagueName: String? = null,
)
@Serializable
data class ClubTeamUpdateBody(
val name: String? = null,
val leagueId: Int? = null,
val seasonId: Int? = null,
val teamGender: String? = null,
val teamAgeGroup: String? = null,
val plannedLeagueName: String? = null,
)
@Serializable
data class ClubTeamDto(
val id: Int,

View File

@@ -0,0 +1,9 @@
package de.tt_tagebuch.shared.api.models
import kotlinx.serialization.Serializable
@Serializable
data class SeasonDto(
val id: Int = 0,
val season: String = "",
)

View File

@@ -0,0 +1,381 @@
package de.tt_tagebuch.shared.api.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
// --- Standard CRUD / Stammdaten ---
@Serializable
data class AddStandardTournamentBody(
val clubId: Int,
val tournamentName: String,
val date: String,
val winningSets: Int? = null,
val allowsExternal: Boolean? = null,
val isDoublesTournament: Boolean? = false,
)
@Serializable
data class AddMiniChampionshipBody(
val clubId: Int,
val ort: String,
val date: String,
val year: Int,
val winningSets: Int? = null,
)
@Serializable
data class UpdateTournamentMetaBody(
val name: String? = null,
val date: String? = null,
val winningSets: Int? = null,
val numberOfTables: Int? = null,
val isDoublesTournament: Boolean? = null,
)
// --- Modus / Gruppen / Spiele ---
@Serializable
data class SetTournamentModusBody(
val clubId: Int,
val tournamentId: Int,
val type: String,
val numberOfGroups: Int? = null,
val advancingPerGroup: Int? = null,
)
@Serializable
data class TournamentClubTournamentBody(
val clubId: Int,
val tournamentId: Int,
)
@Serializable
data class TournamentCleanupOrphanedBody(
val clubId: Int,
val tournamentId: Int,
)
@Serializable
data class TournamentCreateGroupsBody(
val clubId: Int,
val tournamentId: Int,
val numberOfGroups: Int? = null,
)
@Serializable
data class TournamentCreateGroupMatchesBody(
val clubId: Int,
val tournamentId: Int,
val classId: Int? = null,
)
@Serializable
data class TournamentCreateGroupsPerClassBody(
val clubId: Int,
val tournamentId: Int,
val groupsPerClass: Map<String, Int> = emptyMap(),
)
@Serializable
data class ManualGroupAssignmentEntry(
val participantId: Int,
val groupNumber: Int,
)
@Serializable
data class TournamentManualAssignGroupsBody(
val clubId: Int,
val tournamentId: Int,
val assignments: List<ManualGroupAssignmentEntry> = emptyList(),
val numberOfGroups: Int? = null,
val maxGroupSize: Int? = null,
)
@Serializable
data class AssignParticipantToGroupBody(
val clubId: Int,
val tournamentId: Int,
val participantId: Int,
val groupNumber: Int,
val isExternal: Boolean = false,
)
@Serializable
data class MergeTournamentPoolBody(
val clubId: Int,
val tournamentId: Int,
val sourceClassId: Int,
val targetClassId: Int,
val strategy: String,
val outOfCompetitionForSource: Boolean = false,
)
@Serializable
data class ResetTournamentPoolBody(
val clubId: Int,
val tournamentId: Int,
val poolId: Int,
)
// --- Teilnehmer ---
@Serializable
data class TournamentGetParticipantsBody(
val clubId: Int,
val tournamentId: Int,
val classId: Int? = null,
)
@Serializable
data class TournamentAddInternalParticipantBody(
val clubId: Int,
val classId: Int? = null,
val participant: Int,
val tournamentId: Int? = null,
)
@Serializable
data class TournamentRemoveInternalParticipantBody(
val clubId: Int,
val tournamentId: Int,
val participantId: Int,
)
@Serializable
data class TournamentGetExternalParticipantsBody(
val clubId: Int,
val tournamentId: Int,
val classId: Int? = null,
)
@Serializable
data class AddExternalTournamentParticipantBody(
val clubId: Int,
val tournamentId: Int,
val classId: Int? = null,
val firstName: String,
val lastName: String,
val club: String? = null,
val birthDate: String? = null,
val gender: String? = null,
val email: String? = null,
val address: String? = null,
)
@Serializable
data class RemoveExternalTournamentParticipantBody(
val clubId: Int,
val tournamentId: Int,
val participantId: Int,
)
@Serializable
data class UpdateParticipantClassBody(
val classId: Int? = null,
val isExternal: Boolean? = false,
)
@Serializable
data class SeededFlagBody(val seeded: Boolean)
@Serializable
data class GaveUpFlagBody(val gaveUp: Boolean)
// --- Klassen ---
@Serializable
data class AddTournamentClassBody(
val name: String,
val isDoubles: Boolean? = false,
val gender: String? = null,
val minBirthYear: Int? = null,
val maxBirthYear: Int? = null,
)
@Serializable
data class UpdateTournamentClassBody(
val name: String? = null,
val sortOrder: Int? = null,
val isDoubles: Boolean? = null,
val gender: String? = null,
val minBirthYear: Int? = null,
val maxBirthYear: Int? = null,
)
@Serializable
data class TournamentClassDto(
val id: Int = 0,
val tournamentId: Int? = null,
val name: String = "",
val sortOrder: Int? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val isDoubles: Boolean? = null,
val gender: String? = null,
val minBirthYear: Int? = null,
val maxBirthYear: Int? = null,
)
// --- Teilnehmer-Zeilen (intern) ---
@Serializable
data class TournamentParticipantMemberSnippetDto(
val id: Int? = null,
val firstName: String? = null,
val lastName: String? = null,
val gender: String? = null,
)
@Serializable
data class TournamentParticipantRowDto(
val id: Int = 0,
val tournamentId: Int? = null,
val clubMemberId: Int? = null,
val classId: Int? = null,
val groupId: Int? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val seeded: Boolean? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val gaveUp: Boolean? = null,
val member: TournamentParticipantMemberSnippetDto? = null,
)
@Serializable
data class TournamentExternalParticipantRowDto(
val id: Int = 0,
val tournamentId: Int? = null,
val classId: Int? = null,
val firstName: String? = null,
val lastName: String? = null,
val club: String? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val seeded: Boolean? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val gaveUp: Boolean? = null,
)
// --- Matches ---
@Serializable
data class TournamentMatchSetResultDto(
val set: Int = 0,
val pointsPlayer1: Int? = null,
val pointsPlayer2: Int? = null,
)
@Serializable
data class TournamentMatchDto(
val id: Int = 0,
val tournamentId: Int? = null,
val groupId: Int? = null,
val classId: Int? = null,
val groupRound: Int? = null,
val round: String = "",
val player1Id: Int? = null,
val player2Id: Int? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val isFinished: Boolean? = null,
@Serializable(with = FlexibleNullableBooleanSerializer::class)
val isActive: Boolean? = null,
val result: String? = null,
val tableNumber: Int? = null,
val player1: JsonElement? = null,
val player2: JsonElement? = null,
val tournamentResults: List<TournamentMatchSetResultDto>? = null,
)
@Serializable
data class TournamentAddMatchResultBody(
val clubId: Int,
val tournamentId: Int,
val matchId: Int,
val set: Int,
val result: String,
)
@Serializable
data class TournamentFinishMatchBody(
val clubId: Int,
val tournamentId: Int,
val matchId: Int,
)
@Serializable
data class TournamentMatchActiveBody(
val isActive: Boolean,
)
@Serializable
data class TournamentMatchTableBody(
val tableNumber: Int? = null,
)
@Serializable
data class TournamentDeleteMatchResultBody(
val clubId: Int,
val tournamentId: Int,
val matchId: Int,
val set: Int,
)
@Serializable
data class TournamentReopenMatchBody(
val clubId: Int,
val tournamentId: Int,
val matchId: Int,
)
@Serializable
data class TournamentDeleteKnockoutBody(
val clubId: Int,
val tournamentId: Int,
val classId: Int? = null,
)
// --- KO ---
@Serializable
data class TournamentStartKnockoutBody(
val clubId: Int,
val tournamentId: Int,
)
// --- Paarungen ---
@Serializable
data class CreateTournamentPairingBody(
val player1Type: String,
val player1Id: Int,
val player2Type: String,
val player2Id: Int,
val seeded: Boolean? = false,
)
@Serializable
data class UpdateTournamentPairingBody(
val player1Type: String? = null,
val player1Id: Int? = null,
val player2Type: String? = null,
val player2Id: Int? = null,
val seeded: Boolean? = null,
val groupId: Int? = null,
)
// --- Stages ---
@Serializable
data class TournamentAdvanceStageBody(
val clubId: Int,
val tournamentId: Int,
val fromStageIndex: Int? = 1,
val toStageIndex: Int? = null,
)
@Serializable
data class TournamentUpsertStagesBody(
val clubId: Int,
val tournamentId: Int,
val stages: JsonElement? = null,
val advancement: JsonElement? = null,
val advancements: JsonElement? = null,
)