// // SendToAllView.swift // PadelClub // // Created by Razmig Sarkissian on 28/04/2024. // import SwiftUI import LeStorage struct SendToAllView: View { @Environment(\.dismiss) var dismiss @EnvironmentObject var dataStore: DataStore @Environment(Tournament.self) var tournament: Tournament @EnvironmentObject var networkMonitor: NetworkMonitor @State private var contactType: ContactType? = nil @State private var contactMethod: Int = 1 @State private var contactRecipients: Set = Set() @State private var sentError: ContactManagerError? = nil let addLink: Bool @State var cannotPayForTournament: Bool = false @State private var pageLink: PageLink = .teams var messageSentFailed: Binding { Binding { sentError != nil } set: { newValue in if newValue == false { sentError = nil } } } // TODO: Guard 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) } 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) } } } if addLink { Section { let links : [PageLink] = [.teams, .summons, .groupStages, .matches, .rankings] Picker(selection: $pageLink) { ForEach(links) { pageLink in Text(pageLink.localizedLabel()) } } label: { Text("Choisir une page du tournoi en particulier") } .pickerStyle(.menu) } } Section { RowButtonView("Contacter \(_totalString())") { self._contactAndPay() } } } .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") { } } message: { let message = [networkMonitor.connected == false ? "L'appareil n'est pas connecté à internet." as String? : nil, sentError == .mailNotSent ? "Le mail est dans la boîte d'envoi de l'app Mail. Vérifiez son état dans l'app Mail avant d'essayer de le renvoyer." as String? : nil, (sentError == .messageFailed || sentError == .messageNotSent) ? "Le SMS n'a pas été envoyé" as String? : nil, sentError == .mailFailed ? "Le mail n'a pas été envoyé" as String? : nil].compacted().joined(separator: "\n") Text(message) } .sheet(item: $contactType) { contactType in Group { switch contactType { case .message(_, let recipients, let body, _): if !self.cannotPayForTournament { MessageComposeView(recipients: recipients, body: body) { result in switch result { case .cancelled: break case .failed: self.sentError = .messageFailed case .sent: if networkMonitor.connected == false { self.sentError = .messageNotSent } @unknown default: break } } } else { SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } case .mail(_, let recipients, let bccRecipients, let body, let subject, _): if !self.cannotPayForTournament { 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: if networkMonitor.connected == false { self.contactType = nil self.sentError = .mailNotSent } @unknown default: break } } } else { SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } } } .tint(.master) } } .onAppear { self.cannotPayForTournament = Guard.main.paymentForNewTournament() == nil } } func _teams() -> [TeamRegistration] { if _roundTeams().isEmpty && _groupStagesTeams().isEmpty { return tournament.selectedSortedTeams() } return _roundTeams() + _groupStagesTeams() } func _roundTeams() -> [TeamRegistration] { let rounds : [Round] = contactRecipients.compactMap { Store.main.findById($0) } return rounds.flatMap({ $0.teams() }) } func _groupStagesTeams() -> [TeamRegistration] { let groupStages : [GroupStage] = contactRecipients.compactMap { Store.main.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 } } fileprivate func _contactAndPay() { do { try tournament.payIfNecessary() self._contact() } catch { self.cannotPayForTournament = true } } func finalMessage() -> String { var message = [String?]() message.append("\n\n") if addLink { message.append(tournament.shareURL(pageLink)?.absoluteString) } let signature = dataStore.user.summonsMessageSignature ?? dataStore.user.defaultSignature() message.append(signature) return message.compactMap { $0 }.joined(separator: "\n\n") } fileprivate func _contact() { if contactMethod == 0 { contactType = .message(date: nil, recipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.phoneNumber }, body: finalMessage(), tournamentBuild: nil) } else { contactType = .mail(date: nil, recipients: tournament.umpireMail(), bccRecipients: _teams().flatMap { $0.unsortedPlayers() }.compactMap { $0.email }, body: finalMessage(), subject: tournament.tournamentTitle(), tournamentBuild: nil) } } } #Preview { SendToAllView(addLink: true) }