Skip to content

Commit

Permalink
MBL-1893 && MBL-1877: Separate rewards from project query (#2173)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang authored Nov 26, 2024
1 parent 952fef2 commit 9975252
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 89 deletions.
20 changes: 1 addition & 19 deletions app/src/main/graphql/fragments.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -104,27 +104,9 @@ fragment fullProject on Project {
prelaunchActivated
...tagsCreative
...tagsDiscovery
rewards {
rewards { # query within project the bare minimum for rewards
nodes {
... reward
allowedAddons {
pageInfo {
startCursor
}
}
items {
... rewardItems
}
... on Reward {
simpleShippingRulesExpanded {
cost
country
estimatedMax
estimatedMin
locationId
locationName
}
}
}
}
risks
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/graphql/project.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@ query FetchProject($slug: String!) {
}
}

query FetchProjectRewards($slug: String!) {
project(slug: $slug) {
minPledge
rewards {
nodes {
... reward
allowedAddons {
pageInfo {
startCursor
}
}
items {
... rewardItems
}
simpleShippingRulesExpanded {
cost
country
estimatedMax
estimatedMin
locationId
locationName
}
}
}
}
}

query ProjectCreatorDetails($slug: String!) {
project(slug: $slug) {
creator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fun PledgeData.shippingCostIfShipping(): Double {
var addOnsShippingCost = 0.0
this.addOns()?.map {
if (RewardUtils.shipsWorldwide(it) || RewardUtils.shipsToRestrictedLocations(it)) {
addOnsShippingCost += (it.shippingRules()?.first()?.cost() ?: 0.0) * (it.quantity() ?: 0)
addOnsShippingCost += (it.shippingRules()?.firstOrNull()?.cost() ?: 0.0) * (it.quantity() ?: 0)
} else 0.0
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ import java.util.Collections

open class MockApolloClientV2 : ApolloClientTypeV2 {

override fun getRewardsFromProject(slug: String): io.reactivex.Observable<List<Reward>> {
return io.reactivex.Observable.just(emptyList())
}

override fun watchProject(project: Project): io.reactivex.Observable<Project> {
return io.reactivex.Observable.just(project.toBuilder().isStarred(true).build())
}
Expand Down
42 changes: 42 additions & 0 deletions app/src/main/java/com/kickstarter/services/KSApolloClientV2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import DeletePaymentSourceMutation
import ErroredBackingsQuery
import FetchCategoryQuery
import FetchProjectQuery
import FetchProjectRewardsQuery
import FetchProjectsQuery
import GetBackingQuery
import GetCommentQuery
Expand Down Expand Up @@ -52,6 +53,7 @@ import com.kickstarter.features.pledgedprojectsoverview.data.PledgedProjectsOver
import com.kickstarter.libs.utils.extensions.isNotNull
import com.kickstarter.libs.utils.extensions.toBoolean
import com.kickstarter.libs.utils.extensions.toProjectSort
import com.kickstarter.mock.factories.RewardFactory
import com.kickstarter.models.Backing
import com.kickstarter.models.Category
import com.kickstarter.models.Checkout
Expand Down Expand Up @@ -208,6 +210,7 @@ interface ApolloClientTypeV2 {
fun createOrUpdateBackingAddress(eventInput: CreateOrUpdateBackingAddressData): Observable<Boolean>
fun completeOrder(orderInput: CompleteOrderInput): Observable<CompleteOrderPayload>
fun getPledgedProjectsOverviewPledges(inputData: PledgedProjectsOverviewQueryData): Observable<PledgedProjectsOverviewEnvelope>
fun getRewardsFromProject(slug: String): Observable<List<Reward>>
}

private const val PAGE_SIZE = 25
Expand Down Expand Up @@ -714,6 +717,45 @@ class KSApolloClientV2(val service: ApolloClient, val gson: Gson) : ApolloClient
}.subscribeOn(Schedulers.io())
}

override fun getRewardsFromProject(slug: String): Observable<List<Reward>> {
return Observable.defer {
val ps = PublishSubject.create<List<Reward>>()
val query = FetchProjectRewardsQuery.builder()
.slug(slug)
.build()

this.service.query(query)
.enqueue(object : ApolloCall.Callback<FetchProjectRewardsQuery.Data>() {
override fun onFailure(e: ApolloException) {
ps.onError(e)
}

override fun onResponse(response: Response<FetchProjectRewardsQuery.Data>) {
if (response.hasErrors()) {
ps.onError(Exception(response.errors?.first()?.message))
}
response.data?.let { data ->
val rwList = data.project()?.rewards()?.nodes()?.map {
rewardTransformer(
rewardGr = it.fragments().reward(),
allowedAddons = it.allowedAddons().pageInfo().startCursor()?.isNotEmpty() ?: false,
rewardItems = complexRewardItemsTransformer(it.items()?.fragments()?.rewardItems()),
simpleShippingRules = it.simpleShippingRulesExpanded()
)
} ?: emptyList()
// - API does not provide the Reward no reward, we need to add it first
val minPledge = data.project()?.minPledge()?.toDouble() ?: 1.0
val modifiedRewards = rwList.toMutableList()
modifiedRewards.add(0, RewardFactory.noReward().toBuilder().minimum(minPledge).build())
ps.onNext(modifiedRewards.toList())
}
ps.onComplete()
}
})
return@defer ps
}
}

private fun getAddOnsFromProject(addOnsGr: GetProjectAddOnsQuery.AddOns): List<Reward> {
return addOnsGr.nodes()?.map { node ->
val shippingRulesGr =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ fun environmentalCommitmentTransformer(envCommit: fragment.EnvironmentalCommitme
fun rewardTransformer(
rewardGr: fragment.Reward,
shippingRulesExpanded: List<fragment.ShippingRule> = emptyList(),
simpleShippingRules: List<FullProject.SimpleShippingRulesExpanded> = emptyList(),
simpleShippingRules: List<FetchProjectRewardsQuery.SimpleShippingRulesExpanded> = emptyList(),
allowedAddons: Boolean = false,
rewardItems: List<RewardsItem> = emptyList(),
addOnItems: List<RewardsItem> = emptyList()
Expand Down Expand Up @@ -198,7 +198,7 @@ fun rewardTransformer(
.build()
}

fun simpleShippingRuleTransformer(simpleShippingRules: FullProject.SimpleShippingRulesExpanded): ShippingRule {
fun simpleShippingRuleTransformer(simpleShippingRules: FetchProjectRewardsQuery.SimpleShippingRulesExpanded): ShippingRule {
val id = decodeRelayId(simpleShippingRules.locationId()) ?: -1
val country = simpleShippingRules.country() ?: ""
val displayName = simpleShippingRules.locationName()
Expand Down Expand Up @@ -327,12 +327,8 @@ fun projectTransformer(projectFragment: FullProject?): Project {
val minPledge = projectFragment?.minPledge()?.toDouble() ?: 1.0
val rewards =
projectFragment?.rewards()?.nodes()?.map {
val shippingRules = it.simpleShippingRulesExpanded()
rewardTransformer(
it.fragments().reward(),
simpleShippingRules = shippingRules,
allowedAddons = it.allowedAddons().pageInfo().startCursor()?.isNotEmpty() ?: false,
rewardItems = complexRewardItemsTransformer(it.items()?.fragments()?.rewardItems())
it.fragments().reward()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ fun RewardCarouselScreen(
id = R.string.Back_it_because_you_believe_in_it
),
onRewardSelectClicked = { onRewardSelected(reward) },
isCTAButtonVisible = project.isAllowedToPledge()
isCTAButtonVisible = project.isAllowedToPledge(),
yourSelectionIsVisible = project.backing()?.isBacked(reward) ?: false,
)
} else {
KSRewardCard(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ class AddOnsViewModel(val environment: Environment, bundle: Bundle? = null) : Vi
bonusAmount = b.amount()
} else {
backedAddOns = b.addOns() ?: emptyList()
currentUserReward = b.reward() ?: currentUserReward
bonusAmount = b.bonusAmount()
}
}
Expand Down Expand Up @@ -229,10 +228,14 @@ class AddOnsViewModel(val environment: Environment, bundle: Bundle? = null) : Vi
holder[it.id()] = it
}

// Take the backed AddOns, update with the backed AddOn information which will contain the backed quantity
backedAddOns.map {
holder[it.id()] = it
currentSelection[it.id()] = it.quantity() ?: 0
// Take the backed AddOns, update with matching addOn ID with the quantity information
backedAddOns.map { backedAddOn ->
val aux = holder[backedAddOn.id()]
if (aux != null) {
val updated = aux.toBuilder().quantity(backedAddOn.quantity()).build()
holder[backedAddOn.id()] = updated
}
currentSelection[backedAddOn.id()] = backedAddOn.quantity() ?: 0
}

return holder.values.toList()
Expand Down Expand Up @@ -278,7 +281,7 @@ class AddOnsViewModel(val environment: Environment, bundle: Bundle? = null) : Vi
val selectedAddOns = mutableListOf<Reward>()
addOns.forEach {
val amount = currentSelection[it.id()]
if (amount != null) {
if (amount != null && amount > 0) {
selectedAddOns.add(it.toBuilder().quantity(amount).build())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ class CrowdfundCheckoutViewModel(val environment: Environment, bundle: Bundle? =
fun provideBundle(arguments: Bundle?) {
val pData = arguments?.getParcelable(ArgumentsKey.PLEDGE_PLEDGE_DATA) as PledgeData?
pledgeReason = arguments?.getSerializable(ArgumentsKey.PLEDGE_PLEDGE_REASON) as PledgeReason?
val flowContext = pledgeReason?.let { PledgeFlowContext.forPledgeReason(it) }

if (pData != null) {
pledgeData = pData
Expand All @@ -158,12 +157,11 @@ class CrowdfundCheckoutViewModel(val environment: Environment, bundle: Bundle? =
sharedPreferences
)

when (flowContext) {
PledgeFlowContext.NEW_PLEDGE,
PledgeFlowContext.CHANGE_REWARD -> getPledgeInfoFrom(pData)
PledgeFlowContext.MANAGE_REWARD,
PledgeFlowContext.FIX_ERRORED_PLEDGE
-> {
when (pledgeReason) {
PledgeReason.PLEDGE,
PledgeReason.UPDATE_REWARD -> getPledgeInfoFrom(pData)
PledgeReason.UPDATE_PAYMENT,
PledgeReason.FIX_PLEDGE -> {
backing?.let { getPledgeInfoFrom(it) }
}
else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,6 @@ interface ProjectPageViewModel {
.addToDisposable(disposables)

this.updatePledgeData
.distinctUntilChanged()
.subscribe {
this.showUpdatePledge.onNext(it)
}.addToDisposable(disposables)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,25 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx2.asFlow

data class RewardSelectionUIState(
val selectedReward: Reward = Reward.builder().build(),
val initialRewardIndex: Int = 0,
val project: ProjectData = ProjectData.builder().build(),
val project: ProjectData = ProjectData.builder().build()
)

class RewardsSelectionViewModel(private val environment: Environment, private var shippingRulesUseCase: GetShippingRulesUseCase? = null) : ViewModel() {

private val analytics = requireNotNull(environment.analytics())
private val apolloClient = requireNotNull(environment.apolloClientV2())
private val currentConfig = requireNotNull(environment.currentConfigV2()?.observable())

private lateinit var currentProjectData: ProjectData
private var pReason: PledgeReason? = null
Expand Down Expand Up @@ -83,26 +87,30 @@ class RewardsSelectionViewModel(private val environment: Environment, private va
indexOfBackedReward = indexOfBackedReward(project = projectData.project())
pReason = when {
previousUserBacking == null && projectData.project().isInPostCampaignPledgingPhase() == true -> PledgeReason.LATE_PLEDGE
previousUserBacking != null -> PledgeReason.UPDATE_PLEDGE
previousUserBacking != null -> PledgeReason.UPDATE_REWARD
previousUserBacking == null && projectData.project().isInPostCampaignPledgingPhase() == false -> PledgeReason.PLEDGE
else -> PledgeReason.PLEDGE
}

val project = projectData.project()
viewModelScope.launch {
emitCurrentState()
environment.currentConfigV2()?.observable()?.asFlow()?.collectLatest {
if (shippingRulesUseCase == null) {
shippingRulesUseCase = GetShippingRulesUseCase(
projectData.project(),
it,
viewModelScope,
Dispatchers.IO
)
apolloClient.getRewardsFromProject(project.slug() ?: "")
.asFlow()
.combine(currentConfig.asFlow()) { rewardsList, config ->
if (shippingRulesUseCase == null) {
shippingRulesUseCase = GetShippingRulesUseCase(
project = projectData.project(),
config = config,
projectRewards = rewardsList,
viewModelScope,
Dispatchers.IO
)
}
shippingRulesUseCase?.invoke()
emitShippingUIState()
}
shippingRulesUseCase?.invoke()

emitShippingUIState()
}
.catch { }
.collect()
}
}

Expand Down Expand Up @@ -209,7 +217,7 @@ class RewardsSelectionViewModel(private val environment: Environment, private va
fun shouldShowAlert(): Boolean {
val prevRw = previousUserBacking?.reward()
prevRw?.let {
if (pReason == PledgeReason.UPDATE_PLEDGE) {
if (pReason == PledgeReason.UPDATE_REWARD) {
return !previousUserBacking?.addOns().isNullOrEmpty() && prevRw.id() != newUserReward.id()
}
}
Expand Down
Loading

0 comments on commit 9975252

Please sign in to comment.