add consolante handler

sync_v2
Raz 8 months ago
parent cbbf8b970b
commit f8c4c76c47
  1. 8
      PadelClub.xcodeproj/project.pbxproj
  2. 241
      PadelClub/Views/Tournament/ConsolationTournamentImportView.swift
  3. 17
      PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift

@ -893,6 +893,9 @@
FF967D0D2BAF3EB300A9A3BD /* MatchDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0C2BAF3EB200A9A3BD /* MatchDateView.swift */; };
FF967D0F2BAF63B000A9A3BD /* PlayerBlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF967D0E2BAF63B000A9A3BD /* PlayerBlockView.swift */; };
FF9AC3952BE3627B00C2E883 /* GroupStageTeamReplacementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9AC3942BE3627B00C2E883 /* GroupStageTeamReplacementView.swift */; };
FF9B442B2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9B442A2D950E48002448C8 /* ConsolationTournamentImportView.swift */; };
FF9B442C2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9B442A2D950E48002448C8 /* ConsolationTournamentImportView.swift */; };
FF9B442D2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF9B442A2D950E48002448C8 /* ConsolationTournamentImportView.swift */; };
FFA1B1292BB71773006CE248 /* PadelClubButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */; };
FFA252A92CDB70520074E63F /* PlayerStatisticView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252A82CDB70520074E63F /* PlayerStatisticView.swift */; };
FFA252AA2CDB70520074E63F /* PlayerStatisticView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA252A82CDB70520074E63F /* PlayerStatisticView.swift */; };
@ -1347,6 +1350,7 @@
FF967D0C2BAF3EB200A9A3BD /* MatchDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchDateView.swift; sourceTree = "<group>"; };
FF967D0E2BAF63B000A9A3BD /* PlayerBlockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerBlockView.swift; sourceTree = "<group>"; };
FF9AC3942BE3627B00C2E883 /* GroupStageTeamReplacementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupStageTeamReplacementView.swift; sourceTree = "<group>"; };
FF9B442A2D950E48002448C8 /* ConsolationTournamentImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsolationTournamentImportView.swift; sourceTree = "<group>"; };
FFA1B1282BB71773006CE248 /* PadelClubButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadelClubButtonView.swift; sourceTree = "<group>"; };
FFA252A82CDB70520074E63F /* PlayerStatisticView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStatisticView.swift; sourceTree = "<group>"; };
FFA252AC2CDB734A0074E63F /* UmpireStatisticView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UmpireStatisticView.swift; sourceTree = "<group>"; };
@ -1879,6 +1883,7 @@
FF967CF52BAED51600A9A3BD /* TournamentRunningView.swift */,
C4A47D882B7BBB5000ADC637 /* Subscription */,
FF089EBE2BB0B14600F0AEC7 /* FileImportView.swift */,
FF9B442A2D950E48002448C8 /* ConsolationTournamentImportView.swift */,
FF3F74F92B91A018004CFE0E /* Screen */,
FF3F74F82B919FB2004CFE0E /* Shared */,
);
@ -2715,6 +2720,7 @@
FF82CFC52B911F5B00B0CAF2 /* OrganizedTournamentView.swift in Sources */,
FFF964572BC26B3400EEF017 /* RoundScheduleEditorView.swift in Sources */,
FF59FFB32B90EFAC0061EFF9 /* EventListView.swift in Sources */,
FF9B442D2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */,
FF8F263D2BAD627A00650388 /* TournamentConfiguratorView.swift in Sources */,
FFC1E10C2BAC7FB0008D6F59 /* ClubImportView.swift in Sources */,
FF558C632C6CDD020071F9AE /* UnderlineView.swift in Sources */,
@ -2908,6 +2914,7 @@
FF4CBF4B2C996C0600151637 /* Patcher.swift in Sources */,
FF4CBF4C2C996C0600151637 /* FileImportView.swift in Sources */,
FF4CBF4D2C996C0600151637 /* StepperView.swift in Sources */,
FF9B442C2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */,
FF4CBF4E2C996C0600151637 /* RoundsView.swift in Sources */,
FF4CBF4F2C996C0600151637 /* FederalTournament.swift in Sources */,
FF4CBF502C996C0600151637 /* TournamentInitView.swift in Sources */,
@ -3201,6 +3208,7 @@
FF70FACA2C90584900129CC2 /* Patcher.swift in Sources */,
FF70FACB2C90584900129CC2 /* FileImportView.swift in Sources */,
FF70FACC2C90584900129CC2 /* StepperView.swift in Sources */,
FF9B442B2D950E48002448C8 /* ConsolationTournamentImportView.swift in Sources */,
FF70FACD2C90584900129CC2 /* RoundsView.swift in Sources */,
FF70FACE2C90584900129CC2 /* FederalTournament.swift in Sources */,
FF70FACF2C90584900129CC2 /* TournamentInitView.swift in Sources */,

@ -0,0 +1,241 @@
//
// ConsolationTournamentImportView.swift
// PadelClub
//
// Created by razmig on 27/03/2025.
//
import SwiftUI
import LeStorage
struct ConsolationTournamentImportView: View {
@EnvironmentObject var dataStore: DataStore
@Environment(Tournament.self) var tournament: Tournament
@Environment(\.dismiss) private var dismiss
@State private var selectedTournament: Tournament?
@State private var selectedImportSelector: ImportSelector = .groupStage
@State private var selectedImportType: ImportType = .losers
enum ImportType: Int, Identifiable, CaseIterable {
case losers
case winners
case all
func importTypeLocalizedLabel() -> String {
switch self {
case .losers:
return "Perdants"
case .winners:
return "Gagnants"
case .all:
return "Tous"
}
}
var id: Int {
self.rawValue
}
}
enum ImportSelector: Identifiable, Hashable {
case groupStage
case round(index: Int)
case all
func importSelectorLocalizedLabel() -> String {
switch self {
case .groupStage:
return "Poule"
case .round(let index):
return RoundRule.roundName(fromRoundIndex: index)
case .all:
return "Tous"
}
}
var id: String {
switch self {
case .groupStage, .all:
return String(describing: self)
case .round(let index):
return String(describing: index)
}
}
}
var importSelectors: [ImportSelector] {
guard let selectedTournament, selectedTournament.unsortedTeams().isEmpty == false else {
return []
}
var _imports = [ImportSelector]()
if selectedTournament.groupStages().isEmpty == false {
if selectedTournament.groupStageTeams().isEmpty == false {
_imports.append(.groupStage)
}
}
selectedTournament.rounds().forEach { round in
if round.teams().isEmpty == false {
_imports.append(.round(index: round.index))
}
}
_imports.append(.all)
return _imports
}
var tournaments: [Tournament] {
dataStore.tournaments.filter({ $0.isDeleted == false && $0.id != tournament.id }).sorted(by: \.startDate, order: .descending)
}
var body: some View {
List {
Picker(selection: $selectedTournament) {
Text("Aucun tournoi").tag(nil as Tournament?)
ForEach(tournaments) { tournament in
TournamentCellView(tournament: tournament).tag(tournament)
}
} label: {
if selectedTournament == nil {
Text("Choisir la source")
} else {
EmptyView()
}
}
.pickerStyle(.navigationLink)
let importSelectors = importSelectors
if let selectedTournament {
if importSelectors.isEmpty == false {
Section {
Picker(selection: $selectedImportSelector) {
ForEach(importSelectors) { importSelector in
Text(importSelector.importSelectorLocalizedLabel())
.tag(importSelector)
}
} label: {
Text("Équipes")
}
if selectedImportSelector != .all {
Picker(selection: $selectedImportType) {
ForEach(ImportType.allCases) { importType in
Text(importType.importTypeLocalizedLabel())
.tag(importType)
}
} label: {
Text("Type")
}
}
}
}
let unsortedTeams = tournament.unsortedTeams()
let onlineTeams = unsortedTeams.filter({ $0.hasRegisteredOnline() })
if unsortedTeams.count > 0 {
Section {
RowButtonView("Effacer les équipes actuelles", role: .destructive) {
await _deleteTeams(teams: unsortedTeams)
}
.disabled(onlineTeams.isEmpty == false)
} footer: {
if onlineTeams.isEmpty == false {
Text("Ce tournoi contient des inscriptions en ligne, vous ne pouvez pas effacer toute votre liste d'inscription d'un coup.")
}
}
}
let teams = _teamsToImport(selectedTournament: selectedTournament)
Section {
RowButtonView("Importer les équipes") {
await _importTeams(selectedTournament: selectedTournament, teams: teams)
dismiss()
}
.disabled(teams.isEmpty)
} footer: {
if teams.isEmpty {
Text("Aucune équipe détectée").foregroundStyle(.logoRed)
}
}
}
}
.onChange(of: selectedTournament) {
selectedImportSelector = importSelectors.first ?? .groupStage
selectedImportType = .losers
}
.navigationTitle("Importation")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
}
private func _teamsToImport(selectedTournament: Tournament) -> [TeamRegistration] {
var teams = [TeamRegistration]()
switch selectedImportSelector {
case .all:
teams = selectedTournament.unsortedTeams()
case .groupStage:
teams = selectedTournament.groupStageTeams().filter({
switch selectedImportType {
case .losers:
return $0.qualified == false
case .winners:
return $0.qualified
case .all:
return true
}
})
case .round(let index):
if let round = selectedTournament.rounds().filter({ $0.index == index }).first {
if selectedImportType == .all {
teams = round.teams()
} else {
teams = round.playedMatches().compactMap({ match in
if selectedImportType == .losers {
return match.loser()
} else if selectedImportType == .winners {
return match.winner()
} else {
return nil
}
})
}
}
}
return teams
}
private func _importTeams(selectedTournament: Tournament, teams: [TeamRegistration]) async {
let teamHolders = teams.map { team in
let players = team.players().map { player in
let playerCopy = PlayerRegistration(firstName: player.firstName, lastName: player.lastName, licenceId: player.licenceId, rank: player.rank, sex: player.sex, tournamentPlayed: player.tournamentPlayed, points: player.points, clubName: player.clubName, ligueName: player.ligueName, assimilation: player.assimilation, phoneNumber: player.phoneNumber, email: player.email, birthdate: player.birthdate, computedRank: player.computedRank, source: player.source, hasArrived: false)
return playerCopy
}
let teamHolder = FileImportManager.TeamHolder.init(players: players, tournamentCategory: tournament.category, tournamentAgeCategory: tournament.federalAgeCategory, previousTeam: tournament.findTeam(players), registrationDate: Date(), name: team.name, tournament: tournament)
return teamHolder
}
tournament.rankSourceDate = selectedTournament.rankSourceDate
dataStore.tournaments.addOrUpdate(instance: tournament)
tournament.importTeams(teamHolders)
}
private func _deleteTeams(teams: [TeamRegistration]) async {
await MainActor.run {
tournament.tournamentStore?.teamRegistrations.delete(contentOfs: teams)
}
}
}

@ -407,7 +407,7 @@ struct InscriptionManagerView: View {
}
Divider()
_sharingTeamsMenuView()
Button {
presentImportView = true
} label: {
@ -416,6 +416,10 @@ struct InscriptionManagerView: View {
Link(destination: URLs.beachPadel.url) {
Label("beach-padel.app.fft.fr", systemImage: "safari")
}
Divider()
_importTeamsMenuView()
_sharingTeamsMenuView()
} else {
_sharingTeamsMenuView()
@ -446,6 +450,8 @@ struct InscriptionManagerView: View {
Divider()
_importTeamsMenuView()
Button {
presentImportView = true
} label: {
@ -482,6 +488,15 @@ struct InscriptionManagerView: View {
}
}
private func _importTeamsMenuView() -> some View {
NavigationLink {
ConsolationTournamentImportView()
.environment(tournament)
} label: {
Label("Importer des paires", systemImage: "square.and.arrow.down")
}
}
var walkoutTeams: [TeamRegistration] {
tournament.walkoutTeams()
}

Loading…
Cancel
Save