Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for displayPurchaseHistoryLink #4686

Merged
merged 31 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
01aa502
added first version of purchase history view
aboedo Jan 2, 2025
6210762
clean up
aboedo Jan 2, 2025
34ac201
more UI updates
aboedo Jan 2, 2025
196e224
add a couple of notes, clean up
aboedo Jan 2, 2025
d7e0c5d
remove navigation stack wrapper from PurchaseHistoryView
facumenzella Jan 9, 2025
9ea5101
ignore swiftlint
facumenzella Jan 14, 2025
b2cc1c9
Update PurchaseLinkView.swift
hiddevdploeg Jan 14, 2025
8b9d08d
feat: CompatibilityLabeledContent
facumenzella Jan 14, 2025
9a70e54
Merge branch 'main' into feat/customer-center-history
facumenzella Jan 14, 2025
2211c83
introduce PurchaseDetailViewModel with items
facumenzella Jan 14, 2025
9dcd8e3
Merge branch 'main' into feat/customer-center-history
facumenzella Jan 15, 2025
893ca63
feat: Add non subscription support
facumenzella Jan 15, 2025
e8c524d
nit: add missing headers
facumenzella Jan 15, 2025
d0c4b59
feat: Added price
facumenzella Jan 15, 2025
731f925
added displayPurchaseHistoryLink
facumenzella Jan 17, 2025
9a017b5
missing localizations
facumenzella Jan 17, 2025
4f6e4c7
added loading state
facumenzella Jan 17, 2025
50c6047
hide button if not enabled
facumenzella Jan 17, 2025
53ff3cd
feat: [CustomerCenter] Final tweaks for History
facumenzella Jan 20, 2025
6998d48
fix: Broken xcodeproj
facumenzella Jan 20, 2025
073a90e
update ContactSupportUtilitiesTests
facumenzella Jan 20, 2025
384d6f8
unused_declaration
facumenzella Jan 20, 2025
78d2525
nits
facumenzella Jan 20, 2025
3665dd1
add generic error view
facumenzella Jan 20, 2025
dc9f93b
nit CompatibilityNavigationStack
facumenzella Jan 20, 2025
2a89473
list all cases instead of default
facumenzella Jan 20, 2025
aee1e06
Merge branch 'main' into feat/customer-center-history2
facumenzella Jan 20, 2025
dc25e97
added Sendable conformance
facumenzella Jan 20, 2025
8176d06
Merge branch 'main' into feat/customer-center-history2
facumenzella Jan 20, 2025
53ae35d
pod lib lint fixed issues
facumenzella Jan 20, 2025
e768944
nit: Rename CSCommonLocalizedString to CCLocalizedString
facumenzella Jan 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Added price
  • Loading branch information
facumenzella committed Jan 15, 2025
commit d0c4b5985ea3d5ebe4e9c050a2970a1b5990c6c4
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@available(watchOS, unavailable)
enum PurchaseDetailItem: Identifiable {
case productName(String?)
case paidPrice(String?)
case purchaseDate(String)
case status(String)

Expand All @@ -39,6 +40,7 @@ enum PurchaseDetailItem: Identifiable {
var label: String {
switch self {
case .productName: return String(localized: "Product name")
case .paidPrice: return String(localized: "Paid price")
case .purchaseDate: return String(localized: "Original Download Date")
case .status: return String(localized: "Status")
case .nextRenewalDate: return String(localized: "Next Renewal")
Expand All @@ -58,6 +60,7 @@ enum PurchaseDetailItem: Identifiable {
var content: String {
switch self {
case let .productName(name): return name ?? "-"
case let .paidPrice(price): return price ?? "-"

case .purchaseDate(let value),
.expiresDate(let value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ enum PurchaseInfo: Identifiable {
}
}

var paidPrice: String? {
formattedPrice(price)
}

private var price: ProductPaidPrice? {
switch self {
case let .subscription(info):
info.price
case let .nonSubscription(transaction):
nil
}
}

var willRenew: Bool {
switch self {
case let .subscription(info):
Expand Down Expand Up @@ -74,6 +87,10 @@ enum PurchaseInfo: Identifiable {
var items: [PurchaseDetailItem] = []
switch self {
case let .subscription(purchaseInfo):
if let price = paidPrice {
items.append(.paidPrice(price))
}

items.append(.status(purchaseInfo.isActive
? String(localized: "Active")
: String(localized: "Inactive")))
Expand Down Expand Up @@ -156,6 +173,21 @@ private extension PurchaseInfo {
func formattedDate(_ date: Date) -> String {
Self.formatter.string(from: date)
}

func formattedPrice(_ price: ProductPaidPrice?) -> String? {
guard let price else {
return nil
}

// Not the most performance, but not thread to mutate the currency
// todo: cache based on currency
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 2
formatter.currencyCode = price.currency

return formatter.string(from: NSNumber(value: price.amount))
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ struct ManageSubscriptionsView: View {
NavigationLink {
PurchaseHistoryView(viewModel: PurchaseHistoryViewModel())
} label: {
Text("See all purchases")
Text(String(localized: "See all purchases"))
}

Section {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ struct PurchaseLinkView: View {

Spacer()

if let price = purchaseInfo.paidPrice {
Text(price)
.font(.subheadline)
.foregroundStyle(.tertiary)
}

Image(systemName: "chevron.forward")
.foregroundStyle(.secondary)
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/Identity/CustomerInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ public typealias ProductIdentifier = String
periodType: subscriptionData.periodType,
refundedAt: subscriptionData.refundedAt,
storeTransactionId: subscriptionData.storeTransactionId,
requestDate: response.requestDate
requestDate: response.requestDate,
price: subscriptionData.price.map { ProductPaidPrice(currency: $0.currency, amount: $0.amount) }
))
})
}
Expand Down
7 changes: 6 additions & 1 deletion Sources/Identity/SubscriptionInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ import Foundation
/// Whether the subscription will renew at the next billing period.
@objc public let willRenew: Bool

/// Paid price for the subscription
@objc public let price: ProductPaidPrice?

init(productIdentifier: String,
purchaseDate: Date,
originalPurchaseDate: Date?,
Expand All @@ -85,7 +88,8 @@ import Foundation
periodType: PeriodType,
refundedAt: Date?,
storeTransactionId: String?,
requestDate: Date) {
requestDate: Date,
price: ProductPaidPrice?) {
self.productIdentifier = productIdentifier
self.purchaseDate = purchaseDate
self.originalPurchaseDate = originalPurchaseDate
Expand All @@ -104,6 +108,7 @@ import Foundation
store: store,
unsubscribeDetectedAt: unsubscribeDetectedAt,
billingIssueDetectedAt: billingIssuesDetectedAt)
self.price = price

super.init()
}
Expand Down
10 changes: 10 additions & 0 deletions Sources/Networking/Responses/CustomerInfoResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ extension CustomerInfoResponse {
var refundedAt: Date?
var storeTransactionId: String?

var displayName: String?

/// Price paid for the subscription
var price: PurchasePaidPrice?
}

struct PurchasePaidPrice {
let currency: String
let amount: Double
}

struct Transaction {
Expand Down Expand Up @@ -97,6 +106,7 @@ extension CustomerInfoResponse {

extension CustomerInfoResponse.Subscriber: Codable, Hashable {}
extension CustomerInfoResponse.Subscription: Codable, Hashable {}
extension CustomerInfoResponse.PurchasePaidPrice: Codable, Hashable {}

extension CustomerInfoResponse.Entitlement: Hashable {}
extension CustomerInfoResponse.Entitlement: Encodable {}
Expand Down
33 changes: 33 additions & 0 deletions Sources/Purchasing/ProductPaidPrice.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// ProductPaidPrice.swift
//
// Created by Facundo Menzella on 15/1/25.

import Foundation

/// Price paid for the product
@objc(RCProductPaidPrice) public final class ProductPaidPrice: NSObject {

/// Currency paid
@objc public let currency: String

/// Amount paid
@objc public let amount: Double

/// ProductPaidPrice initialiser
/// - Parameters:
/// - currency: Currency paid
/// - amount: Amount paid
public init(currency: String, amount: Double) {
self.currency = currency
self.amount = amount
}
}
2 changes: 1 addition & 1 deletion Sources/Purchasing/Purchases/Purchases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ public extension Purchases {
}

func customerInfo() async throws -> CustomerInfo {
return try await self.customerInfo(fetchPolicy: .default)
return try await self.customerInfo(fetchPolicy: .fetchCurrent)
}

func customerInfo(fetchPolicy: CacheFetchPolicy) async throws -> CustomerInfo {
Expand Down