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.
 
 
PadelClub/PadelClub/Views/Calling/SendToAllView.swift

229 lines
9.2 KiB

//
// 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<String> = Set()
@State private var sentError: ContactManagerError? = nil
let addLink: Bool
@State var cannotPayForTournament: Bool = false
@State private var pageLink: PageLink = .teams
var messageSentFailed: Binding<Bool> {
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)
//}