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/Cashier/Event/EventStatusView.swift

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)
}
}