diff --git a/PadelClub/Data/Match.swift b/PadelClub/Data/Match.swift index fad2046..9778728 100644 --- a/PadelClub/Data/Match.swift +++ b/PadelClub/Data/Match.swift @@ -344,7 +344,7 @@ class Match: ModelObject, Storable { func followingMatch() -> Match? { guard let nextRoundId = roundObject?.nextRound()?.id else { return nil } - return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == index / 2 }).first + return Store.main.filter(isIncluded: { $0.round == nextRoundId && $0.index == (index - 1) / 2 }).first } func getDuration() -> Int { @@ -478,16 +478,17 @@ class Match: ModelObject, Storable { _loserMatch()?.updateTeamScores() } - func resetTeamScores() { - let teamScores = teamScores + func resetTeamScores(outsideOf newTeamScores: [TeamScore]) { + let ids = newTeamScores.map { $0.id } + let teamScores = teamScores.filter({ ids.contains($0.id) == false }) if teamScores.isEmpty == false { do { try DataStore.shared.teamScores.delete(contentOfs: teamScores) } catch { Logger.error(error) } - followingMatch()?.resetTeamScores() - _loserMatch()?.resetTeamScores() + followingMatch()?.resetTeamScores(outsideOf: []) + _loserMatch()?.resetTeamScores(outsideOf: []) } } @@ -498,14 +499,21 @@ class Match: ModelObject, Storable { return teams } + func getOrCreateTeamScores() -> [TeamScore] { + let teamOne = team(.one) + let teamTwo = team(.two) + let teams = [teamOne, teamTwo].compactMap({ $0 }).map { teamScore(ofTeam: $0) ?? TeamScore(match: id, team: $0) } + return teams + } + func updateTeamScores() { - resetTeamScores() - let teams = createTeamScores() + let teams = getOrCreateTeamScores() do { try DataStore.shared.teamScores.addOrUpdate(contentOfs: teams) } catch { Logger.error(error) } + resetTeamScores(outsideOf: teams) if teams.isEmpty == false { updateFollowingMatchTeamScore() } diff --git a/PadelClub/Data/TeamScore.swift b/PadelClub/Data/TeamScore.swift index ed2217d..b224197 100644 --- a/PadelClub/Data/TeamScore.swift +++ b/PadelClub/Data/TeamScore.swift @@ -35,7 +35,7 @@ class TeamScore: ModelObject, Storable { self.match = match if let team { self.teamRegistration = team.id - self.playerRegistrations = team.players().map { $0.id } + //self.playerRegistrations = team.players().map { $0.id } } self.score = nil self.walkOut = nil diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index aa1acfc..a02c79c 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1317,7 +1317,7 @@ class Tournament : ModelObject, Storable { func resetTeamScores(in matchOfBracketPosition: Int?) { guard let match = match(for: matchOfBracketPosition) else { return } - match.resetTeamScores() + match.resetTeamScores(outsideOf: []) } func updateTeamScores(in matchOfBracketPosition: Int?) { diff --git a/PadelClub/Utils/FileImportManager.swift b/PadelClub/Utils/FileImportManager.swift index 9e5c057..2d0a80d 100644 --- a/PadelClub/Utils/FileImportManager.swift +++ b/PadelClub/Utils/FileImportManager.swift @@ -8,6 +8,17 @@ import Foundation import LeStorage +enum FileImportManagerError: LocalizedError { + case unknownFormat + + var errorDescription: String? { + switch self { + case .unknownFormat: + return "Format non reconnu" + } + } +} + class FileImportManager { static let shared = FileImportManager() @@ -138,11 +149,11 @@ class FileImportManager { static let FFT_ASSIMILATION_WOMAN_IN_MAN = "A calculer selon la pondération en vigueur" - func createTeams(from fileContent: String, tournament: Tournament, fileProvider: FileProvider = .frenchFederation) async -> [TeamHolder] { + func createTeams(from fileContent: String, tournament: Tournament, fileProvider: FileProvider = .frenchFederation) async throws -> [TeamHolder] { switch fileProvider { case .frenchFederation: - return await _getFederalTeams(from: fileContent, tournament: tournament) + return try await _getFederalTeams(from: fileContent, tournament: tournament) case .padelClub: return await _getPadelClubTeams(from: fileContent, tournament: tournament) case .unknown: @@ -192,7 +203,7 @@ class FileImportManager { } } - private func _getFederalTeams(from fileContent: String, tournament: Tournament) async -> [TeamHolder] { + private func _getFederalTeams(from fileContent: String, tournament: Tournament) async throws -> [TeamHolder] { let lines = fileContent.components(separatedBy: "\n") guard let firstLine = lines.first else { return [] } var separator = "," @@ -200,6 +211,11 @@ class FileImportManager { separator = ";" } let headerCount = firstLine.components(separatedBy: separator).count + + guard headerCount > 12 else { + throw FileImportManagerError.unknownFormat + } + var results: [TeamHolder] = [] if headerCount <= 18 { Array(lines.dropFirst()).chunked(into: 2).forEach { teamLines in diff --git a/PadelClub/Views/Calling/Components/MenuWarningView.swift b/PadelClub/Views/Calling/Components/MenuWarningView.swift index 696eaff..6668980 100644 --- a/PadelClub/Views/Calling/Components/MenuWarningView.swift +++ b/PadelClub/Views/Calling/Components/MenuWarningView.swift @@ -26,6 +26,19 @@ struct MenuWarningView: View { // TODO: Guard @ViewBuilder private func _actionView(players: [PlayerRegistration], privateMode: Bool = false) -> some View { + Menu { + ForEach(players) { player in + if let number = player.phoneNumber?.replacingOccurrences(of: " ", with: ""), let url = URL(string: "tel:\(number)") { + Link(destination: url) { + Text(player.playerLabel(.short)) + Label(number, systemImage: "phone") + } + } + } + } label: { + Label("Appeler un joueur", systemImage: "phone") + } + Button("Message") { contactType = .message(date: date, recipients: players.compactMap({ $0.phoneNumber }), body: message, tournamentBuild: nil) } diff --git a/PadelClub/Views/Player/Components/EditablePlayerView.swift b/PadelClub/Views/Player/Components/EditablePlayerView.swift index 55b0b17..b6f7ccd 100644 --- a/PadelClub/Views/Player/Components/EditablePlayerView.swift +++ b/PadelClub/Views/Player/Components/EditablePlayerView.swift @@ -86,14 +86,22 @@ struct EditablePlayerView: View { if let number = player.phoneNumber?.replacingOccurrences(of: " ", with: ""), let url = URL(string: "tel:\(number)") { Link(destination: url) { Label("Appeler", systemImage: "phone") + Text(number) } } if let number = player.phoneNumber?.replacingOccurrences(of: " ", with: ""), let url = URL(string: "sms:\(number)") { Link(destination: url) { Label("SMS", systemImage: "message") + Text(number) } } - + if let mail = player.email, let url = URL(string: "mailto:\(mail)") { + Link(destination: url) { + Label("SMS", systemImage: "message") + Text(mail) + } + } + if editingOptions.contains(.name) { Divider() Button("Modifier le prénom") { diff --git a/PadelClub/Views/Tournament/FileImportView.swift b/PadelClub/Views/Tournament/FileImportView.swift index a24e7a4..530384f 100644 --- a/PadelClub/Views/Tournament/FileImportView.swift +++ b/PadelClub/Views/Tournament/FileImportView.swift @@ -53,7 +53,11 @@ struct FileImportView: View { RowButtonView("Démarrer l'importation") { if let fileContent { - await _startImport(fileContent: fileContent) + do { + try await _startImport(fileContent: fileContent) + } catch { + errorMessage = error.localizedDescription + } } } .disabled(fileContent == nil || convertingFile) @@ -249,7 +253,7 @@ struct FileImportView: View { } } - func _startImport(fileContent: String) async { + func _startImport(fileContent: String) async throws { await MainActor.run { errorMessage = nil teams.removeAll() @@ -258,7 +262,7 @@ struct FileImportView: View { await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: rankSourceDate) } - self.teams = await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider) + self.teams = try await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider) await MainActor.run { didImport = true }