diff options
Diffstat (limited to 'DomainDig/PaywallView.swift')
| -rw-r--r-- | DomainDig/PaywallView.swift | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/DomainDig/PaywallView.swift b/DomainDig/PaywallView.swift new file mode 100644 index 0000000..a21448f --- /dev/null +++ b/DomainDig/PaywallView.swift @@ -0,0 +1,123 @@ +import StoreKit +import SwiftUI + +struct PaywallView: View { + @Environment(\.dismiss) private var dismiss + @Environment(\.appDensity) private var appDensity + @State private var purchaseService = PurchaseService.shared + + var body: some View { + NavigationStack { + List { + Section { + Text("Pro unlocks automation, larger runs, and export convenience while keeping the core lookup experience free.") + .font(appDensity.font(.body, design: .default)) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + } + + Section("What Pro Unlocks") { + featureRow("Unlimited tracked domains") + featureRow("Workflows") + featureRow("Larger batch sizes") + featureRow("Advanced exports") + } + + Section("Subscription") { + if purchaseService.isLoadingProducts { + ProgressView("Loading pricing…") + } else if purchaseService.products.isEmpty { + Text("Pricing is unavailable right now.") + .font(appDensity.font(.caption, design: .default)) + .foregroundStyle(.secondary) + + Button("Retry") { + Task { + await purchaseService.refreshProducts() + } + } + } else { + ForEach(purchaseService.products, id: \.id) { product in + Button { + Task { + await purchaseService.purchase(product) + } + } label: { + VStack(alignment: .leading, spacing: 6) { + Text(subscriptionTitle(for: product)) + .font(appDensity.font(.headline, design: .default, weight: .semibold)) + .foregroundStyle(.primary) + Text(product.displayPrice) + .font(appDensity.font(.callout, design: .default)) + .foregroundStyle(.secondary) + } + .frame(maxWidth: .infinity, alignment: .leading) + } + .disabled(purchaseService.isPurchasing || purchaseService.isRestoring) + } + } + + if let statusMessage = purchaseService.statusMessage { + Text(statusMessage) + .font(appDensity.font(.caption, design: .default)) + .foregroundStyle(.secondary) + } + + if let errorMessage = purchaseService.errorMessage { + Text(errorMessage) + .font(appDensity.font(.caption, design: .default)) + .foregroundStyle(.red) + } + } + + Section("Account") { + Button(purchaseService.isRestoring ? "Restoring…" : "Restore Purchases") { + Task { + await purchaseService.restorePurchases() + } + } + .disabled(purchaseService.isPurchasing || purchaseService.isRestoring) + + if purchaseService.hasProAccess { + Button("Manage Subscription") { + Task { + await purchaseService.manageSubscription() + } + } + } + } + } + .navigationTitle("DomainDig Pro") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("Done") { + dismiss() + } + } + } + } + .task { + await purchaseService.refreshProducts() + await purchaseService.refreshEntitlements() + } + .onDisappear { + purchaseService.clearMessages() + } + } + + private func featureRow(_ title: String) -> some View { + Text(title) + .font(appDensity.font(.body, design: .default)) + } + + private func subscriptionTitle(for product: Product) -> String { + switch product.id { + case PurchaseService.monthlyProductID: + return "Pro Monthly" + case PurchaseService.yearlyProductID: + return "Pro Yearly" + default: + return product.displayName + } + } +} |
