// // CallMessageCustomizationView.swift // Padel Tournament // // Created by Razmig Sarkissian on 02/11/2023. // import SwiftUI import LeStorage import PadelClubData struct CallMessageCustomizationView: View { @EnvironmentObject var dataStore: DataStore var tournament: Tournament enum Field { case signature case body case paymentMethods case clubName } @FocusState var focusedField: CallMessageCustomizationView.Field? @State private var customClubName: String = "" @State private var customCallMessageBody: String = "" @State private var customCallMessageSignature: String = "" @State private var summonsAvailablePaymentMethods: String = "" var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3) init(tournament: Tournament) { self.tournament = tournament _customCallMessageBody = State(wrappedValue: DataStore.shared.user.summonsMessageBody ?? (DataStore.shared.user.summonsUseFullCustomMessage ? "" : ContactType.defaultCustomMessage)) _customCallMessageSignature = State(wrappedValue: DataStore.shared.user.getSummonsMessageSignature() ?? DataStore.shared.user.defaultSignature(tournament)) _customClubName = State(wrappedValue: tournament.customClubName ?? tournament.clubName ?? "Lieu du tournoi") _summonsAvailablePaymentMethods = State(wrappedValue: DataStore.shared.user.summonsAvailablePaymentMethods ?? ContactType.defaultAvailablePaymentMethods) } var clubName: String { customClubName } var entryFeeMessage: String? { dataStore.user.summonsDisplayEntryFee ? tournament.entryFeeMessage : nil } var computedMessage: String { var linkMessage: String? { if tournament.isPrivate == false, let shareLink = tournament.shareURL(.matches)?.absoluteString { return "Vous pourrez suivre tous les résultats de ce tournoi sur le site :\n\n".appending(shareLink) } else { return nil } } return [entryFeeMessage, customCallMessageBody, linkMessage].compacted().map { $0.trimmedMultiline }.joined(separator: "\n") } var finalMessage: String? { let localizedCalled = "convoqué" + (tournament.tournamentCategory == .women ? "e" : "") + "s" return "Bonjour,\n\nVous êtes \(localizedCalled) pour jouer en \(RoundRule.roundName(fromRoundIndex: 2).lowercased()) du \(tournament.tournamentTitle(.title, hideSenior: true)) au \(clubName) le \(tournament.startDate.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(tournament.startDate.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(customCallMessageSignature)" } var body: some View { @Bindable var user = dataStore.user List { _renderingView() .disabled(true) _optionsView() _editorView() if user.summonsUseFullCustomMessage && tournament.isFree() == false { _paymentMethodsView() } Section { ZStack { Text(customCallMessageSignature).hidden() TextEditor(text: $customCallMessageSignature) .autocorrectionDisabled() .focused($focusedField, equals: .signature) } } header: { Text("Signature du message") } footer: { HStack { Spacer() FooterButtonView("effacer") { customCallMessageSignature = "" _save() } Divider() FooterButtonView("défaut") { customCallMessageSignature = DataStore.shared.user.defaultSignature(tournament) _save() } Divider() FooterButtonView("éditer") { focusedField = .signature } } } _clubNameView() } .headerProminence(.increased) .navigationBarTitleDisplayMode(.inline) .navigationBarBackButtonHidden(focusedField != nil) .toolbar(content: { if focusedField != nil { ToolbarItem(placement: .topBarLeading) { Button("Annuler", role: .cancel) { focusedField = nil } } } }) .toolbarBackground(.visible, for: .navigationBar) .navigationTitle("Message de convocation") .toolbar { ToolbarItemGroup(placement: .keyboard) { if focusedField != .clubName { Spacer() Button { focusedField = nil _save() } label: { Text("Valider") } .buttonStyle(.borderedProminent) } } } .onChange(of: user.summonsUseFullCustomMessage) { user.summonsMessageBody = nil if user.summonsUseFullCustomMessage == false { customCallMessageBody = ContactType.defaultCustomMessage } else { customCallMessageBody = "" } _save() } .onChange(of: user.summonsDisplayEntryFee) { _save() } } private func _save() { if customCallMessageBody.isEmpty { self.dataStore.user.summonsMessageBody = nil } else { self.dataStore.user.summonsMessageBody = customCallMessageBody } if customCallMessageSignature.isEmpty { self.dataStore.user.summonsMessageSignature = nil } else { self.dataStore.user.summonsMessageSignature = customCallMessageSignature } self.dataStore.user.summonsAvailablePaymentMethods = summonsAvailablePaymentMethods self.dataStore.saveUser() } @ViewBuilder private func _editorView() -> some View { @Bindable var user = dataStore.user Section { ZStack { Text(customCallMessageBody).hidden() .padding(.vertical, 20) TextEditor(text: $customCallMessageBody) .autocorrectionDisabled() .focused($focusedField, equals: .body) } } header: { if user.summonsUseFullCustomMessage { Text("Message de convocation") } else { Text("Information supplémentaire") } } footer: { if user.summonsUseFullCustomMessage == false { HStack { Spacer() FooterButtonView("effacer") { customCallMessageBody = "" _save() } Divider() FooterButtonView("défaut") { customCallMessageBody = ContactType.defaultCustomMessage _save() } Divider() FooterButtonView("éditer") { focusedField = .body } } } else { LazyVGrid(columns: columns, spacing: 0) { FooterButtonView("#titre") { customCallMessageBody.append("#titre") focusedField = .body } FooterButtonView("#manche") { customCallMessageBody.append("#manche") focusedField = .body } FooterButtonView("#prix") { customCallMessageBody.append("#prix") focusedField = .body } FooterButtonView("#jour") { customCallMessageBody.append("#jour") focusedField = .body } FooterButtonView("#horaire") { customCallMessageBody.append("#horaire") focusedField = .body } FooterButtonView("#club") { customCallMessageBody.append("#club") focusedField = .body } FooterButtonView("#signature") { customCallMessageBody.append("#signature") focusedField = .body } } } } } @ViewBuilder private func _clubNameView() -> some View { if let eventClub = tournament.eventObject()?.clubObject() { let hasBeenCreated: Bool = eventClub.hasBeenCreated(by: StoreCenter.main.userId) Section { TextField("Nom du club", text: $customClubName) .autocorrectionDisabled() .focused($focusedField, equals: .clubName) .onSubmit { tournament.customClubName = customClubName.prefixTrimmed(100) do { try dataStore.tournaments.addOrUpdate(instance: tournament) } catch { Logger.error(error) } } .disabled(hasBeenCreated == false) } footer: { if hasBeenCreated == false { Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed) } else { HStack { Spacer() FooterButtonView("éditer") { focusedField = .clubName } } } } } } @ViewBuilder private func _renderingView() -> some View { @Bindable var user = dataStore.user Section { Group { if user.summonsUseFullCustomMessage { Text(self.computedFullCustomMessage()) } else if let finalMessage { Text(finalMessage) } }.italic().foregroundStyle(.gray) } header: { Text("Exemple généré automatiquement") } } @ViewBuilder private func _optionsView() -> some View { @Bindable var user = dataStore.user Section { Toggle(isOn: $user.summonsUseFullCustomMessage) { Text("Tout personnaliser") Text("Écrivez votre propre message.") } if user.summonsUseFullCustomMessage == false { Toggle(isOn: $user.summonsDisplayEntryFee) { Text("Afficher le prix d'inscription") Text("et les informations sur le paiement") } } } header: { Text("Options") } if user.summonsDisplayEntryFee && user.summonsUseFullCustomMessage == false && tournament.isFree() == false { _paymentMethodsView() } } @ViewBuilder private func _paymentMethodsView() -> some View { Section { ZStack { Text(summonsAvailablePaymentMethods).hidden() .padding(.vertical, 20) TextEditor(text: $summonsAvailablePaymentMethods) .autocorrectionDisabled() .focused($focusedField, equals: .paymentMethods) } } header: { Text("Information sur le paiement") } footer: { HStack { Spacer() FooterButtonView("effacer") { summonsAvailablePaymentMethods = "" _save() } Divider() FooterButtonView("défaut") { summonsAvailablePaymentMethods = ContactType.defaultAvailablePaymentMethods _save() } Divider() FooterButtonView("éditer") { focusedField = .paymentMethods } } } } func computedFullCustomMessage() -> String { return ContactType.callingCustomMessage(source: customCallMessageBody, tournament: tournament, startDate: Date(), roundLabel: RoundRule.roundName(fromRoundIndex: 2)) } }