From 757f22cc67a1b5ae351f601655f07c1ba54ac5bb Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Fri, 17 Oct 2025 10:44:55 +0200 Subject: [PATCH] improve call team view --- PadelClub/Views/Calling/CallView.swift | 112 ++++++++++++------ .../Views/Calling/TeamsCallingView.swift | 57 ++++++--- 2 files changed, 112 insertions(+), 57 deletions(-) diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index dd25e95..8c4e84d 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -60,9 +60,10 @@ struct CallView: View { @State var showUserCreationView: Bool = false @State var summonParamByMessage: Bool = false - @State var summonParamReSummon: Bool = false + @State var summonParamReSummon: SummonType = .contact let simpleMode : Bool + let summonType: SummonType init(teams: [TeamRegistration], callDate: Date, matchFormat: MatchFormat, roundLabel: String) { self.teams = teams @@ -71,6 +72,7 @@ struct CallView: View { self.roundLabel = roundLabel self.simpleMode = false self.displayContext = .footer + self.summonType = .contact } init(teams: [TeamRegistration]) { @@ -80,12 +82,14 @@ struct CallView: View { self.roundLabel = "" self.simpleMode = true self.displayContext = .footer + self.summonType = .contact } - init(team: TeamRegistration, displayContext: SummoningDisplayContext) { + init(team: TeamRegistration, displayContext: SummoningDisplayContext, summonType: SummonType) { self.teams = [team] let expectedSummonDate = team.expectedSummonDate() self.displayContext = displayContext + self.summonType = summonType if let expectedSummonDate, let initialMatch = team.initialMatch() { self.callDate = expectedSummonDate @@ -97,6 +101,11 @@ struct CallView: View { self.matchFormat = initialGroupStage.matchFormat self.roundLabel = "poule" self.simpleMode = false + } else if let expectedSummonDate { + self.callDate = expectedSummonDate + self.matchFormat = MatchFormat.nineGames + self.roundLabel = "" + self.simpleMode = false } else { self.callDate = Date() self.matchFormat = MatchFormat.nineGames @@ -126,7 +135,7 @@ struct CallView: View { if success { calledTeams.forEach { team in team.callDate = callDate - if reSummon { + if summonType.shouldConfirm() { team.confirmationDate = nil } } @@ -138,21 +147,21 @@ struct CallView: View { } } - func finalMessage(reSummon: Bool, forcedEmptyMessage: Bool) -> String { + func finalMessage(summonType: SummonType, forcedEmptyMessage: Bool) -> String { if simpleMode || forcedEmptyMessage { let signature = dataStore.user.getSummonsMessageSignature() ?? dataStore.user.defaultSignature(tournament) return "\n\n\n\n" + signature } - return ContactType.callingMessage(tournament: tournament, startDate: callDate, roundLabel: roundLabel, matchFormat: matchFormat, reSummon: reSummon) - } - - var reSummon: Bool { - if simpleMode { - return false - } - return self.teams.allSatisfy({ $0.called() }) + return ContactType.callingMessage(tournament: tournament, startDate: callDate, roundLabel: roundLabel, matchFormat: matchFormat, summonType: summonType) } +// +// var summonType: SummonType { +// if simpleMode { +// return .contact +// } +// return self.teams.allSatisfy({ $0.called() }) == true ? .summon : .summonWalkoutFollowUp +// } var mainWord: String { if simpleMode { @@ -263,7 +272,7 @@ struct CallView: View { LoginView(reason: LoginReason.loginRequiredForFeature) { _ in self.showUserCreationView = false self._summon(byMessage: self.summonParamByMessage, - reSummon: self.summonParamByMessage) + summonType: self.summonType) } } }) @@ -271,7 +280,7 @@ struct CallView: View { private func _footerStyleView() -> some View { HStack { - let callWord : String = (reSummon ? "Reconvoquer" : mainWord) + let callWord : String = (summonType.isRecall() ? "Reconvoquer" : mainWord) if self.teams.count == 1 { if simpleMode { Text("\(callWord) cette paire par") @@ -299,19 +308,24 @@ struct CallView: View { self._summonMenu(byMessage: true) self._summonMenu(byMessage: false) } label: { - let callWord : String = (reSummon ? "Reconvoquer" : mainWord) - if self.teams.count == 1 { - if simpleMode { - Text("\(callWord) cette paire") - } else { - if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { - Text("Reconvoquer \(self.callDate.localizedDate())") - } else { + VStack(alignment: .leading) { + let callWord : String = (summonType.isRecall() ? "Reconvoquer" : mainWord) + if self.teams.count == 1 { + if simpleMode { Text("\(callWord) cette paire") + } else { + if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame { + Text("Reconvoquer \(self.callDate.localizedDate())") + } else { + Text("\(callWord) cette paire") + } } + } else { + Text("\(callWord) ces \(self.teams.count) paires") + } + if let caption = summonType.caption() { + Text(caption).foregroundStyle(.secondary).font(.caption) } - } else { - Text("\(callWord) ces \(self.teams.count) paires") } } } @@ -319,20 +333,40 @@ struct CallView: View { @ViewBuilder private func _summonMenu(byMessage: Bool) -> some View { - if self.reSummon { + if displayContext == .menu { + Button { + switch summonType { + case .contact: + self._summon(byMessage: byMessage, summonType: .contact, forcedEmptyMessage: true) + case .summon: + self._summon(byMessage: byMessage, summonType: .summon) + case .summonWalkoutFollowUp: + self._summon(byMessage: byMessage, summonType: .summonWalkoutFollowUp) + case .summonErrorFollowUp: + self._summon(byMessage: byMessage, summonType: .summonErrorFollowUp) + } + } label: { + Text(byMessage ? "sms" : "mail") + .underline() + } + } else if summonType.isRecall() { Menu { Button(mainWord) { - self._summon(byMessage: byMessage, reSummon: false) + self._summon(byMessage: byMessage, summonType: simpleMode ? .contact : .summon) } - Button("Re-convoquer") { - self._summon(byMessage: byMessage, reSummon: true) + Button("Re-convoquer suite à des forfaits") { + self._summon(byMessage: byMessage, summonType: .summonWalkoutFollowUp) } - + + Button("Re-convoquer suite à une erreur") { + self._summon(byMessage: byMessage, summonType: .summonErrorFollowUp) + } + if simpleMode == false { Divider() Button("Contacter") { - self._summon(byMessage: byMessage, reSummon: false, forcedEmptyMessage: true) + self._summon(byMessage: byMessage, summonType: .contact, forcedEmptyMessage: true) } } @@ -342,19 +376,19 @@ struct CallView: View { } } else { FooterButtonView(byMessage ? "sms" : "mail") { - self._summon(byMessage: byMessage, reSummon: false) + self._summon(byMessage: byMessage, summonType: summonType) } } } - private func _summon(byMessage: Bool, reSummon: Bool, forcedEmptyMessage: Bool = false) { + private func _summon(byMessage: Bool, summonType: SummonType, forcedEmptyMessage: Bool = false) { self.summonParamByMessage = byMessage - self.summonParamReSummon = reSummon + self.summonParamReSummon = summonType self._verifyUser { if byMessage { - self._contactByMessage(reSummon: reSummon, forcedEmptyMessage: forcedEmptyMessage) + self._contactByMessage(summonType: summonType, forcedEmptyMessage: forcedEmptyMessage) } else { - self._contactByMail(reSummon: reSummon, forcedEmptyMessage: forcedEmptyMessage) + self._contactByMail(summonType: summonType, forcedEmptyMessage: forcedEmptyMessage) } } } @@ -376,18 +410,18 @@ struct CallView: View { // } // } - fileprivate func _contactByMessage(reSummon: Bool, forcedEmptyMessage: Bool) { + fileprivate func _contactByMessage(summonType: SummonType, forcedEmptyMessage: Bool) { self.contactType = .message(date: callDate, recipients: teams.flatMap { $0.getPhoneNumbers() }, - body: finalMessage(reSummon: reSummon, forcedEmptyMessage: forcedEmptyMessage), + body: finalMessage(summonType: summonType, forcedEmptyMessage: forcedEmptyMessage), tournamentBuild: nil) } - fileprivate func _contactByMail(reSummon: Bool, forcedEmptyMessage: Bool) { + fileprivate func _contactByMail(summonType: SummonType, forcedEmptyMessage: Bool) { self.contactType = .mail(date: callDate, recipients: tournament.umpireMail(), bccRecipients: teams.flatMap { $0.getMail() }, - body: finalMessage(reSummon: reSummon, forcedEmptyMessage: forcedEmptyMessage), + body: finalMessage(summonType: summonType, forcedEmptyMessage: forcedEmptyMessage), subject: tournament.mailSubject(), tournamentBuild: nil) } diff --git a/PadelClub/Views/Calling/TeamsCallingView.swift b/PadelClub/Views/Calling/TeamsCallingView.swift index b8987c4..1a42de7 100644 --- a/PadelClub/Views/Calling/TeamsCallingView.swift +++ b/PadelClub/Views/Calling/TeamsCallingView.swift @@ -129,21 +129,28 @@ struct CallMenuOptionsView: View { @Environment(Tournament.self) var tournament: Tournament let team: TeamRegistration let action: (() -> Void)? + @State private var callDate: Date + + init(team: TeamRegistration, action: (() -> Void)?) { + self.team = team + self.action = action + _callDate = .init(wrappedValue: team.expectedSummonDate() ?? team.tournamentObject()?.startDate ?? Date()) + } var confirmed: Binding { Binding { team.confirmed() } set: { _ in team.toggleSummonConfirmation() - do { - try self.tournament.tournamentStore?.teamRegistrations.addOrUpdate(instance: team) - } catch { - Logger.error(error) - } + _save() action?() } } + private func _save() { + self.tournament.tournamentStore?.teamRegistrations.addOrUpdate(instance: team) + } + var body: some View { List { Section { @@ -151,11 +158,33 @@ struct CallMenuOptionsView: View { Toggle(isOn: confirmed) { Text("Confirmation reçue") } + + DatePicker(selection: $callDate) { + if callDate != team.expectedSummonDate() { + HStack { + Button("Valider", systemImage: "checkmark.circle") { + team.callDate = callDate + _save() + } + .tint(.green) + Divider() + Button("Annuler", systemImage: "xmark.circle", role: .cancel) { + callDate = team.expectedSummonDate() ?? tournament.startDate + } + .tint(.logoRed) + } + .labelStyle(.iconOnly) + .buttonStyle(.borderedProminent) + } else { + Text("Heure de convocation") + } + } + if team.expectedSummonDate() != nil { - CallView(team: team, displayContext: .menu) + CallView(team: team, displayContext: .menu, summonType: .summon) + CallView(team: team, displayContext: .menu, summonType: .summonWalkoutFollowUp) + CallView(team: team, displayContext: .menu, summonType: .summonErrorFollowUp) } - } footer: { - CallView(teams: [team]) } Section { @@ -170,11 +199,7 @@ struct CallMenuOptionsView: View { Section { RowButtonView("Effacer la date de convocation", role: .destructive) { team.callDate = nil - do { - try self.tournament.tournamentStore?.teamRegistrations.addOrUpdate(instance: team) - } catch { - Logger.error(error) - } + _save() action?() dismiss() } @@ -183,11 +208,7 @@ struct CallMenuOptionsView: View { Section { RowButtonView("Indiquer comme convoquée", role: .destructive) { team.callDate = team.initialMatch()?.startDate ?? tournament.startDate - do { - try self.tournament.tournamentStore?.teamRegistrations.addOrUpdate(instance: team) - } catch { - Logger.error(error) - } + _save() action?() dismiss() }