feat(store): add In-App Purchase system with Pro subscription
Implement freemium model with StoreKit 2: - StoreManager singleton for purchase/restore/entitlements - ProFeature enum defining gated features - PaywallView and OnboardingPaywallView for upsell UI - ProGate view modifier and ProBadge component Feature gating: - Trip saving: 1 free trip, then requires Pro - PDF export: Pro only with badge indicator - Progress tab: Shows ProLockedView for free users - Settings: Subscription management section Also fixes pre-existing test issues with StadiumVisit and ItineraryOption model signature changes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,29 +4,36 @@
|
||||
//
|
||||
|
||||
import Testing
|
||||
import Foundation
|
||||
import CoreLocation
|
||||
@testable import SportsTime
|
||||
|
||||
struct TripOptionsGroupingTests {
|
||||
|
||||
// Helper to create mock ItineraryStop
|
||||
private func makeStop(city: String, games: [String] = []) -> ItineraryStop {
|
||||
ItineraryStop(
|
||||
city: city,
|
||||
state: "XX",
|
||||
coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0),
|
||||
games: games,
|
||||
arrivalDate: Date(),
|
||||
departureDate: Date(),
|
||||
location: LocationInput(name: city, coordinate: nil),
|
||||
firstGameStart: nil
|
||||
)
|
||||
}
|
||||
|
||||
// Helper to create mock ItineraryOption
|
||||
private func makeOption(stops: [(city: String, games: [String])], totalMiles: Double = 500) -> ItineraryOption {
|
||||
let tripStops = stops.map { stopData in
|
||||
TripStop(
|
||||
city: stopData.city,
|
||||
state: "XX",
|
||||
coordinate: .init(latitude: 0, longitude: 0),
|
||||
games: stopData.games,
|
||||
arrivalDate: Date(),
|
||||
departureDate: Date(),
|
||||
travelFromPrevious: nil
|
||||
)
|
||||
}
|
||||
let itineraryStops = stops.map { makeStop(city: $0.city, games: $0.games) }
|
||||
return ItineraryOption(
|
||||
id: UUID().uuidString,
|
||||
stops: tripStops,
|
||||
totalDistanceMiles: totalMiles,
|
||||
rank: 1,
|
||||
stops: itineraryStops,
|
||||
travelSegments: [],
|
||||
totalDrivingHours: totalMiles / 60,
|
||||
score: 1.0
|
||||
totalDistanceMiles: totalMiles,
|
||||
geographicRationale: "Test"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user