Skip to content

Commit

Permalink
[MBL-1317] Show Rewards Based on Reward.isAvailable (#2014)
Browse files Browse the repository at this point in the history
* use isAvailable property on the reward model to render rewards

* update Library tests

* update snapshot tests

* oops missed a line when committing

* hopefully fixing snapshots

* set rewards availability to false in failing tests

* This is ok because we're testing that updated values don't impact whether rewards are shown or now. Just that they are shown with the correct data

* undo ProjectTemplate changes

* snapshots need to include Rewards screen title

* formatting

* Re-record snapshots

---------

Co-authored-by: Ingerid Fosli <i.fosli@kickstarter.com>
  • Loading branch information
scottkicks and ifosli committed Apr 4, 2024
1 parent 4b90a3d commit fd1a221
Show file tree
Hide file tree
Showing 14 changed files with 71 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ final class RewardsCollectionViewControllerTests: TestCase {
let reward = Reward.template
|> Reward.lens.shipping.preference .~ .local
|> Reward.lens.localPickup .~ .canada
|> Reward.lens.isAvailable .~ true

let project = Project.cosmicSurgery
|> Project.lens.state .~ .live
Expand All @@ -123,6 +124,7 @@ final class RewardsCollectionViewControllerTests: TestCase {
let reward = Reward.template
|> Reward.lens.shipping.preference .~ .local
|> Reward.lens.localPickup .~ .canada
|> Reward.lens.isAvailable .~ true

let project = Project.cosmicSurgery
|> Project.lens.state .~ .live
Expand All @@ -148,6 +150,7 @@ final class RewardsCollectionViewControllerTests: TestCase {
let reward = Reward.template
|> Reward.lens.shipping.preference .~ .local
|> Reward.lens.localPickup .~ .canada
|> Reward.lens.isAvailable .~ true

let project = Project.cosmicSurgery
|> Project.lens.state .~ .live
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -428,29 +428,35 @@ let allRewards: [(String, Reward)] = {
|> Reward.lens.hasAddOns .~ true
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.isAvailable .~ true
let availableLimitedReward = Reward.postcards
|> Reward.lens.limit .~ 100
|> Reward.lens.remaining .~ 25
|> Reward.lens.convertedMinimum .~ 7.0
|> Reward.lens.isAvailable .~ true
let availableTimebasedReward = Reward.postcards
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.convertedMinimum .~ 7.0
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0)
|> Reward.lens.isAvailable .~ true
let availableLimitedTimebasedReward = Reward.postcards
|> Reward.lens.limit .~ 100
|> Reward.lens.remaining .~ 25
|> Reward.lens.convertedMinimum .~ 7.0
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0)
|> Reward.lens.isAvailable .~ true
let availableNonLimitedReward = Reward.postcards
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.endsAt .~ nil
|> Reward.lens.convertedMinimum .~ 7.0
|> Reward.lens.isAvailable .~ true
let availableShippingEnabledReward = Reward.postcards
|> Reward.lens.limit .~ 100
|> Reward.lens.remaining .~ 25
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60.0 * 60.0 * 24.0)
|> Reward.lens.isAvailable .~ true
|> Reward.lens.convertedMinimum .~ 7.0
|> Reward.lens.shipping .~ (
.template
Expand Down
25 changes: 16 additions & 9 deletions Kickstarter-iOS/Library/SharedFunctionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,12 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ nil

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), nil)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand All @@ -325,6 +326,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ (
Expand All @@ -333,7 +335,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Backing.lens.rewardId .~ reward.id
)

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), nil)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand All @@ -343,11 +345,12 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.limit .~ 5
|> Reward.lens.remaining .~ 0
|> Reward.lens.isAvailable .~ false
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ nil

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), false)
XCTAssertEqual(rewardIsAvailable(reward), false)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), 0)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand All @@ -357,6 +360,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.limit .~ 5
|> Reward.lens.remaining .~ 0
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ (
Expand All @@ -366,7 +370,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Backing.lens.rewardId .~ reward.id
)

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), 1)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand All @@ -376,6 +380,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limitPerBacker .~ 5
|> Reward.lens.limit .~ 4
|> Reward.lens.remaining .~ 0
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.addOns .~ [reward]
|> Project.lens.personalization.backing .~ (
Expand All @@ -384,7 +389,7 @@ internal final class SharedFunctionsTests: TestCase {
|> Backing.lens.addOns .~ [reward, reward] // qty 2
)

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), 2)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), 2)
}
Expand All @@ -394,12 +399,12 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limitPerBacker .~ 5
|> Reward.lens.limit .~ 15
|> Reward.lens.remaining .~ 4
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.addOns .~ [reward]
|> Project.lens.personalization.backing .~ nil

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), 4)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), 4)
}
Expand All @@ -410,11 +415,12 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.isAvailable .~ true
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ nil

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), true)
XCTAssertEqual(rewardIsAvailable(reward), true)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), nil)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand All @@ -425,11 +431,12 @@ internal final class SharedFunctionsTests: TestCase {
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.limitPerBacker .~ nil
|> Reward.lens.isAvailable .~ false
let project = Project.template
|> Project.lens.rewardData.rewards .~ [reward]
|> Project.lens.personalization.backing .~ nil

XCTAssertEqual(rewardIsAvailable(project: project, reward: reward), false)
XCTAssertEqual(rewardIsAvailable(reward), false)
XCTAssertEqual(rewardLimitRemainingForBacker(project: project, reward: reward), nil)
XCTAssertEqual(rewardLimitPerBackerRemainingForBacker(project: project, reward: reward), nil)
}
Expand Down
38 changes: 19 additions & 19 deletions KsApi/models/lenses/RewardLenses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -51,7 +51,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $0,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -77,7 +77,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -103,7 +103,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -129,7 +129,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -155,7 +155,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -181,7 +181,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -207,7 +207,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -233,7 +233,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -259,7 +259,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -285,7 +285,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -311,7 +311,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -337,7 +337,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -363,7 +363,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -389,7 +389,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -415,7 +415,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -441,7 +441,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -467,7 +467,7 @@ extension Reward {
startsAt: $0,
title: $1.title,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand All @@ -493,7 +493,7 @@ extension Reward {
startsAt: $1.startsAt,
title: $0,
localPickup: $1.localPickup,
isAvailable: nil
isAvailable: $1.isAvailable
) }
)

Expand Down
26 changes: 3 additions & 23 deletions Library/SharedFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,28 +279,8 @@ public func isNativeRiskMessagingControlEnabled() -> Bool {
return true
}

public func rewardIsAvailable(project: Project, reward: Reward) -> Bool {
let isLimited = reward.isLimitedQuantity
let isTimebased = reward.isLimitedTime

guard isLimited || isTimebased else { return true }

let remainingQty = rewardLimitRemainingForBacker(project: project, reward: reward)
let isRemaining = remainingQty == nil || (remainingQty ?? 0) > 0

let now = AppEnvironment.current.dateType.init().timeIntervalSince1970
let endsAt = reward.endsAt.coalesceWith(now)
let timeLimitNotReached = endsAt > now

// Limited availability is valid if the reward is limited and remaining > 0 OR this reward is not limited.
let limitedAvailabilityValid = (isLimited && isRemaining) || !isLimited

// Timebased availability is valid if the reward is timebased and the time limit has not been reached
// OR the reward is not timebased.
let timebasedAvailabilityValid = (isTimebased && timeLimitNotReached) || !isTimebased

// Both types of availability must be valid in order for this reward to be considered available.
return limitedAvailabilityValid && timebasedAvailabilityValid
public func rewardIsAvailable(_ reward: Reward) -> Bool {
reward.isAvailable == true || reward.isNoReward
}

public func rewardLimitRemainingForBacker(project: Project, reward: Reward) -> Int? {
Expand Down Expand Up @@ -377,7 +357,7 @@ public func rewardsCarouselCanNavigateToReward(_ reward: Reward, in project: Pro
guard !currentUserIsCreator(of: project) else { return false }

let isBacking = userIsBacking(reward: reward, inProject: project)
let isAvailableForNewBacker = rewardIsAvailable(project: project, reward: reward) && !isBacking
let isAvailableForNewBacker = rewardIsAvailable(reward) && !isBacking
let isAvailableForExistingBackerToEdit = (isBacking && reward.hasAddOns)

if featurePostCampaignPledgeEnabled(), project.isInPostCampaignPledgingPhase {
Expand Down

0 comments on commit fd1a221

Please sign in to comment.