You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
14 KiB
342 lines
14 KiB
//
|
|
// SendToAllView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 28/04/2024.
|
|
//
|
|
|
|
import SwiftUI
|
|
import LeStorage
|
|
import PadelClubData
|
|
|
|
struct SendToAllView: View {
|
|
|
|
@Environment(\.dismiss) var dismiss
|
|
@EnvironmentObject var dataStore: DataStore
|
|
|
|
@EnvironmentObject var networkMonitor: NetworkMonitor
|
|
|
|
@State private var contactType: ContactType? = nil
|
|
@State private var contactMethod: Int = 1
|
|
@State private var contactRecipients: Set<String> = Set()
|
|
@State private var sentError: ContactManagerError? = nil
|
|
var event: Event?
|
|
var tournament: Tournament?
|
|
var addLink: Bool
|
|
|
|
// @State var cannotPayForTournament: Bool = false
|
|
@State private var pageLink: PageLink = .matches
|
|
@State private var includeWaitingList: Bool = false
|
|
@State private var onlyWaitingList: Bool = false
|
|
|
|
@State var showSubscriptionView: Bool = false
|
|
@State var showUserCreationView: Bool = false
|
|
|
|
@State var summonParamByMessage: Bool = false
|
|
@State var summonParamReSummon: Bool = false
|
|
|
|
init(event: Event) {
|
|
self.event = event
|
|
self.addLink = false
|
|
_contactRecipients = .init(wrappedValue: Set(event.confirmedTournaments().map(\.id)))
|
|
}
|
|
|
|
init(tournament: Tournament, addLink: Bool) {
|
|
self.tournament = tournament
|
|
self.addLink = addLink
|
|
}
|
|
|
|
var tournamentStore: TournamentStore? {
|
|
return self.tournament?.tournamentStore
|
|
}
|
|
|
|
var messageSentFailed: Binding<Bool> {
|
|
Binding {
|
|
sentError != nil
|
|
} set: { newValue in
|
|
if newValue == false {
|
|
sentError = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
List(selection: $contactRecipients) {
|
|
Section {
|
|
Picker(selection: $contactMethod) {
|
|
Text("Contacter par sms").tag(0)
|
|
Text("Contacter par mail").tag(1)
|
|
} label: {
|
|
Text("méthode")
|
|
}
|
|
.labelsHidden()
|
|
.pickerStyle(.inline)
|
|
}
|
|
if let event {
|
|
LabeledContent {
|
|
Text(event.selectedTeams().filter({ contactRecipients.isEmpty || contactRecipients.contains($0.tournament) }).count.formatted())
|
|
} label: {
|
|
Text("Participants")
|
|
}
|
|
|
|
let confirmedTournaments = event.confirmedTournaments()
|
|
ForEach(confirmedTournaments) { tournament in
|
|
TournamentCellView(tournament: tournament).tag(tournament.id)
|
|
}
|
|
} else if let tournament {
|
|
Section {
|
|
ForEach(tournament.groupStages()) { groupStage in
|
|
let teams = groupStage.teams()
|
|
if teams.isEmpty == false {
|
|
LabeledContent {
|
|
Text(teams.count.formatted() + " équipe" + teams.count.pluralSuffix)
|
|
} label: {
|
|
Text(groupStage.groupStageTitle())
|
|
}
|
|
.tag(groupStage.id)
|
|
}
|
|
}
|
|
ForEach(tournament.rounds()) { round in
|
|
let teams = round.teams()
|
|
if teams.isEmpty == false {
|
|
LabeledContent {
|
|
Text(teams.count.formatted() + " équipe" + teams.count.pluralSuffix)
|
|
} label: {
|
|
Text(round.roundTitle())
|
|
}
|
|
.tag(round.id)
|
|
}
|
|
}
|
|
|
|
Toggle("Inclure la liste d'attente", isOn: $includeWaitingList)
|
|
if includeWaitingList {
|
|
Toggle("Seulement la liste d'attente", isOn: $onlyWaitingList)
|
|
}
|
|
} footer: {
|
|
Text("Si vous ne souhaitez pas contacter toutes les équipes, choisissez un ou plusieurs groupes d'équipes manuellement.")
|
|
}
|
|
}
|
|
|
|
if addLink, event == nil {
|
|
Section {
|
|
let links : [PageLink] = [.teams, .summons, .groupStages, .matches, .rankings]
|
|
Picker(selection: $pageLink) {
|
|
ForEach(links) { pageLink in
|
|
Text(pageLink.localizedLabel()).tag(pageLink)
|
|
}
|
|
} label: {
|
|
Text("Lien à partager")
|
|
}
|
|
.pickerStyle(.menu)
|
|
}
|
|
}
|
|
|
|
Section {
|
|
RowButtonView("Contacter \(_totalString())") {
|
|
self._contact()
|
|
}
|
|
}
|
|
}
|
|
.onChange(of: includeWaitingList, {
|
|
if includeWaitingList == false {
|
|
onlyWaitingList = false
|
|
}
|
|
})
|
|
.toolbar {
|
|
ToolbarItem(placement: .topBarLeading) {
|
|
Button("Annuler", role: .cancel) {
|
|
dismiss()
|
|
}
|
|
|
|
}
|
|
}
|
|
.environment(\.editMode, Binding.constant(EditMode.active))
|
|
.headerProminence(.increased)
|
|
.navigationTitle("Préparation")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.alert("Un problème est survenu", isPresented: messageSentFailed) {
|
|
Button("OK") {
|
|
}
|
|
|
|
if case .uncalledTeams(let uncalledTeams) = sentError, let tournament {
|
|
NavigationLink("Voir les équipes non contactées") {
|
|
TeamsCallingView(teams: uncalledTeams)
|
|
.environment(tournament)
|
|
}
|
|
}
|
|
} message: {
|
|
Text(_networkErrorMessage)
|
|
}
|
|
.sheet(item: $contactType) { contactType in
|
|
Group {
|
|
switch contactType {
|
|
case .message(_, let recipients, let body, _):
|
|
MessageComposeView(recipients: recipients, body: body) { result in
|
|
switch result {
|
|
case .cancelled:
|
|
break
|
|
case .failed:
|
|
self.sentError = .messageFailed
|
|
case .sent:
|
|
let uncalledTeams = _teams().filter { $0.getPhoneNumbers().isEmpty }
|
|
|
|
if networkMonitor.connected == false {
|
|
self.contactType = nil
|
|
if uncalledTeams.isEmpty == false {
|
|
self.sentError = .uncalledTeams(uncalledTeams)
|
|
} else {
|
|
self.sentError = .messageNotSent
|
|
}
|
|
} else {
|
|
if uncalledTeams.isEmpty == false {
|
|
self.sentError = .uncalledTeams(uncalledTeams)
|
|
}
|
|
}
|
|
|
|
@unknown default:
|
|
break
|
|
}
|
|
}
|
|
case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
|
|
MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in
|
|
switch result {
|
|
case .cancelled, .saved:
|
|
self.contactType = nil
|
|
case .failed:
|
|
self.contactType = nil
|
|
self.sentError = .mailFailed
|
|
case .sent:
|
|
let uncalledTeams = _teams().filter { $0.getMail().isEmpty }
|
|
|
|
if networkMonitor.connected == false {
|
|
self.contactType = nil
|
|
if uncalledTeams.isEmpty == false {
|
|
self.sentError = .uncalledTeams(uncalledTeams)
|
|
} else {
|
|
self.sentError = .mailNotSent
|
|
}
|
|
} else {
|
|
if uncalledTeams.isEmpty == false {
|
|
self.sentError = .uncalledTeams(uncalledTeams)
|
|
}
|
|
}
|
|
@unknown default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.tint(.master)
|
|
}
|
|
.sheet(isPresented: self.$showSubscriptionView, content: {
|
|
NavigationStack {
|
|
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
|
|
.environment(\.colorScheme, .light)
|
|
}
|
|
})
|
|
.sheet(isPresented: self.$showUserCreationView, content: {
|
|
NavigationStack {
|
|
LoginView(reason: LoginReason.loginRequiredForFeature) { _ in
|
|
self.showUserCreationView = false
|
|
self._contact()
|
|
}
|
|
}
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
func _teams() -> [TeamRegistration] {
|
|
if let event {
|
|
return event.selectedTeams().filter({ contactRecipients.isEmpty || contactRecipients.contains($0.tournament) })
|
|
}
|
|
|
|
guard let tournament else { return [] }
|
|
let selectedSortedTeams = tournament.selectedSortedTeams()
|
|
if onlyWaitingList {
|
|
return tournament.waitingListSortedTeams(selectedSortedTeams: selectedSortedTeams)
|
|
}
|
|
if _roundTeams().isEmpty && _groupStagesTeams().isEmpty {
|
|
return tournament.selectedSortedTeams() + (includeWaitingList ? tournament.waitingListSortedTeams(selectedSortedTeams: selectedSortedTeams) : [])
|
|
}
|
|
return _roundTeams() + _groupStagesTeams() + (includeWaitingList ? tournament.waitingListSortedTeams(selectedSortedTeams: selectedSortedTeams) : [])
|
|
}
|
|
|
|
func _roundTeams() -> [TeamRegistration] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
let rounds: [Round] = contactRecipients.compactMap { tournamentStore.rounds.findById($0) }
|
|
return rounds.flatMap { $0.teams() }
|
|
}
|
|
|
|
func _groupStagesTeams() -> [TeamRegistration] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
let groupStages : [GroupStage] = contactRecipients.compactMap { tournamentStore.groupStages.findById($0) }
|
|
return groupStages.flatMap { $0.teams() }
|
|
}
|
|
|
|
func _totalString() -> String {
|
|
if contactRecipients.isEmpty {
|
|
return "toutes les équipes"
|
|
} else {
|
|
let teams = _teams()
|
|
return teams.count.formatted() + " équipe" + teams.count.pluralSuffix
|
|
}
|
|
}
|
|
|
|
func finalMessage() -> String {
|
|
var message = [String?]()
|
|
message.append("\n\n")
|
|
if let tournament, addLink, event == nil {
|
|
message.append(tournament.shareURL(pageLink)?.absoluteString)
|
|
} else if let event {
|
|
message.append(event.shareURL()?.absoluteString)
|
|
}
|
|
|
|
let signature = dataStore.user.getSummonsMessageSignature() ?? dataStore.user.defaultSignature(tournament)
|
|
|
|
message.append(signature)
|
|
|
|
return message.compactMap { $0 }.joined(separator: "\n\n")
|
|
}
|
|
|
|
fileprivate func _contact() {
|
|
|
|
self._verifyUser {
|
|
if contactMethod == 0 {
|
|
contactType = .message(date: nil, recipients: _teams().flatMap { $0.unsortedPlayers() }.flatMap { [$0.phoneNumber, $0.contactPhoneNumber] }.compactMap({ $0 }), body: finalMessage(), tournamentBuild: nil)
|
|
} else {
|
|
let umpireMail = tournament?.umpireMail() ?? event?.umpireMail()
|
|
let subject = tournament?.mailSubject() ?? event?.mailSubject()
|
|
contactType = .mail(date: nil, recipients: umpireMail, bccRecipients: _teams().flatMap { $0.unsortedPlayers() }.flatMap { [$0.email, $0.contactEmail] }.compactMap({ $0 }), body: finalMessage(), subject: subject, tournamentBuild: nil)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
fileprivate func _verifyUser(_ handler: () -> ()) {
|
|
if StoreCenter.main.userId != nil {
|
|
handler()
|
|
} else {
|
|
self.showUserCreationView = true
|
|
}
|
|
}
|
|
|
|
// fileprivate func _payTournamentAndExecute(_ handler: () -> ()) {
|
|
// do {
|
|
// try tournament.payIfNecessary()
|
|
// handler()
|
|
// } catch {
|
|
// self.showSubscriptionView = true
|
|
// }
|
|
// }
|
|
|
|
private var _networkErrorMessage: String {
|
|
ContactManagerError.getNetworkErrorMessage(sentError: sentError, networkMonitorConnected: networkMonitor.connected)
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// SendToAllView(addLink: true)
|
|
//}
|
|
|