Skip to content

Commit

Permalink
[Paywalls V2] Added V1 fallback paywall into Paywall V2 error logic (#…
Browse files Browse the repository at this point in the history
…4666)

* Start of some fallback fixes

* Better fallback paywall stuff

* Lint
  • Loading branch information
joshdholtz authored Jan 15, 2025
1 parent 8c8f2d4 commit 4413503
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 34 deletions.
21 changes: 20 additions & 1 deletion RevenueCatUI/PaywallView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import SwiftUI
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
@available(macOS, unavailable, message: "RevenueCatUI does not support macOS yet")
@available(tvOS, unavailable, message: "RevenueCatUI does not support tvOS yet")
// swiftlint:disable:next type_body_length
public struct PaywallView: View {

private let contentToDisplay: PaywallViewConfiguration.Content
Expand Down Expand Up @@ -254,6 +255,23 @@ public struct PaywallView: View {

#if PAYWALL_COMPONENTS
if let paywallComponents = offering.paywallComponents {
// For fallback view
let paywall: PaywallData = .createDefault(with: offering.availablePackages,
locale: self.locale)
let paywallView = LoadedOfferingPaywallView(
offering: offering,
activelySubscribedProductIdentifiers: activelySubscribedProductIdentifiers,
paywall: paywall,
template: PaywallData.defaultTemplate,
mode: self.mode,
fonts: fonts,
displayCloseButton: self.displayCloseButton,
introEligibility: checker,
purchaseHandler: purchaseHandler,
locale: self.locale,
showZeroDecimalPlacePrices: showZeroDecimalPlacePrices
)

PaywallsV2View(
paywallComponents: paywallComponents,
offering: offering,
Expand All @@ -265,7 +283,8 @@ public struct PaywallView: View {
return
}
onRequestedDismissal()
}
},
fallbackView: paywallView
)
.environmentObject(self.introEligibility)
.environmentObject(self.purchaseHandler)
Expand Down
81 changes: 56 additions & 25 deletions RevenueCatUI/Templates/V2/PaywallsV2View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private struct PaywallState {
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
struct PaywallsV2View: View {
struct PaywallsV2View<Content: View>: View {

@Environment(\.horizontalSizeClass)
private var horizontalSizeClass
Expand All @@ -53,16 +53,19 @@ struct PaywallsV2View: View {
private let uiConfigProvider: UIConfigProvider
private let offering: Offering
private let onDismiss: () -> Void
private let fallbackView: Content

public init(
paywallComponents: Offering.PaywallComponents,
offering: Offering,
introEligibilityChecker: TrialOrIntroEligibilityChecker,
showZeroDecimalPlacePrices: Bool,
onDismiss: @escaping () -> Void
onDismiss: @escaping () -> Void,
fallbackView: Content
) {
let uiConfigProvider = UIConfigProvider(uiConfig: paywallComponents.uiConfig)

self.fallbackView = fallbackView
self.paywallComponentsData = paywallComponents.data
self.uiConfigProvider = uiConfigProvider
self.offering = offering
Expand Down Expand Up @@ -91,36 +94,64 @@ struct PaywallsV2View: View {
}

public var body: some View {
switch self.paywallStateManager.state {
case .success(let paywallState):
LoadedPaywallsV2View(
paywallState: paywallState,
uiConfigProvider: self.uiConfigProvider,
onDismiss: self.onDismiss
if let errorInfo = self.paywallComponentsData.errorInfo, !errorInfo.isEmpty {
// Show fallback paywall and debug error message that
// occurred while decoding the paywall
self.fallbackViewWithErrorMessage(
"Error decoding paywall response on: \(errorInfo.keys.joined(separator: ", "))"
)
.environment(\.screenCondition, ScreenCondition.from(self.horizontalSizeClass))
.environmentObject(self.introOfferEligibilityContext)
.disabled(self.purchaseHandler.actionInProgress)
.onAppear {
self.purchaseHandler.trackPaywallImpression(
self.createEventData()
} else {
switch self.paywallStateManager.state {
case .success(let paywallState):
LoadedPaywallsV2View(
paywallState: paywallState,
uiConfigProvider: self.uiConfigProvider,
onDismiss: self.onDismiss
)
}
.onDisappear { self.purchaseHandler.trackPaywallClose() }
.onChangeOf(self.purchaseHandler.purchased) { purchased in
if purchased {
self.onDismiss()
.environment(\.screenCondition, ScreenCondition.from(self.horizontalSizeClass))
.environmentObject(self.introOfferEligibilityContext)
.disabled(self.purchaseHandler.actionInProgress)
.onAppear {
self.purchaseHandler.trackPaywallImpression(
self.createEventData()
)
}
.onDisappear { self.purchaseHandler.trackPaywallClose() }
.onChangeOf(self.purchaseHandler.purchased) { purchased in
if purchased {
self.onDismiss()
}
}
.task {
await self.introOfferEligibilityContext.computeEligibility(for: paywallState.packages)
}
case .failure(let error):
// Show fallback paywall and debug error message that
// occurred while validating data and view models
self.fallbackViewWithErrorMessage(
"Error validating paywall: \(error.localizedDescription)"
)
}
.task {
await self.introOfferEligibilityContext.computeEligibility(for: paywallState.packages)
}
case .failure:
// WIP: Need to use fallback paywall
Text("Error creating paywall")
}
}

@ViewBuilder
func fallbackViewWithErrorMessage(_ errorMessage: String) -> some View {
let fullMessage = """
\(errorMessage)
Validate your paywall is correct in the RevenueCat dashboard,
update your SDK, or contact RevenueCat support.
View console logs for full detail.
The displayed paywall contains default configuration.
This error will be hidden in production.
"""

DebugErrorView(
fullMessage,
replacement: self.fallbackView
)
}

private func createEventData() -> PaywallEvent.Data {
return .init(
offering: self.offering,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// TestPaywallPreviews.swift
//
// Created by Josh Holtz on 9/26/24.
// swiftlint:disable file_length

import Foundation
import RevenueCat
Expand Down Expand Up @@ -387,7 +388,8 @@ struct FamilySharingTogglePreview_Previews: PreviewProvider {
]),
introEligibilityChecker: .default(),
showZeroDecimalPlacePrices: true,
onDismiss: { }
onDismiss: { },
fallbackView: EmptyView()
)
.previewRequiredEnvironmentProperties()
.previewLayout(.fixed(width: 400, height: 800))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ struct MultiTierPreview_Previews: PreviewProvider {
]),
introEligibilityChecker: .default(),
showZeroDecimalPlacePrices: true,
onDismiss: { }
onDismiss: { },
fallbackView: EmptyView()
)
.previewRequiredEnvironmentProperties()
.previewLayout(.fixed(width: 400, height: 800))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ struct Template1Preview_Previews: PreviewProvider {
availablePackages: [package]),
introEligibilityChecker: .default(),
showZeroDecimalPlacePrices: true,
onDismiss: { }
onDismiss: { },
fallbackView: EmptyView()
)
.previewRequiredEnvironmentProperties()
.previewLayout(.fixed(width: 400, height: 800))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public extension PaywallComponent {
switch self {
case .rectangle(let corners):
try container.encode(ShapeType.rectangle.rawValue, forKey: .type)
try container.encode(corners, forKey: .corners)
try container.encodeIfPresent(corners, forKey: .corners)
case .pill:
try container.encode(ShapeType.pill.rawValue, forKey: .type)
}
Expand Down Expand Up @@ -200,7 +200,7 @@ public extension PaywallComponent {
switch self {
case .rectangle(let corners):
try container.encode(ShapeType.rectangle.rawValue, forKey: .type)
try container.encode(corners, forKey: .corners)
try container.encodeIfPresent(corners, forKey: .corners)
case .circle:
try container.encode(ShapeType.circle.rawValue, forKey: .type)
}
Expand Down Expand Up @@ -249,14 +249,14 @@ public extension PaywallComponent {

switch self {
case .rectangle(let corners):
try container.encode(MaskShapeType.rectangle.rawValue, forKey: .type)
try container.encodeIfPresent(MaskShapeType.rectangle.rawValue, forKey: .type)
try container.encode(corners, forKey: .corners)
case .pill:
try container.encode(MaskShapeType.pill.rawValue, forKey: .type)
case .concave:
try container.encode(MaskShapeType.pill.rawValue, forKey: .type)
try container.encode(MaskShapeType.concave.rawValue, forKey: .type)
case .convex:
try container.encode(MaskShapeType.pill.rawValue, forKey: .type)
try container.encode(MaskShapeType.convex.rawValue, forKey: .type)
}
}

Expand Down

0 comments on commit 4413503

Please sign in to comment.