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.
211 lines
8.4 KiB
211 lines
8.4 KiB
//
|
|
// ContactManager.swift
|
|
// Padel Tournament
|
|
//
|
|
// Created by Razmig Sarkissian on 19/09/2023.
|
|
//
|
|
|
|
import Foundation
|
|
import SwiftUI
|
|
import MessageUI
|
|
import LeStorage
|
|
|
|
enum ContactManagerError: LocalizedError {
|
|
case mailFailed
|
|
case mailNotSent //no network no error
|
|
case messageFailed
|
|
case messageNotSent //no network no error
|
|
case calendarAccessDenied
|
|
case calendarEventSaveFailed
|
|
case noCalendarAvailable
|
|
}
|
|
|
|
enum ContactType: Identifiable {
|
|
case mail(date: Date?, recipients: [String]?, bccRecipients: [String]?, body: String?, subject: String?, tournamentBuild: TournamentBuild?)
|
|
case message(date: Date?, recipients: [String]?, body: String?, tournamentBuild: TournamentBuild?)
|
|
|
|
var id: Int {
|
|
switch self {
|
|
case .message: return 0
|
|
case .mail: return 1
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ContactType {
|
|
static let defaultCustomMessage: String =
|
|
"""
|
|
Il est conseillé de vous présenter 10 minutes avant de jouer.\n\nMerci de me confirmer votre présence avec votre nom et de prévenir votre partenaire.
|
|
"""
|
|
static let defaultAvailablePaymentMethods: String = "Règlement possible par chèque ou espèces."
|
|
|
|
static func callingCustomMessage(source: String? = nil, tournament: Tournament?, startDate: Date?, roundLabel: String) -> String {
|
|
let tournamentCustomMessage = source ?? DataStore.shared.user.summonsMessageBody ?? defaultCustomMessage
|
|
let clubName = tournament?.clubName ?? ""
|
|
|
|
var text = tournamentCustomMessage
|
|
let date = startDate ?? tournament?.startDate ?? Date()
|
|
|
|
if let tournament {
|
|
text = text.replacingOccurrences(of: "#titre", with: tournament.tournamentTitle(.short))
|
|
text = text.replacingOccurrences(of: "#prix", with: tournament.entryFeeMessage)
|
|
}
|
|
|
|
text = text.replacingOccurrences(of: "#club", with: clubName)
|
|
text = text.replacingOccurrences(of: "#manche", with: roundLabel.lowercased())
|
|
text = text.replacingOccurrences(of: "#jour", with: "\(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide)))")
|
|
text = text.replacingOccurrences(of: "#horaire", with: "\(date.formatted(Date.FormatStyle().hour().minute()))")
|
|
|
|
let signature = DataStore.shared.user.summonsMessageSignature ?? DataStore.shared.user.defaultSignature()
|
|
|
|
text = text.replacingOccurrences(of: "#signature", with: signature)
|
|
return text
|
|
}
|
|
|
|
static func callingMessage(tournament: Tournament?, startDate: Date?, roundLabel: String, matchFormat: MatchFormat?, reSummon: Bool = false) -> String {
|
|
|
|
let useFullCustomMessage = DataStore.shared.user.summonsUseFullCustomMessage
|
|
|
|
if useFullCustomMessage {
|
|
return callingCustomMessage(tournament: tournament, startDate: startDate, roundLabel: roundLabel)
|
|
}
|
|
|
|
let date = startDate ?? tournament?.startDate ?? Date()
|
|
|
|
let clubName = tournament?.clubName ?? ""
|
|
let message = DataStore.shared.user.summonsMessageBody ?? defaultCustomMessage
|
|
let signature = DataStore.shared.user.summonsMessageSignature ?? DataStore.shared.user.defaultSignature()
|
|
|
|
let localizedCalled = "convoqué" + (tournament?.tournamentCategory == .women ? "e" : "") + "s"
|
|
|
|
var entryFeeMessage: String? {
|
|
(DataStore.shared.user.summonsDisplayEntryFee) ? tournament?.entryFeeMessage : nil
|
|
}
|
|
|
|
var computedMessage: String {
|
|
[entryFeeMessage, message].compacted().map { $0.trimmedMultiline }.joined(separator: "\n\n")
|
|
}
|
|
|
|
let intro = reSummon ? "Suite à des forfaits, vous êtes finalement" : "Vous êtes"
|
|
|
|
if let tournament {
|
|
return "Bonjour,\n\n\(intro) \(localizedCalled) pour jouer en \(roundLabel.lowercased()) du \(tournament.tournamentTitle(.short)) au \(clubName) le \(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(date.formatted(Date.FormatStyle().hour().minute())).\n\n" + computedMessage + "\n\n\(signature)"
|
|
} else {
|
|
return "Bonjour,\n\n\(intro) \(localizedCalled) \(roundLabel) au \(clubName) le \(date.formatted(Date.FormatStyle().weekday(.wide).day().month(.wide))) à \(date.formatted(Date.FormatStyle().hour().minute())).\n\nMerci de confirmer en répondant à ce message et de prévenir votre partenaire !\n\n\(signature)"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct MessageComposeView: UIViewControllerRepresentable {
|
|
typealias Completion = (_ result: MessageComposeResult) -> Void
|
|
|
|
static var canSendText: Bool { MFMessageComposeViewController.canSendText() }
|
|
|
|
let recipients: [String]?
|
|
let body: String?
|
|
let completion: Completion?
|
|
|
|
func makeUIViewController(context: Context) -> UIViewController {
|
|
guard Self.canSendText else {
|
|
let errorView = ContentUnavailableView("Aucun compte de messagerie", systemImage: "xmark", description: Text("Aucun compte de messagerie n'est configuré sur cet appareil."))
|
|
return UIHostingController(rootView: errorView)
|
|
}
|
|
|
|
let controller = MFMessageComposeViewController()
|
|
controller.messageComposeDelegate = context.coordinator
|
|
controller.recipients = recipients
|
|
controller.body = body
|
|
|
|
return controller
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(completion: self.completion)
|
|
}
|
|
|
|
class Coordinator: NSObject, MFMessageComposeViewControllerDelegate {
|
|
private let completion: Completion?
|
|
|
|
public init(completion: Completion?) {
|
|
self.completion = completion
|
|
}
|
|
|
|
public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
|
|
controller.dismiss(animated: true, completion: {
|
|
self.completion?(result)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
struct MailComposeView: UIViewControllerRepresentable {
|
|
typealias Completion = (_ result: MFMailComposeResult) -> Void
|
|
|
|
static var canSendMail: Bool {
|
|
if let mailURL = URL(string: "mailto:?to=jap@padelclub.com") {
|
|
let mailConfigured = UIApplication.shared.canOpenURL(mailURL)
|
|
return mailConfigured && MFMailComposeViewController.canSendMail()
|
|
} else {
|
|
return MFMailComposeViewController.canSendMail()
|
|
}
|
|
}
|
|
|
|
let recipients: [String]?
|
|
let bccRecipients: [String]?
|
|
let body: String?
|
|
let subject: String?
|
|
var attachmentURL: URL?
|
|
let completion: Completion?
|
|
|
|
func makeUIViewController(context: Context) -> UIViewController {
|
|
guard Self.canSendMail else {
|
|
let errorView = ContentUnavailableView("Aucun compte mail", systemImage: "xmark", description: Text("Aucun compte mail n'est configuré sur cet appareil."))
|
|
return UIHostingController(rootView: errorView)
|
|
}
|
|
|
|
let controller = MFMailComposeViewController()
|
|
controller.mailComposeDelegate = context.coordinator
|
|
controller.setToRecipients(recipients)
|
|
controller.setBccRecipients(bccRecipients)
|
|
if let attachmentURL {
|
|
do {
|
|
let attachmentData = try Data(contentsOf: attachmentURL)
|
|
controller.addAttachmentData(attachmentData, mimeType: "application/zip", fileName: "backup.zip")
|
|
} catch {
|
|
print("Could not attach file: \(error)")
|
|
}
|
|
}
|
|
|
|
if let body {
|
|
controller.setMessageBody(body, isHTML: false)
|
|
}
|
|
if let subject {
|
|
controller.setSubject(subject)
|
|
}
|
|
|
|
return controller
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(completion: self.completion)
|
|
}
|
|
|
|
class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
|
|
private let completion: Completion?
|
|
|
|
public init(completion: Completion?) {
|
|
self.completion = completion
|
|
}
|
|
|
|
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
|
controller.dismiss(animated: true, completion: {
|
|
self.completion?(result)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|