diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 272356a..ba5f5be 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -84,6 +84,16 @@ class Tournament : ModelObject, Storable { enum TournamentPayment: Int { case free, unit, subscriptionUnit, unlimited + + var isSubscription: Bool { + switch self { + case .subscriptionUnit, .unlimited: + return true + default: + return false + } + } + } enum State { diff --git a/PadelClub/Views/Subscription/Guard.swift b/PadelClub/Views/Subscription/Guard.swift index e138366..9f20c66 100644 --- a/PadelClub/Views/Subscription/Guard.swift +++ b/PadelClub/Views/Subscription/Guard.swift @@ -10,7 +10,7 @@ import StoreKit import LeStorage @available(iOS 15, *) -@objc class Guard : NSObject { +@objc class Guard: NSObject { static var main: Guard = Guard() @@ -20,17 +20,18 @@ import LeStorage var updateListenerTask: Task? = nil - fileprivate var _userPurchases: [Purchase] = [] + fileprivate var _purchases: StoredCollection override init() { + self._purchases = Store.main.registerCollection(synchronized: true, inMemory: true) + super.init() self.updateListenerTask = self.listenForTransactions() Task { do { - try await self._retrievePrivateServerPurchases() try await self.refreshPurchasedAppleProducts() } catch { Logger.error(error) @@ -38,23 +39,6 @@ import LeStorage } } - fileprivate func _uploadTransaction(_ transaction: StoreKit.Transaction) async throws { - - let service = try Store.main.service() - var purchase = try transaction.purchase() - -// if let apiCall = try self._callForInstance(purchase, method: Method.post) { -// -// } - - - } - - fileprivate func _retrievePrivateServerPurchases() async throws { - let service = try Store.main.service() - self._userPurchases = try await service.get() - } - func refreshPurchasedAppleProducts() async throws { // Iterate through the user's purchased products. @@ -105,8 +89,10 @@ import LeStorage if transaction.revocationDate == nil { // If the App Store has not revoked the transaction, add it to the list of `purchasedIdentifiers`. purchasedTransactions.insert(transaction) + do { - try await self._uploadTransaction(transaction) + let purchase: Purchase = transaction.purchase() + try self._purchases.addOrUpdate(instance: purchase) } catch { Logger.error(error) } @@ -146,7 +132,7 @@ import LeStorage fileprivate func _userFilteredPurchases() -> [StoreKit.Transaction] { return self.purchasedTransactions.filter { transaction in - return self._userPurchases.contains(where: { $0.identifier == transaction.id } ) + return self._purchases.contains(where: { $0.identifier == transaction.id } ) } } @@ -171,42 +157,61 @@ import LeStorage return units.reduce(0) { $0 + $1.purchasedQuantity } } - func canAddTournament() -> Bool { - if self.currentPlan == .monthlyUnlimited { - return true - } - let tournamentCount = DataStore.shared.tournaments.count - let tournamentCreditCount = self._purchasedTournamentCount() - return tournamentCreditCount > tournamentCount - } +// func canAddTournament() -> Bool { +// switch self.currentPlan { +// case .monthlyUnlimited: return true +// case .fivePerMonth: +// if let date = self.currentBestPlan?.originalPurchaseDate { +// let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > date } +// return tournaments.count < StoreItem.five +// } else { +// Logger.error(StoreManagerError.missingPlan) +// return false +// } +// case .unit: +// let tournamentCount = DataStore.shared.tournaments.count +// let tournamentCreditCount = self._purchasedTournamentCount() +// return tournamentCreditCount > tournamentCount +// case nil: +// return DataStore.shared.tournaments.count == 0 +// } +// } func paymentForNewTournament() -> Tournament.TournamentPayment? { - if self.currentPlan == .monthlyUnlimited { + + switch self.currentPlan { + case .monthlyUnlimited: return Tournament.TournamentPayment.unlimited - } else if self.currentPlan == .fivePerMonth, let purchaseDate = self.currentBestPlan?.originalPurchaseDate { - let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate } - if tournaments.count < 5 { - return Tournament.TournamentPayment.subscriptionUnit + case .fivePerMonth: + if let purchaseDate = self.currentBestPlan?.originalPurchaseDate { + let tournaments = DataStore.shared.tournaments.filter { $0.creationDate > purchaseDate } + if tournaments.count < StoreItem.five { + return Tournament.TournamentPayment.subscriptionUnit + } } + return nil + default: + let subscriptionPayed = DataStore.shared.tournaments.filter { $0.payment.isSubscription } + + let unitlyPayed = DataStore.shared.tournaments.count - subscriptionPayed.count + if unitlyPayed == 0 { + return Tournament.TournamentPayment.free + } + let tournamentCreditCount = self._purchasedTournamentCount() + if tournamentCreditCount > unitlyPayed { + return Tournament.TournamentPayment.unit + } + return nil } - let tournamentCount = DataStore.shared.tournaments.count - if tournamentCount == 0 { - return Tournament.TournamentPayment.free - } - let tournamentCreditCount = self._purchasedTournamentCount() - if tournamentCreditCount > tournamentCount { - return Tournament.TournamentPayment.unit - } - return nil } } fileprivate extension StoreKit.Transaction { - func purchase() throws -> Purchase { - let userId = try Store.main.currentUserUUID().uuidString + func purchase() -> Purchase { + let userId = Store.main.currentUserUUID().uuidString return Purchase(user: userId, identifier: self.id, purchaseDate: self.purchaseDate, diff --git a/PadelClub/Views/Subscription/StoreItem.swift b/PadelClub/Views/Subscription/StoreItem.swift index e640f9b..95d034d 100644 --- a/PadelClub/Views/Subscription/StoreItem.swift +++ b/PadelClub/Views/Subscription/StoreItem.swift @@ -12,6 +12,8 @@ enum StoreItem: String, Identifiable, CaseIterable { case fivePerMonth = "app.padelclub.tournament.subscription.five.per.month" case unit = "app.padelclub.tournament.unit" + static let five: Int = 5 + var id: String { return self.rawValue } // var title: String { return "Tournoi illimités" } diff --git a/PadelClub/Views/Subscription/StoreManager.swift b/PadelClub/Views/Subscription/StoreManager.swift index 19f5693..bf1699a 100644 --- a/PadelClub/Views/Subscription/StoreManager.swift +++ b/PadelClub/Views/Subscription/StoreManager.swift @@ -11,6 +11,7 @@ import LeStorage public enum StoreManagerError: Error { case failedVerification + case missingPlan } protocol StoreDelegate { @@ -25,8 +26,6 @@ extension Notification.Name { @available(iOS 15, *) class StoreManager { -// @Published private(set) var products: [Product] = [] - @Published private(set) var purchasedTransactions = Set() var delegate: StoreDelegate? = nil @@ -48,10 +47,6 @@ class StoreManager { self.updateListenerTask?.cancel() } -// func indexOf(identifier: String) -> Int? { -// return self.products.map { $0.id }.firstIndex(of: identifier) -// } - @MainActor func requestProducts() async { do { @@ -95,7 +90,7 @@ class StoreManager { Logger.log("Store purchase started...") var options: Set = [] - let uuid: UUID = try Store.main.currentUserUUID() + let uuid: UUID = Store.main.currentUserUUID() let tokenOption = Product.PurchaseOption.appAccountToken(uuid) options.insert(tokenOption)