From a3c2db382396cb6b1b4220c1464298834b6a9526 Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 17 May 2024 20:05:21 +0200 Subject: [PATCH] fixes stuff for subscriptions --- PadelClub/Utils/SourceFileManager.swift | 1 - PadelClub/Views/Calling/CallView.swift | 15 ++-- PadelClub/Views/Calling/SendToAllView.swift | 13 ++- PadelClub/Views/Match/MatchDetailView.swift | 6 +- .../Views/Navigation/Umpire/UmpireView.swift | 2 +- PadelClub/Views/Subscription/Guard.swift | 27 +++--- .../Views/Subscription/SubscriptionView.swift | 87 +++++++++++-------- 7 files changed, 88 insertions(+), 63 deletions(-) diff --git a/PadelClub/Utils/SourceFileManager.swift b/PadelClub/Utils/SourceFileManager.swift index 1a6fc97..570fbf8 100644 --- a/PadelClub/Utils/SourceFileManager.swift +++ b/PadelClub/Utils/SourceFileManager.swift @@ -34,7 +34,6 @@ class SourceFileManager { print("Error: \(error)") } } - var lastDataSource: String? { DataStore.shared.appSettings.lastDataSource diff --git a/PadelClub/Views/Calling/CallView.swift b/PadelClub/Views/Calling/CallView.swift index 292c0c2..da9bd86 100644 --- a/PadelClub/Views/Calling/CallView.swift +++ b/PadelClub/Views/Calling/CallView.swift @@ -59,6 +59,8 @@ struct CallView: View { @State private var contactType: ContactType? = nil @State private var sentError: ContactManagerError? = nil + @State var cannotPayForTournament: Bool = false + var messageSentFailed: Binding { Binding { sentError != nil @@ -82,8 +84,6 @@ struct CallView: View { ContactType.callingMessage(tournament: tournament, startDate: callDate, roundLabel: roundLabel, matchFormat: matchFormat) } - // TODO: Guard - var body: some View { let callWord = teams.allSatisfy({ $0.called() }) ? "Reconvoquer" : "Convoquer" HStack { @@ -110,6 +110,9 @@ struct CallView: View { .underline() } } + .onAppear { + self.cannotPayForTournament = Guard.main.paymentForNewTournament() == nil + } .font(.subheadline) .buttonStyle(.borderless) .alert("Un problème est survenu", isPresented: messageSentFailed) { @@ -123,7 +126,7 @@ struct CallView: View { Group { switch contactType { case .message(_, let recipients, let body, _): - if Guard.main.paymentForNewTournament() != nil { + if !self.cannotPayForTournament { MessageComposeView(recipients: recipients, body: body) { result in switch result { case .cancelled: @@ -142,10 +145,10 @@ struct CallView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } case .mail(_, let recipients, let bccRecipients, let body, let subject, _): - if Guard.main.paymentForNewTournament() != nil { + if !self.cannotPayForTournament { MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in switch result { case .cancelled, .saved: @@ -166,7 +169,7 @@ struct CallView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } } } diff --git a/PadelClub/Views/Calling/SendToAllView.swift b/PadelClub/Views/Calling/SendToAllView.swift index ec157ed..5ebdc71 100644 --- a/PadelClub/Views/Calling/SendToAllView.swift +++ b/PadelClub/Views/Calling/SendToAllView.swift @@ -17,6 +17,8 @@ struct SendToAllView: View { @State private var contactRecipients: Set = Set() @State private var sentError: ContactManagerError? = nil + @State var cannotPayForTournament: Bool = false + var messageSentFailed: Binding { Binding { sentError != nil @@ -93,7 +95,7 @@ struct SendToAllView: View { Group { switch contactType { case .message(_, let recipients, let body, _): - if Guard.main.paymentForNewTournament() != nil { + if !self.cannotPayForTournament { MessageComposeView(recipients: recipients, body: body) { result in switch result { case .cancelled: @@ -109,10 +111,10 @@ struct SendToAllView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } case .mail(_, let recipients, let bccRecipients, let body, let subject, _): - if Guard.main.paymentForNewTournament() != nil { + if !self.cannotPayForTournament { MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in switch result { case .cancelled, .saved: @@ -130,13 +132,16 @@ struct SendToAllView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$cannotPayForTournament, showLackOfPlanMessage: true) } } } .tint(.master) } } + .onAppear { + self.cannotPayForTournament = Guard.main.paymentForNewTournament() == nil + } } func _teams() -> [TeamRegistration] { diff --git a/PadelClub/Views/Match/MatchDetailView.swift b/PadelClub/Views/Match/MatchDetailView.swift index f9598e2..4e74f57 100644 --- a/PadelClub/Views/Match/MatchDetailView.swift +++ b/PadelClub/Views/Match/MatchDetailView.swift @@ -182,7 +182,7 @@ struct MatchDetailView: View { } .sheet(isPresented: self.$showSubscriptionView, content: { NavigationStack { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) } }) .sheet(item: $scoreType, onDismiss: { @@ -254,7 +254,7 @@ struct MatchDetailView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) } case .mail(_, let recipients, let bccRecipients, let body, let subject, _): if Guard.main.paymentForNewTournament() != nil { @@ -275,7 +275,7 @@ struct MatchDetailView: View { } } } else { - SubscriptionView(showLackOfPlanMessage: true) + SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true) } } } diff --git a/PadelClub/Views/Navigation/Umpire/UmpireView.swift b/PadelClub/Views/Navigation/Umpire/UmpireView.swift index bcff6bd..fcef6b2 100644 --- a/PadelClub/Views/Navigation/Umpire/UmpireView.swift +++ b/PadelClub/Views/Navigation/Umpire/UmpireView.swift @@ -167,7 +167,7 @@ struct UmpireView: View { } .sheet(isPresented: self.$showSubscriptions, content: { NavigationStack { - SubscriptionView() + SubscriptionView(isPresented: self.$showSubscriptions) } }) .sheet(isPresented: $presentSearchView) { diff --git a/PadelClub/Views/Subscription/Guard.swift b/PadelClub/Views/Subscription/Guard.swift index a220a09..1ac045b 100644 --- a/PadelClub/Views/Subscription/Guard.swift +++ b/PadelClub/Views/Subscription/Guard.swift @@ -87,6 +87,7 @@ import LeStorage @MainActor func updatePurchasedIdentifiers(_ transaction: StoreKit.Transaction) async { + Logger.log("\(transaction.productID) > purchase = \(transaction.originalPurchaseDate), exp date= \(transaction.expirationDate), rev date = \(transaction.revocationDate)") do { if transaction.revocationDate == nil { // If the App Store has not revoked the transaction, add it to the list of `purchasedIdentifiers`. @@ -205,22 +206,26 @@ import LeStorage return Tournament.TournamentPayment.subscriptionUnit } } - return nil + return self._paymentWithoutSubscription() default: - let freelyPayed: Int = DataStore.shared.tournaments.filter { $0.payment == .free && $0.isCanceled == false }.count - if freelyPayed < 1 { - return Tournament.TournamentPayment.free - } - let tournamentCreditCount: Int = self._purchasedTournamentCount() - let unitlyPayed = DataStore.shared.tournaments.filter { $0.payment == .unit && $0.isCanceled == false }.count - if tournamentCreditCount > unitlyPayed { - return Tournament.TournamentPayment.unit - } - return nil + return self._paymentWithoutSubscription() } } + fileprivate func _paymentWithoutSubscription() -> Tournament.TournamentPayment? { + let freelyPayed: Int = DataStore.shared.tournaments.filter { $0.payment == .free && $0.isCanceled == false }.count + if freelyPayed < 1 { + return Tournament.TournamentPayment.free + } + let tournamentCreditCount: Int = self._purchasedTournamentCount() + let unitlyPayed = DataStore.shared.tournaments.filter { $0.payment == .unit && $0.isCanceled == false }.count + if tournamentCreditCount > unitlyPayed { + return Tournament.TournamentPayment.unit + } + return nil + } + var remainingTournaments: Int { let unitlyPayed = DataStore.shared.tournaments.filter { $0.payment == Tournament.TournamentPayment.unit }.count let tournamentCreditCount = self._purchasedTournamentCount() diff --git a/PadelClub/Views/Subscription/SubscriptionView.swift b/PadelClub/Views/Subscription/SubscriptionView.swift index a4481db..bf53eb2 100644 --- a/PadelClub/Views/Subscription/SubscriptionView.swift +++ b/PadelClub/Views/Subscription/SubscriptionView.swift @@ -38,7 +38,6 @@ class SubscriptionModel: ObservableObject, StoreDelegate { @Published var error: Error? = nil @Published var isLoading: Bool = false - @Published var isPurchasing: Bool = false @Published var selectedProduct: Product? = nil { didSet { self._computePrice() @@ -52,7 +51,6 @@ class SubscriptionModel: ObservableObject, StoreDelegate { } @Published var products: [Product] = [] @Published var totalPrice: String = "" - @State var showSuccessfulPurchaseView: Bool = false func load() { self.isLoading = true @@ -72,30 +70,22 @@ class SubscriptionModel: ObservableObject, StoreDelegate { self.error = error } - func purchase() { + func purchase() async throws -> Bool { Logger.log("start purchase...") guard let product: Product = self.selectedProduct, let storeManager = self.storeManager else { Logger.w("missing product or store manager") - return + return false } - self.isPurchasing = true - Task { - do { - if product.item.isConsumable { - if let _ = try await storeManager.purchase(product, quantity: self.quantity) { - self.isPurchasing = false - self.showSuccessfulPurchaseView = true - } - } else { - let _ = try await storeManager.purchase(product) - self.isPurchasing = false + if product.item.isConsumable { + if let _ = try await storeManager.purchase(product, quantity: self.quantity) { + return true } - } catch { - Logger.error(error) - self.isPurchasing = false + } else { + let _ = try await storeManager.purchase(product) + return true } - } + return false } fileprivate func _computePrice() { @@ -118,10 +108,14 @@ struct SubscriptionView: View { @ObservedObject var model: SubscriptionModel = SubscriptionModel() + @Binding var isPresented: Bool + var showLackOfPlanMessage: Bool = false @State var isRestoring: Bool = false @State var showLoginView: Bool = false - + @State var isPurchasing: Bool = false + @State var showSuccessfulPurchaseView: Bool = false + var body: some View { Group { @@ -147,21 +141,21 @@ struct SubscriptionView: View { Section { - ForEach(self.model.products) { product in - let isSelected = self.model.selectedProduct == product - ProductView(product: product, - quantity: self.$model.quantity, - selected: isSelected) - .foregroundStyle(.white) - .frame(maxWidth: .infinity) - .buttonStyle(.borderedProminent) - .tint(Color.master) - .listRowBackground(Color.clear) - - .onTapGesture { - self.model.selectedProduct = product - } + ForEach(self.model.products) { product in + let isSelected = self.model.selectedProduct == product + ProductView(product: product, + quantity: self.$model.quantity, + selected: isSelected) + .foregroundStyle(.white) + .frame(maxWidth: .infinity) + .buttonStyle(.borderedProminent) + .tint(Color.master) + .listRowBackground(Color.clear) + + .onTapGesture { + self.model.selectedProduct = product } + } } header: { Text("Sélectionnez une offre") } @@ -178,7 +172,7 @@ struct SubscriptionView: View { } } label: { HStack { - if self.model.isPurchasing { + if self.isPurchasing { Spacer() ProgressView().tint(.white) Spacer() @@ -230,7 +224,26 @@ struct SubscriptionView: View { } fileprivate func _purchase() { - self.model.purchase() + + self.isPurchasing = true + + Task { + do { + let success = try await self.model.purchase() + DispatchQueue.main.async { + self.isPurchasing = false + self.showSuccessfulPurchaseView = true + if success { + self.isPresented = false + } + } + } catch { + Logger.error(error) + DispatchQueue.main.async { + self.isPurchasing = false + } + } + } } fileprivate func _load() { @@ -337,6 +350,6 @@ struct SubscriptionFooterView: View { #Preview { NavigationStack { - SubscriptionView(showLackOfPlanMessage: false) + SubscriptionView(isPresented: .constant(true), showLackOfPlanMessage: false) } }