diff --git a/Library/SharedFunctions.swift b/Library/SharedFunctions.swift index 15819ebde1..cd637d3699 100644 --- a/Library/SharedFunctions.swift +++ b/Library/SharedFunctions.swift @@ -367,7 +367,7 @@ public func rewardsCarouselCanNavigateToReward(_ reward: Reward, in project: Pro let isBacking = userIsBacking(reward: reward, inProject: project) let isAvailableForNewBacker = rewardIsAvailable(reward) && !isBacking - let isAvailableForExistingBackerToEdit = (isBacking && reward.hasAddOns) + let isAvailableForExistingBackerToEdit = (isBacking && (reward.hasAddOns || featureNoShippingAtCheckout())) if featurePostCampaignPledgeEnabled(), project.isInPostCampaignPledgingPhase { return [ diff --git a/Library/SharedFunctionsTests.swift b/Library/SharedFunctionsTests.swift index 2870aacd87..b07e62bcb4 100644 --- a/Library/SharedFunctionsTests.swift +++ b/Library/SharedFunctionsTests.swift @@ -149,7 +149,8 @@ final class SharedFunctionsTests: TestCase { XCTAssertTrue(rewardsCarouselCanNavigateToReward(reward, in: project)) } - func testRewardsCarouselCanNavigateToReward_RegularReward_Available_Backed() { + func testRewardsCarouselCanNavigateToReward_RegularReward_Available_Backed_FeatureNoShippingAtCheckout_False( + ) { let reward = Reward.template |> Reward.lens.limit .~ 5 |> Reward.lens.remaining .~ 5 @@ -166,6 +167,31 @@ final class SharedFunctionsTests: TestCase { XCTAssertFalse(rewardsCarouselCanNavigateToReward(reward, in: project)) } + func testRewardsCarouselCanNavigateToReward_RegularReward_Available_Backed_FeatureNoShippingAtCheckout_True( + ) { + let mockConfigClient = MockRemoteConfigClient() + mockConfigClient.features = [ + RemoteConfigFeature.noShippingAtCheckout.rawValue: true + ] + + let reward = Reward.template + |> Reward.lens.limit .~ 5 + |> Reward.lens.remaining .~ 5 + |> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60) + + let project = Project.cosmicSurgery + |> Project.lens.rewardData.rewards .~ [reward] + |> Project.lens.personalization.backing .~ ( + .template + |> Backing.lens.reward .~ reward + |> Backing.lens.rewardId .~ reward.id + ) + + withEnvironment(remoteConfigClient: mockConfigClient) { + XCTAssertTrue(rewardsCarouselCanNavigateToReward(reward, in: project)) + } + } + func testRewardsCarouselCanNavigateToReward_RegularReward_Unavailable_Backed() { let reward = Reward.template |> Reward.lens.limit .~ 5 diff --git a/Library/ViewModels/NoShippingPledgeViewModel.swift b/Library/ViewModels/NoShippingPledgeViewModel.swift index 72fdf630ed..b30a4e9a68 100644 --- a/Library/ViewModels/NoShippingPledgeViewModel.swift +++ b/Library/ViewModels/NoShippingPledgeViewModel.swift @@ -1076,7 +1076,8 @@ private func amountValid( that is, in `RewardAddOnSelectionViewController` we don't navigate further unless the selection changes. */ return [ - pledgeAmountData.amount != initialAdditionalPledgeAmount || reward.hasAddOns, + pledgeAmountData + .amount != initialAdditionalPledgeAmount || (reward.hasAddOns || featureNoShippingAtCheckout()), pledgeAmountData.isValid ] .allSatisfy(isTrue) diff --git a/Library/ViewModels/RewardCardContainerViewModel.swift b/Library/ViewModels/RewardCardContainerViewModel.swift index b3174229a5..1a6600ecab 100644 --- a/Library/ViewModels/RewardCardContainerViewModel.swift +++ b/Library/ViewModels/RewardCardContainerViewModel.swift @@ -105,7 +105,7 @@ private func pledgeButtonTitle(project: Project, reward: Reward) -> String? { case (.backed(.live), false, true): return Strings.Select() case (.backed(.live), true, _), (.backed(.nonLive), true, _): - if reward.hasAddOns, project.state == .live { + if reward.hasAddOns || featureNoShippingAtCheckout(), project.state == .live { return Strings.Continue() } return Strings.Selected() @@ -135,7 +135,7 @@ private func buttonStyleType(project: Project, reward: Reward) -> ButtonStyleTyp } case .backed(.live): if isBackingThisReward { - if reward.hasAddOns { + if reward.hasAddOns || featureNoShippingAtCheckout() { return .green } return .black diff --git a/Library/ViewModels/WithShippingRewardsCollectionViewModel.swift b/Library/ViewModels/WithShippingRewardsCollectionViewModel.swift index 5b4e903ed2..21172e455b 100644 --- a/Library/ViewModels/WithShippingRewardsCollectionViewModel.swift +++ b/Library/ViewModels/WithShippingRewardsCollectionViewModel.swift @@ -476,8 +476,8 @@ private func filteredRewardsByLocation( let isUnrestrictedShippingReward = reward.isUnRestrictedShippingPreference let isRestrictedShippingReward = reward.isRestrictedShippingPreference - // return all rewards that are digital or ship anywhere in the world. - if isRewardLocalOrDigital || isUnrestrictedShippingReward { + // return all rewards that are no reward, digital, or ship anywhere in the world. + if rewards.first?.id == reward.id || isRewardLocalOrDigital || isUnrestrictedShippingReward { shouldDisplayReward = true // if add on is local pickup, ensure locations are equal.