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/Team/EditingTeamView.swift

332 lines
12 KiB

//
// EditingTeamView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 17/04/2024.
//
import SwiftUI
import LeStorage
struct EditingTeamView: View {
@EnvironmentObject var dataStore: DataStore
@EnvironmentObject var networkMonitor: NetworkMonitor
@Environment(Tournament.self) var tournament: Tournament
@Environment(\.dismiss) private var dismiss
var team: TeamRegistration
@State private var editedTeam: TeamRegistration?
@State private var contactType: ContactType? = nil
@State private var sentError: ContactManagerError? = nil
@State private var showSubscriptionView: Bool = false
@State private var registrationDate : Date
@State private var callDate : Date
@State private var name: String
@FocusState private var focusedField: TeamRegistration.CodingKeys?
var messageSentFailed: Binding<Bool> {
Binding {
sentError != nil
} set: { newValue in
if newValue == false {
sentError = nil
}
}
}
var tournamentStore: TournamentStore {
return self.tournament.tournamentStore
}
init(team: TeamRegistration) {
self.team = team
_name = .init(wrappedValue: team.name ?? "")
_registrationDate = State(wrappedValue: team.registrationDate ?? Date())
_callDate = State(wrappedValue: team.callDate ?? Date())
}
var body: some View {
List {
Section {
RowButtonView("Modifier la composition de l'équipe") {
editedTeam = team
}
TeamDetailView(team: team)
} footer: {
HStack {
CopyPasteButtonView(pasteValue: team.playersPasteData())
Spacer()
NavigationLink {
GroupStageTeamReplacementView(team: team)
.environment(tournament)
} label: {
Text("Chercher à remplacer")
.underline()
}
}
}
Section {
DatePicker(selection: $registrationDate) {
Text("Inscription")
Text(registrationDate.localizedWeekDay().capitalized)
}
if let callDate = team.callDate {
LabeledContent() {
Text(callDate.localizedDate())
} label: {
Text("Convocation")
}
Toggle(isOn: confirmationReceived) {
Text("Confirmation reçue")
Text("L'équipe vous a confirmé votre convocation")
}
} else {
Text("Cette équipe n'a pas été convoquée")
}
if team.unsortedPlayers().isEmpty == false {
Toggle(isOn: hasArrived) {
Text("Équipe sur place")
}
}
Toggle(isOn: .init(get: {
return team.wildCardBracket
}, set: { value in
team.resetPositions()
team.wildCardGroupStage = false
team.walkOut = false
team.wildCardBracket = value
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
})) {
Text("Wildcard Tableau")
}
Toggle(isOn: .init(get: {
return team.wildCardGroupStage
}, set: { value in
team.resetPositions()
team.wildCardBracket = false
team.walkOut = false
team.wildCardGroupStage = value
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
})) {
Text("Wildcard Poule")
}
Toggle(isOn: .init(get: {
return team.walkOut
}, set: { value in
team.resetPositions()
team.wildCardBracket = false
team.wildCardGroupStage = false
team.walkOut = value
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
})) {
Text("Forfait")
}
}
Section {
TextField("Nom de l'équipe", text: $name)
.autocorrectionDisabled()
.focused($focusedField, equals: ._name)
.keyboardType(.alphabet)
.frame(maxWidth: .infinity)
.submitLabel(.done)
.onSubmit(of: .text) {
let trimmed = name.trimmedMultiline
if trimmed.isEmpty {
team.name = nil
} else {
team.name = trimmed
}
_save()
}
} header: {
Text("Nom de l'équipe")
}
Section {
RowButtonView("Retirer des poules", role: .destructive) {
team.resetGroupeStagePosition()
_save()
}
.disabled(team.inGroupStage() == false)
}
Section {
RowButtonView("Retirer du tableau", role: .destructive) {
team.resetBracketPosition()
_save()
}
.disabled(team.inRound() == false)
}
Section {
RowButtonView("Effacer l'équipe", role: .destructive, systemImage: "trash") {
team.deleteTeamScores()
do {
try tournamentStore.teamRegistrations.delete(instance: team)
} catch {
Logger.error(error)
}
dismiss()
}
}
}
.navigationBarBackButtonHidden(focusedField != nil)
.toolbar(content: {
if focusedField != nil {
ToolbarItem(placement: .topBarLeading) {
Button("Annuler", role: .cancel) {
focusedField = nil
}
}
}
})
.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, _):
if Guard.main.paymentForNewTournament() != nil {
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
if team.getPhoneNumbers().isEmpty == false {
self.sentError = .uncalledTeams([team])
} else {
self.sentError = .messageNotSent
}
}
@unknown default:
break
}
}
} else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
}
case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
if Guard.main.paymentForNewTournament() != nil {
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
if team.getMail().isEmpty == false {
self.sentError = .uncalledTeams([team])
} else {
self.sentError = .mailNotSent
}
}
@unknown default:
break
}
}
} else {
SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
.environment(\.colorScheme, .light)
}
}
}
.tint(.master)
}
.fullScreenCover(item: $editedTeam) { editedTeam in
NavigationStack {
AddTeamView(tournament: tournament, editedTeam: editedTeam)
}
.tint(.master)
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
MenuWarningView(tournament: tournament, teams: [team], contactType: $contactType)
}
}
.onChange(of: registrationDate) {
team.registrationDate = registrationDate
_save()
}
.toolbarBackground(.visible, for: .navigationBar)
.navigationTitle("Édition de l'équipe")
.navigationBarTitleDisplayMode(.inline)
}
private var confirmationReceived: Binding<Bool> {
Binding {
team.confirmed()
} set: { confirmed in
team.confirmationDate = confirmed ? Date() : nil
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
}
}
private var hasArrived: Binding<Bool> {
Binding {
team.unsortedPlayers().allSatisfy({ $0.hasArrived })
} set: { hasArrived in
team.unsortedPlayers().forEach {
$0.hasArrived = hasArrived
}
do {
try tournamentStore.playerRegistrations.addOrUpdate(contentOfs: team.unsortedPlayers())
} catch {
Logger.error(error)
}
}
}
private func _save() {
do {
try tournamentStore.teamRegistrations.addOrUpdate(instance: team)
} catch {
Logger.error(error)
}
}
private var _networkErrorMessage: String {
ContactManagerError.getNetworkErrorMessage(sentError: sentError, networkMonitorConnected: networkMonitor.connected)
}
}
//#Preview {
// EditingTeamView(team: TeamRegistration.mock())
//}