Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[PAY-2030] Use cooldown_days from backend instead of hardcoding #6597

Merged
merged 10 commits into from
Nov 9, 2023
2 changes: 0 additions & 2 deletions packages/common/src/hooks/purchaseContent/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ export const AMOUNT_PRESET = 'amountPreset'
// Pay between $1 and $100 extra
export const minimumPayExtraAmountCents = 100
export const maximumPayExtraAmountCents = 10000

export const COOLDOWN_DAYS = 7
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import {
UndisbursedUserChallenge,
audioRewardsPageSelectors
} from 'store/pages'

import { COOLDOWN_DAYS } from './constants'
import { isCooldownChallengeClaimable, toLocalTime } from 'utils/challenges'

const { getUndisbursedUserChallenges } = audioRewardsPageSelectors

Expand All @@ -30,40 +29,45 @@ export const useChallengeCooldownSchedule = (
const challenges = useSelector(getUndisbursedUserChallenges)
.filter((c) => c.challenge_id === challengeId)
.map((c) => ({ ...c, createdAtDate: dayjs.utc(c.created_at) }))
const now = dayjs.utc()
// Only challenges past the cooldown period are claimable
const claimableAmount = challenges
.filter((c) => now.diff(c.createdAtDate, 'day') >= COOLDOWN_DAYS)
.reduce((acc, curr) => acc + curr.amount, 0)
// Challenges are already ordered by completed_blocknumber ascending.
const cooldownChallenges = challenges.filter(
(c) => now.diff(c.createdAtDate, 'day') < COOLDOWN_DAYS
(c) => !isCooldownChallengeClaimable(c)
)
return { claimableAmount, cooldownChallenges }
const claimableAmount = challenges
.filter(isCooldownChallengeClaimable)
dharit-tan marked this conversation as resolved.
Show resolved Hide resolved
.reduce((acc, curr) => acc + curr.amount, 0)
return { cooldownChallenges, claimableAmount }
}

const getAudioMatchingCooldownLabel = (now: Dayjs, created_at: Dayjs) => {
const diff = now.diff(created_at, 'day')
if (diff === COOLDOWN_DAYS) {
const getAudioMatchingCooldownLabel = (
challenge: UndisbursedUserChallenge,
now: Dayjs
) => {
const createdAt = toLocalTime(challenge.created_at)
const cooldownDays = challenge.cooldown_days ?? 0
const diff = now.diff(createdAt, 'day')
if (diff === cooldownDays) {
return messages.laterToday
} else if (diff === COOLDOWN_DAYS - 1) {
} else if (diff === cooldownDays - 1) {
return messages.tomorrow
}
return created_at.local().add(COOLDOWN_DAYS, 'day').format('ddd (M/D)')
return createdAt.add(cooldownDays, 'day').format('ddd (M/D)')
}

const formatAudioMatchingChallengeCooldownSchedule = (
const formatAudioMatchingChallengesForCooldownSchedule = (
challenges: UndisbursedUserChallenge[]
) => {
const now = dayjs.utc().endOf('day')
const cooldownChallenges = new Array(7)
if (challenges.length === 0) return []
const now = dayjs().endOf('day')
const cooldownChallenges = new Array(challenges[0].cooldown_days)
challenges.forEach((c) => {
const createdAtUTC = dayjs.utc(c.created_at)
const diff = now.diff(createdAtUTC, 'day')
const createdAt = toLocalTime(c.created_at)
const diff = now.diff(createdAt, 'day')
cooldownChallenges[diff] = {
...cooldownChallenges[diff],
id: c.specifier,
label: getAudioMatchingCooldownLabel(now, createdAtUTC),
label: getAudioMatchingCooldownLabel(c, now),
value: (cooldownChallenges[diff]?.value ?? 0) + c.amount
}
})
Expand All @@ -87,7 +91,7 @@ export const useAudioMatchingChallengeCooldownSchedule = (
return {
claimableAmount,
cooldownChallenges:
formatAudioMatchingChallengeCooldownSchedule(cooldownChallenges),
formatAudioMatchingChallengesForCooldownSchedule(cooldownChallenges),
cooldownChallengesSummary:
claimableAmount > 0
? getAudioMatchingChallengeCooldownSummary(claimableAmount)
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/store/pages/audio-rewards/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type UndisbursedUserChallenge = Pick<
handle: string
wallet: string
created_at: string
cooldown_days?: number
}

export enum HCaptchaStatus {
Expand Down
23 changes: 16 additions & 7 deletions packages/common/src/utils/challenges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,17 +249,20 @@ export const isAudioMatchingChallenge = (
)
}

// TODO: currently only $AUDIO matching challenges have cooldown
// so this works, but really we should check if `cooldown_period` exists on the
// challenge instead of using `!isAudioMatchingChallenge`. PAY-2030
/** Returns true if the challenge is not a cooldown challenge by checking
* whether it has `cooldown_days` defined and whether the challenge has been
* created for more than `cooldown_days` days.
*/
export const isCooldownChallengeClaimable = (
challenge: UndisbursedUserChallenge
) => {
return (
!isAudioMatchingChallenge(challenge.challenge_id) ||
dayjs.utc().diff(dayjs.utc(challenge.created_at), 'day') >= 7
challenge.cooldown_days === undefined ||
dayjs.utc().diff(dayjs.utc(challenge.created_at), 'day') >=
challenge.cooldown_days
)
}

/* Filter for only claimable challenges */
export const getClaimableChallengeSpecifiers = (
specifiers: SpecifierWithAmount[],
Expand All @@ -268,7 +271,13 @@ export const getClaimableChallengeSpecifiers = (
return specifiers.filter((s) => {
const challenge = undisbursedUserChallenges.filter(
(c) => c.specifier === s.specifier
)[0] // specifiers are unique
return isCooldownChallengeClaimable(challenge)
)
if (challenge.length === 0) return false
// specifiers are unique
return isCooldownChallengeClaimable(challenge[0])
})
}

export const toLocalTime = (date: string) => {
dharit-tan marked this conversation as resolved.
Show resolved Hide resolved
return dayjs.utc(date).local()
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def test_undisbursed_challenges(app):
"handle": "TestHandle6",
"wallet": "0x6",
"created_at": "2023-10-16 17:51:31.105065+00:00",
"cooldown_days": None,
},
{
"challenge_id": "test_challenge_2",
Expand All @@ -163,6 +164,7 @@ def test_undisbursed_challenges(app):
"handle": "TestHandle4",
"wallet": "0x4",
"created_at": "2023-10-16 17:51:31.105065+00:00",
"cooldown_days": None,
},
{
"challenge_id": "test_challenge_2",
Expand All @@ -173,6 +175,7 @@ def test_undisbursed_challenges(app):
"handle": "TestHandle5",
"wallet": "0x5",
"created_at": "2023-10-16 17:51:31.105065+00:00",
"cooldown_days": None,
},
]
assert expected == undisbursed
Expand All @@ -193,6 +196,7 @@ def test_undisbursed_challenges(app):
"handle": "TestHandle6",
"wallet": "0x6",
"created_at": "2023-10-16 17:51:31.105065+00:00",
"cooldown_days": None,
},
]
assert expected == undisbursed
Expand Down
1 change: 1 addition & 0 deletions packages/discovery-provider/src/api/v1/challenges.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ def get(self, challenge_id: str):
"starting_block": challenge.starting_block,
"weekly_pool": challenge.weekly_pool,
"weekly_pool_remaining": weekly_pool_remaining,
"cooldown_days": challenge.cooldown_days,
}
if (
weekly_pool_min_amount
Expand Down
2 changes: 2 additions & 0 deletions packages/discovery-provider/src/api/v1/models/challenges.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"handle": fields.String(required=True),
"wallet": fields.String(required=True),
"created_at": fields.String(required=True),
"cooldown_days": fields.Integer(required=False),
},
)

Expand All @@ -43,5 +44,6 @@
"starting_block": fields.Integer(required=False),
"weekly_pool": fields.String(required=False),
"weekly_pool_remaining": fields.String(required=False),
"cooldown_days": fields.Integer(required=False),
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class UndisbursedChallengeResponse(TypedDict):
handle: str
wallet: str
created_at: str
cooldown_days: Optional[int]


def to_challenge_response(
Expand All @@ -34,6 +35,7 @@ def to_challenge_response(
"handle": handle,
"wallet": wallet,
"created_at": str(user_challenge.created_at),
"cooldown_days": challenge.cooldown_days,
}


Expand Down