Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[NT-1584][NT-1588] Handling rewards and add ons with future start dates #1317

Merged
merged 2 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Library/SharedFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,27 @@ public func rewardsCarouselCanNavigateToReward(_ reward: Reward, in project: Pro
]
.allSatisfy(isTrue)
}

/**
Determines if a start date from a given reward/add on predates the current date.

- parameter reward: The reward being evaluated

- returns: A Bool representing whether the reward has a start date prior to the current date/time.
*/
public func isStartDateBeforeToday(for reward: Reward) -> Bool {
return (reward.startsAt == nil || (reward.startsAt ?? 0) <= AppEnvironment.current.dateType.init()
.timeIntervalSince1970)
}

/**
Determines if an end date from a given reward/add on is after the current date.

- parameter reward: The reward being evaluated

- returns: A Bool representing whether the reward has an end date after to the current date/time.
*/
public func isEndDateAfterToday(for reward: Reward) -> Bool {
return (reward.endsAt == nil || (reward.endsAt ?? 0) >= AppEnvironment.current.dateType.init()
.timeIntervalSince1970)
}
43 changes: 42 additions & 1 deletion Library/SharedFunctionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ final class SharedFunctionsTests: TestCase {
XCTAssertTrue(rewardsCarouselCanNavigateToReward(reward, in: project))
}


func testRewardsCarouselCanNavigateToReward_Reward_Unavailable_NotBacked_HasAddOns() {
let reward = Reward.template
|> Reward.lens.limit .~ 5
Expand Down Expand Up @@ -305,4 +304,46 @@ final class SharedFunctionsTests: TestCase {

XCTAssertTrue(rewardsCarouselCanNavigateToReward(reward, in: project))
}

func testIsStartDateBeforeToday_Reward_StartsAt_Nil() {
let reward = Reward.template
|> Reward.lens.startsAt .~ nil

XCTAssertTrue(isStartDateBeforeToday(for: reward))
}

func testIsStartDateBeforeToday_Reward_StartsAt_PastDate() {
let reward = Reward.template
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 - 60)

XCTAssertTrue(isStartDateBeforeToday(for: reward))
}

func testIsStartDateBeforeToday_Reward_StartsAt_FutureDate() {
let reward = Reward.template
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 + 60)

XCTAssertFalse(isStartDateBeforeToday(for: reward))
}

func testIsEndDateAfterToday_Reward_EndsAt_Nil() {
let reward = Reward.template
|> Reward.lens.endsAt .~ nil

XCTAssertTrue(isEndDateAfterToday(for: reward))
}

func testIsEndDateAfterToday_Reward_EndsAt_PastDate() {
let reward = Reward.template
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 - 60)

XCTAssertFalse(isEndDateAfterToday(for: reward))
}

func testIsEndDateAfterToday_Reward_EndsAt_FutureDate() {
let reward = Reward.template
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60)

XCTAssertTrue(isEndDateAfterToday(for: reward))
}
}
9 changes: 4 additions & 5 deletions Library/ViewModels/RewardAddOnSelectionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,13 @@ private func addOnIsAvailable(_ addOn: Reward, in project: Project) -> Bool {
}

let isUnlimitedOrAvailable = addOn.limit == nil || addOn.remaining ?? 0 > 0
let hasNoTimeLimitOrHasNotEnded = (
addOn.endsAt == nil ||
(addOn.endsAt ?? 0) >= AppEnvironment.current.dateType.init().timeIntervalSince1970
)

// Assuming the user has not backed the addOn, we only display if it's within range of the start and end date
let hasNoTimeLimitOrIsWithinRange = isStartDateBeforeToday(for: addOn) && isEndDateAfterToday(for: addOn)

return [
project.state == .live,
hasNoTimeLimitOrHasNotEnded,
hasNoTimeLimitOrIsWithinRange,
isUnlimitedOrAvailable
]
.allSatisfy(isTrue)
Expand Down
35 changes: 33 additions & 2 deletions Library/ViewModels/RewardAddOnSelectionViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -394,17 +394,48 @@ final class RewardAddOnSelectionViewModelTests: TestCase {
|> Reward.lens.limit .~ 5
|> Reward.lens.remaining .~ 2

// timebased add-on, starts in 60 seconds
let addOn7 = Reward.template
|> Reward.lens.id .~ 7
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 + 60)

// timebased add-on, started 60 seconds ago.
let addOn8 = Reward.template
|> Reward.lens.id .~ 8
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 - 60)

// timebased add-on, both startsAt and endsAt are within a valid range
let addOn9 = Reward.template
|> Reward.lens.id .~ 9
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 - 60)
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60)

// timebased add-on, invalid range
let addOn10 = Reward.template
|> Reward.lens.id .~ 10
|> Reward.lens.limit .~ nil
|> Reward.lens.remaining .~ nil
|> Reward.lens.startsAt .~ (MockDate().timeIntervalSince1970 + 30)
|> Reward.lens.endsAt .~ (MockDate().timeIntervalSince1970 + 60)

let project = Project.template
|> Project.lens.rewardData.rewards .~ [baseReward]
|> Project.lens.rewardData.addOns .~ [addOn1, addOn2, addOn3, addOn4, addOn5, addOn6]
|> Project.lens.rewardData
.addOns .~ [addOn1, addOn2, addOn3, addOn4, addOn5, addOn6, addOn7, addOn8, addOn9, addOn10]
|> Project.lens.personalization.backing .~ (
.template
|> Backing.lens.addOns .~ [addOn3]
|> Backing.lens.reward .~ baseReward
|> Backing.lens.rewardId .~ baseReward.id
)

let expectedAddOns = [addOn1, addOn3, addOn5, addOn6]
let expectedAddOns = [addOn1, addOn3, addOn5, addOn6, addOn8, addOn9]

let expected = expectedAddOns
.map { reward in
Expand Down
5 changes: 4 additions & 1 deletion Library/ViewModels/RewardsCollectionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ public final class RewardsCollectionViewModel: RewardsCollectionViewModelType,

self.reloadDataWithValues = Signal.combineLatest(project, rewards)
.map { project, rewards in
rewards.map { reward in (project, reward, .pledge) }
rewards.filter { reward in isStartDateBeforeToday(for: reward) }
.map { reward in (project, reward, .pledge) }
}

self.configureRewardsCollectionViewFooterWithCount = self.reloadDataWithValues
Expand Down Expand Up @@ -255,6 +256,8 @@ public final class RewardsCollectionViewModel: RewardsCollectionViewModelType,
public var outputs: RewardsCollectionViewModelOutputs { return self }
}

// MARK: - Functions

private func titleForContext(_ context: RewardsCollectionViewContext, project: Project) -> String {
if currentUserIsCreator(of: project) {
return Strings.View_your_rewards()
Expand Down