From df760a38e2a6158aeeb19a223caf166eaebe79c4 Mon Sep 17 00:00:00 2001 From: Isabel Martin Date: Thu, 29 Aug 2024 10:07:35 -0700 Subject: [PATCH] MBL-1676: When a project is no longer allowed to collect, view rewards menu should not filter rewards nor show the select button (#2116) --- .../libs/utils/extensions/ProjectExt.kt | 7 ++ .../projectpage/RewardCarouselScreen.kt | 7 +- .../usecases/GetShippingRulesUseCase.kt | 14 ++- .../libs/utils/extensions/ProjectExtTest.kt | 48 ++++++++++ .../usecases/GetShippingRulesUseCaseTest.kt | 94 +++++++++++++++++++ 5 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 app/src/test/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCaseTest.kt diff --git a/app/src/main/java/com/kickstarter/libs/utils/extensions/ProjectExt.kt b/app/src/main/java/com/kickstarter/libs/utils/extensions/ProjectExt.kt index 7b2c92054d..6792cf999a 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/extensions/ProjectExt.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/extensions/ProjectExt.kt @@ -142,6 +142,13 @@ fun Project.deadlineCountdownValue(): Int { } } +/** + * The project is allowed to pledges during crowdfund active campaign or late pledges phase + */ +fun Project.isAllowedToPledge(): Boolean { + return (!this.isCompleted() || this.showLatePledgeFlow()) +} + /** * Returns `true` if the project is no longer live, `false` otherwise. */ diff --git a/app/src/main/java/com/kickstarter/ui/activities/compose/projectpage/RewardCarouselScreen.kt b/app/src/main/java/com/kickstarter/ui/activities/compose/projectpage/RewardCarouselScreen.kt index f046b34715..b42dd70a6a 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/compose/projectpage/RewardCarouselScreen.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/compose/projectpage/RewardCarouselScreen.kt @@ -32,6 +32,7 @@ import com.kickstarter.libs.utils.DateTimeUtils import com.kickstarter.libs.utils.NumberUtils import com.kickstarter.libs.utils.RewardUtils import com.kickstarter.libs.utils.RewardViewUtils +import com.kickstarter.libs.utils.extensions.isAllowedToPledge import com.kickstarter.libs.utils.extensions.isBacked import com.kickstarter.libs.utils.extensions.isNotNull import com.kickstarter.libs.utils.extensions.isNullOrZero @@ -218,7 +219,8 @@ fun RewardCarouselScreen( description = if (isBacked) stringResource(id = R.string.Thanks_for_bringing_this_project_one_step_closer_to_becoming_a_reality) else stringResource( id = R.string.Back_it_because_you_believe_in_it ), - onRewardSelectClicked = { onRewardSelected(reward) } + onRewardSelectClicked = { onRewardSelected(reward) }, + isCTAButtonVisible = project.isAllowedToPledge() ) } else { KSRewardCard( @@ -339,7 +341,8 @@ fun RewardCarouselScreen( } } } else null, - addonsPillVisible = reward.hasAddons() + addonsPillVisible = reward.hasAddons(), + isCTAButtonVisible = project.isAllowedToPledge() ) } } diff --git a/app/src/main/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCase.kt b/app/src/main/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCase.kt index bf237e0ded..d6716794a2 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCase.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCase.kt @@ -3,6 +3,7 @@ package com.kickstarter.viewmodels.usecases import com.kickstarter.libs.Config import com.kickstarter.libs.utils.RewardUtils import com.kickstarter.libs.utils.extensions.getDefaultLocationFrom +import com.kickstarter.libs.utils.extensions.isAllowedToPledge import com.kickstarter.libs.utils.extensions.isNotNull import com.kickstarter.models.Location import com.kickstarter.models.Project @@ -93,7 +94,7 @@ class GetShippingRulesUseCase( val avShipMap = allAvailableRulesForProject emitCurrentState(isLoading = true) - if (rewardsByShippingType.isNotEmpty()) { + if (rewardsByShippingType.isNotEmpty() && project.isAllowedToPledge()) { rewardsByShippingType.forEachIndexed { index, reward -> if (RewardUtils.shipsToRestrictedLocations(reward)) { @@ -119,12 +120,21 @@ class GetShippingRulesUseCase( filterRewardsByLocation(avShipMap, defaultShippingRule, projectRewards) } } - } else { + } + // - all rewards digital + if (rewardsByShippingType.isEmpty() && project.isAllowedToPledge()) { // - All rewards are digital, all rewards must be available filteredRewards.clear() filteredRewards.addAll(projectRewards) emitCurrentState(isLoading = false) } + + // - Just displaying all rewards available or not, project no collecting any longer + if (!project.isAllowedToPledge()) { + filteredRewards.clear() + filteredRewards.addAll(project.rewards() ?: emptyList()) + emitCurrentState(isLoading = false) + } } } diff --git a/app/src/test/java/com/kickstarter/libs/utils/extensions/ProjectExtTest.kt b/app/src/test/java/com/kickstarter/libs/utils/extensions/ProjectExtTest.kt index 3d1213bb74..479a394b88 100644 --- a/app/src/test/java/com/kickstarter/libs/utils/extensions/ProjectExtTest.kt +++ b/app/src/test/java/com/kickstarter/libs/utils/extensions/ProjectExtTest.kt @@ -418,4 +418,52 @@ class ProjectExtTest : KSRobolectricTestCase() { assertEquals(reducedProject.projectFaqs(), emptyList()) // Default builder value assertEquals(reducedProject.story(), "") // Default builder value } + + @Test + fun `test if a project is not allowed to collect pledges when has been funded and no late pledges`() { + val project = ProjectFactory.project() + .toBuilder() + .state(Project.STATE_SUCCESSFUL) + .isInPostCampaignPledgingPhase(false) + .postCampaignPledgingEnabled(false) + .build() + + assertFalse(project.isAllowedToPledge()) + } + + @Test + fun `test if a project is allowed to collect pledges when campaign is still ongoing`() { + val project = ProjectFactory.project() + .toBuilder() + .state(Project.STATE_LIVE) + .isInPostCampaignPledgingPhase(false) + .postCampaignPledgingEnabled(false) + .build() + + assertTrue(project.isAllowedToPledge()) + } + + @Test + fun `test if a project is allowed to collect pledges when has been funded but has late pledges enabled and it is collecting`() { + val project = ProjectFactory.project() + .toBuilder() + .state(Project.STATE_SUCCESSFUL) + .isInPostCampaignPledgingPhase(true) + .postCampaignPledgingEnabled(true) + .build() + + assertTrue(project.isAllowedToPledge()) + } + + @Test + fun `test if a project is not allowed to collect pledges when has been funded but has late pledges enabled but not collecting`() { + val project = ProjectFactory.project() + .toBuilder() + .state(Project.STATE_SUCCESSFUL) + .isInPostCampaignPledgingPhase(false) + .postCampaignPledgingEnabled(true) + .build() + + assertFalse(project.isAllowedToPledge()) + } } diff --git a/app/src/test/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCaseTest.kt b/app/src/test/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCaseTest.kt new file mode 100644 index 0000000000..8c83f68909 --- /dev/null +++ b/app/src/test/java/com/kickstarter/viewmodels/usecases/GetShippingRulesUseCaseTest.kt @@ -0,0 +1,94 @@ +package com.kickstarter.viewmodels.usecases + +import com.kickstarter.KSRobolectricTestCase +import com.kickstarter.mock.factories.ConfigFactory +import com.kickstarter.mock.factories.ProjectFactory +import com.kickstarter.mock.factories.RewardFactory +import com.kickstarter.mock.factories.ShippingRuleFactory +import com.kickstarter.mock.services.MockApolloClientV2 +import com.kickstarter.models.Project +import com.kickstarter.models.Reward +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class GetShippingRulesUseCaseTest : KSRobolectricTestCase() { + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `test useCase returns project reward list unfiltered when not collecting`() = runTest { + val apolloClient = MockApolloClientV2() + val config = ConfigFactory.configForCA() + val project = ProjectFactory.project() + .toBuilder() + .state(Project.STATE_SUCCESSFUL) + .isInPostCampaignPledgingPhase(false) + .postCampaignPledgingEnabled(false) + .build() + + val dispatcher = UnconfinedTestDispatcher(testScheduler) + val scope = backgroundScope + + val useCase = GetShippingRulesUseCase(apolloClient, project, config, scope, dispatcher) + + val state = mutableListOf() + scope.launch(dispatcher) { + useCase.invoke() + useCase.shippingRulesState.toList(state) + } + advanceUntilIdle() + + assertEquals(state.size, 2) + assertEquals(state.last().filteredRw, project.rewards()) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `test useCase returns project reward list filtered when collecting late pledges`() = runTest { + val apolloClient = MockApolloClientV2() + val config = ConfigFactory.configForUSUser() + + val shippingRule1 = ShippingRuleFactory.canadaShippingRule() + val shippingRule2 = ShippingRuleFactory.germanyShippingRule() + val shippingRule3 = ShippingRuleFactory.usShippingRule() + + val reward = RewardFactory.reward().toBuilder() + .shippingPreference(Reward.ShippingPreference.RESTRICTED.name) + .shippingType(Reward.SHIPPING_TYPE_MULTIPLE_LOCATIONS) + .isAvailable(true) + .shippingRules(listOf(shippingRule1)) + .build() + val reward2 = reward.toBuilder() + .shippingRules(listOf(shippingRule1, shippingRule2, shippingRule3)) + .build() + + val project = ProjectFactory.project() + .toBuilder() + .rewards(listOf(reward, reward2)) + .state(Project.STATE_SUCCESSFUL) + .isInPostCampaignPledgingPhase(true) + .postCampaignPledgingEnabled(true) + .build() + + val dispatcher = UnconfinedTestDispatcher(testScheduler) + val scope = backgroundScope + + val useCase = GetShippingRulesUseCase(apolloClient, project, config, scope, dispatcher) + + val state = mutableListOf() + scope.launch(dispatcher) { + useCase.invoke() + useCase.shippingRulesState.toList(state) + } + advanceUntilIdle() + + assertEquals(state.size, 2) + assertNotSame(state.last().filteredRw, project.rewards()) + assertEquals(state.last().filteredRw.size, 1) + assertEquals(state.last().filteredRw.first(), reward2) + } +}