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.
229 lines
7.6 KiB
229 lines
7.6 KiB
//
|
|
// EventStatusView.swift
|
|
// PadelClub
|
|
//
|
|
// Created by Razmig Sarkissian on 04/06/2025.
|
|
//
|
|
|
|
import SwiftUI
|
|
import PadelClubData
|
|
import LeStorage
|
|
|
|
struct EventStatusView: View {
|
|
@State private var teamsCount: Int?
|
|
@State private var includeWaitingList: Bool = false
|
|
@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 tournaments: [Tournament]
|
|
|
|
var event: Event?
|
|
|
|
init(tournament: Tournament) {
|
|
self.tournaments = [tournament]
|
|
}
|
|
|
|
init(event: Event) {
|
|
self.event = event
|
|
self.tournaments = event.confirmedTournaments()
|
|
}
|
|
|
|
init(tournaments: [Tournament]) {
|
|
self.tournaments = tournaments
|
|
}
|
|
|
|
func defaultCurrency() -> String {
|
|
tournaments.first?.currencyCode ?? Locale.defaultCurrency()
|
|
}
|
|
|
|
private func _calculateTeamsCount() async {
|
|
Task {
|
|
self.teamsCount = tournaments.map({ $0.selectedSortedTeams().count }).reduce(0, +)
|
|
}
|
|
}
|
|
|
|
private func _valueView<T: Numeric & CustomStringConvertible>(value: T, value2: T? = nil) -> some View {
|
|
if let value2 {
|
|
Text("\(value.description)/\(value2.description)")
|
|
.font(.title3)
|
|
} else {
|
|
Text("\(value.description)")
|
|
.font(.title3)
|
|
}
|
|
}
|
|
|
|
private func _currencyView(value: Double, value2: Double? = nil) -> some View {
|
|
|
|
let maps = [value, value2].compactMap({ $0 }).map {
|
|
$0.formatted(.currency(code: defaultCurrency()).precision(.fractionLength(0)))
|
|
}
|
|
|
|
let string = maps.joined(separator: " / ")
|
|
return Text(string)
|
|
}
|
|
|
|
|
|
var body: some View {
|
|
List {
|
|
Section {
|
|
LabeledContent {
|
|
_valueView(value: tournaments.count)
|
|
} label: {
|
|
Text("Tournois")
|
|
}
|
|
|
|
LabeledContent {
|
|
if let teamsCount {
|
|
_valueView(value: teamsCount, value2: tournaments.map({ $0.teamCount }).reduce(0, +))
|
|
} else {
|
|
ProgressView()
|
|
}
|
|
} label: {
|
|
Text("Inscriptions")
|
|
}
|
|
|
|
LabeledContent {
|
|
_currencyView(value: tournaments.map({ $0.earnings() }).reduce(0, +), value2: tournaments.map({ $0.totalIncome() }).reduce(0, +))
|
|
} label: {
|
|
Text("Recettes")
|
|
}
|
|
} header: {
|
|
if let tournament = tournaments.first, tournaments.count == 1 {
|
|
Text(tournament.tournamentTitle())
|
|
} else {
|
|
Text("Statistiques globales")
|
|
}
|
|
}
|
|
|
|
if tournaments.count > 1 {
|
|
Section {
|
|
ForEach(tournaments) { tournament in
|
|
NavigationLink(destination: EventStatusView(tournament: tournament)) {
|
|
LabeledContent {
|
|
_valueView(value: tournament.selectedSortedTeams().count, value2: tournament.teamCount)
|
|
} label: {
|
|
Text(tournament.tournamentTitle())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if event != nil {
|
|
_contactAllButtonView()
|
|
}
|
|
}
|
|
.task {
|
|
await self._calculateTeamsCount()
|
|
}
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.alert("Un problème est survenu", isPresented: messageSentFailed) {
|
|
Button("OK") {
|
|
}
|
|
} 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:
|
|
if networkMonitor.connected == false {
|
|
self.contactType = nil
|
|
self.sentError = .messageNotSent
|
|
}
|
|
@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:
|
|
if networkMonitor.connected == false {
|
|
self.contactType = nil
|
|
self.sentError = .mailNotSent
|
|
}
|
|
@unknown default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.tint(.master)
|
|
}
|
|
}
|
|
|
|
private func _contactAllButtonView() -> some View {
|
|
Section {
|
|
Toggle("Inclure les équipes en liste d'attente", isOn: $includeWaitingList)
|
|
|
|
RowButtonView("Contacter toutes les équipes", systemImage: "paperplane") {
|
|
|
|
var teams = [TeamRegistration]()
|
|
|
|
if includeWaitingList {
|
|
teams = tournaments.flatMap { $0.allTeamsWithoutWalkOut() }
|
|
} else {
|
|
teams = tournaments.flatMap { $0.selectedSortedTeams() }
|
|
}
|
|
|
|
_contact(teams: teams)
|
|
}
|
|
} footer: {
|
|
Text("Permet de rédiger un mail à tous les équipes de tous les tournois.")
|
|
}
|
|
.disabled(StoreCenter.main.isAuthenticated == false)
|
|
}
|
|
|
|
func finalMessage() -> String? {
|
|
event?.eventLinksPasteData()
|
|
}
|
|
|
|
func subjectMessage() -> String? {
|
|
event?.eventTitle()
|
|
}
|
|
|
|
var messageSentFailed: Binding<Bool> {
|
|
Binding {
|
|
sentError != nil
|
|
} set: { newValue in
|
|
if newValue == false {
|
|
sentError = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func umpiresEmail() -> [String] {
|
|
let mails = tournaments.compactMap({
|
|
$0.umpireMail()
|
|
})
|
|
|
|
return mails.flatMap({ $0 })
|
|
}
|
|
|
|
fileprivate func _contact(teams: [TeamRegistration]) {
|
|
contactType = .mail(date: nil, recipients: umpiresEmail(), bccRecipients: teams.flatMap { $0.unsortedPlayers() }.compactMap { $0.email }, body: finalMessage(), subject: subjectMessage(), tournamentBuild: nil)
|
|
}
|
|
|
|
private var _networkErrorMessage: String {
|
|
ContactManagerError.getNetworkErrorMessage(sentError: sentError, networkMonitorConnected: networkMonitor.connected)
|
|
}
|
|
|
|
}
|
|
|