Skip to content

Commit

Permalink
[C-4080] Mobile cooldown and claim all (#8263)
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacsolo committed May 1, 2024
1 parent 80cca19 commit 22280c6
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 122 deletions.
2 changes: 2 additions & 0 deletions packages/mobile/src/app/Drawers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AudioBreakdownDrawer } from 'app/components/audio-breakdown-drawer'
import { TiersExplainerDrawer } from 'app/components/audio-rewards'
import { BlockMessagesDrawer } from 'app/components/block-messages-drawer'
import { ChallengeRewardsDrawer } from 'app/components/challenge-rewards-drawer'
import { ClaimAllRewardsDrawer } from 'app/components/challenge-rewards-drawer/ClaimAllRewardsDrawer'
import { ChatActionsDrawer } from 'app/components/chat-actions-drawer'
import { CoinflowOnrampDrawer } from 'app/components/coinflow-onramp-drawer/CoinflowOnrampDrawer'
import { CollectibleDetailsDrawer } from 'app/components/collectible-details-drawer'
Expand Down Expand Up @@ -96,6 +97,7 @@ const commonDrawersMap: { [Modal in Modals]?: ComponentType } = {
TiersExplainer: TiersExplainerDrawer,
TrendingRewardsExplainer: TrendingRewardsDrawer,
ChallengeRewardsExplainer: ChallengeRewardsDrawer,
ClaimAllRewards: ClaimAllRewardsDrawer,
APIRewardsExplainer: ApiRewardsDrawer,
TransferAudioMobileWarning: TransferAudioMobileDrawer,
MobileEditCollectiblesDrawer: EditCollectiblesDrawer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import type { ReactNode } from 'react'

import { useFeatureFlag } from '@audius/common/hooks'
import { FeatureFlags } from '@audius/common/services'
import { View } from 'react-native'

import { Text } from 'app/components/core'
import { Flex, Text } from '@audius/harmony-native'

import { useStyles } from './styles'
const messages = {
task: 'Task Details'
task: 'Task Details',
cooldownDescription:
'Note: There is a 7 day waiting period from completion until you can claim your reward.'
}

type DescriptionContent =
Expand All @@ -33,16 +37,19 @@ export const ChallengeDescription = ({
description,
renderDescription
}: ChallengeDescriptionProps) => {
const { isEnabled: isRewardsCooldownEnabled } = useFeatureFlag(
FeatureFlags.REWARDS_COOLDOWN
)

const styles = useStyles()
return (
<View style={styles.task}>
<View style={styles.taskHeader}>
{taskIcon}
<Text
variant='label'
fontSize='medium'
style={styles.subheader}
weight='heavy'
strength='strong'
textTransform='uppercase'
>
{task}
Expand All @@ -51,7 +58,14 @@ export const ChallengeDescription = ({
{renderDescription ? (
renderDescription()
) : (
<Text variant='body'>{description}</Text>
<Flex gap='m' mb='l'>
<Text variant='body'>{description}</Text>
{isRewardsCooldownEnabled ? (
<Text variant='body' color='subdued'>
{messages.cooldownDescription}
</Text>
) : null}
</Flex>
)}
</View>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import React from 'react'

import type { UserChallengeState } from '@audius/common/models'
import {
formatCooldownChallenges,
useChallengeCooldownSchedule,
useFeatureFlag
} from '@audius/common/hooks'
import type {
ChallengeRewardID,
UserChallengeState
} from '@audius/common/models'
import { FeatureFlags } from '@audius/common/services'
import { ClaimStatus } from '@audius/common/store'
import { fillString, formatNumberCommas } from '@audius/common/utils'
import { View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'

import { IconCheck, IconVerified } from '@audius/harmony-native'
import Button, { ButtonType } from 'app/components/button'
import { Text } from 'app/components/core'
import LoadingSpinner from 'app/components/loading-spinner'
import {
Text,
Button,
IconArrowRight,
IconCheck,
IconVerified
} from '@audius/harmony-native'
import { ProgressBar } from 'app/components/progress-bar'
import { formatLabel } from 'app/utils/challenges'
import { useThemePalette } from 'app/utils/theme'

import { SummaryTable } from '../summary-table'

import { ChallengeDescription } from './ChallengeDescription'
import { ChallengeReward } from './ChallengeReward'
import { ClaimError } from './ClaimError'
Expand All @@ -25,7 +41,9 @@ const messages = {
complete: 'Complete',
claim: 'Claim This Reward',
claimableLabel: '$AUDIO available to claim',
claimedLabel: '$AUDIO claimed so far'
claimableAmountLabel: (amount) => `Claim ${amount} $AUDIO`,
claimedLabel: '$AUDIO claimed so far',
upcomingRewards: 'Upcoming Rewards'
}

type ChallengeRewardsDrawerContentProps = {
Expand Down Expand Up @@ -55,6 +73,10 @@ type ChallengeRewardsDrawerContentProps = {
/** True if the challenge type is 'aggregate' */
showProgressBar: boolean
children?: React.ReactChild
/** The identifier for the challenge type */
challengeId: ChallengeRewardID
/** True if challenge has a cooldown */
isCooldownChallenge: boolean
}

/** Generic drawer content used for most challenges, responsible for rendering the
Expand All @@ -66,6 +88,8 @@ export const ChallengeRewardsDrawerContent = ({
currentStep,
stepCount = 1,
progressLabel,
challengeId,
isCooldownChallenge,
challengeState,
claimableAmount,
claimedAmount,
Expand All @@ -79,6 +103,16 @@ export const ChallengeRewardsDrawerContent = ({
const styles = useStyles()
const palette = useThemePalette()
const isInProgress = challengeState === 'in_progress'
const isClaimable = claimableAmount > 0
const {
cooldownChallenges,
summary,
isEmpty: isCooldownChallengesEmpty
} = useChallengeCooldownSchedule({ challengeId })
const { isEnabled: isRewardsCooldownEnabled } = useFeatureFlag(
FeatureFlags.REWARDS_COOLDOWN
)

const claimInProgress =
claimStatus === ClaimStatus.CLAIMING ||
claimStatus === ClaimStatus.WAITING_FOR_RETRY
Expand All @@ -103,97 +137,140 @@ export const ChallengeRewardsDrawerContent = ({
messages.claimableLabel
}`

return (
<View style={styles.content}>
{isVerifiedChallenge ? (
<ChallengeDescription
task={messages.taskVerified}
taskIcon={
<IconVerified
style={styles.subheaderIcon}
fill={palette.staticPrimary}
fillSecondary={palette.staticWhite}
/>
}
description={description}
const renderCooldownSummaryTable = () => {
if (isCooldownChallenge && !isCooldownChallengesEmpty) {
return (
<SummaryTable
title={messages.upcomingRewards}
items={formatCooldownChallenges(cooldownChallenges).map(formatLabel)}
summaryItem={summary}
secondaryTitle={messages.audio}
summaryLabelColor='accent'
summaryValueColor='default'
/>
) : (
<ChallengeDescription description={description} />
)}
<View style={styles.statusGrid}>
<View style={styles.statusGridColumns}>
<ChallengeReward amount={amount} subtext={messages.audio} />
{showProgressBar ? (
<View style={styles.progressCell}>
<Text
color='neutralLight4'
style={[styles.subheader, styles.progressSubheader]}
weight='heavy'
textTransform='uppercase'
>
{messages.progress}
</Text>
<ProgressBar progress={currentStep} max={stepCount} />
</View>
) : null}
</View>
<View
style={[
styles.statusCell,
hasCompleted ? styles.statusCellComplete : null
]}
>
<Text
)
}
return null
}

return (
<>
<ScrollView style={styles.content}>
{isVerifiedChallenge ? (
<ChallengeDescription
task={messages.taskVerified}
taskIcon={
<IconVerified
style={styles.subheaderIcon}
fill={palette.staticPrimary}
fillSecondary={palette.staticWhite}
/>
}
description={description}
/>
) : (
<ChallengeDescription description={description} />
)}
<View style={styles.statusGrid}>
<View style={styles.statusGridColumns}>
<ChallengeReward amount={amount} subtext={messages.audio} />
{showProgressBar ? (
<View style={styles.progressCell}>
<Text
color='subdued'
style={[styles.subheader, styles.progressSubheader]}
strength='strong'
textTransform='uppercase'
variant='label'
size='l'
>
{messages.progress}
</Text>
<ProgressBar progress={currentStep} max={stepCount} />
</View>
) : null}
</View>
<View
style={[
styles.subheader,
hasCompleted ? styles.statusTextComplete : null,
isInProgress ? styles.statusTextInProgress : null
styles.statusCell,
hasCompleted ? styles.statusCellComplete : null
]}
weight='heavy'
textTransform='uppercase'
>
{statusText}
</Text>
<Text
style={[styles.subheader]}
strength='strong'
textTransform='uppercase'
variant='label'
color={
hasCompleted
? 'staticWhite'
: isInProgress
? 'accent'
: 'default'
}
>
{statusText}
</Text>
</View>
</View>
</View>
{children}
<View style={styles.claimRewardsContainer}>
{claimableAmount > 0 && onClaim
? [
<Text
key='claimableAmount'
style={styles.claimableAmount}
weight='heavy'
textTransform='uppercase'
>
{claimableAmountText}
</Text>,
<Button
key='claimButton'
containerStyle={styles.claimButtonContainer}
style={styles.claimButton}
type={claimInProgress ? ButtonType.COMMON : ButtonType.PRIMARY}
disabled={claimInProgress}
title={messages.claim}
onPress={onClaim}
renderIcon={(color) =>
claimInProgress ? (
<LoadingSpinner />
) : (
<IconCheck fill={color} />
)
}
iconPosition='left'
/>
]
: null}
{claimedAmount > 0 && challengeState !== 'disbursed' ? (
<Text style={styles.claimedAmount} weight='heavy'>
{claimedAmountText}
</Text>
) : null}
{claimError ? <ClaimError aaoErrorCode={aaoErrorCode} /> : null}
</View>
</View>
{children}
<View style={styles.claimRewardsContainer}>
{isClaimable && onClaim ? (
isCooldownChallenge && isRewardsCooldownEnabled ? (
renderCooldownSummaryTable()
) : (
<>
<Text
key='claimableAmount'
style={styles.claimableAmount}
variant='label'
strength='strong'
textTransform='uppercase'
>
{claimableAmountText}
</Text>
<Button
style={styles.claimButton}
variant={claimInProgress ? 'secondary' : 'primary'}
isLoading={claimInProgress}
onPress={onClaim}
iconLeft={IconCheck}
>
{messages.claim}
</Button>
</>
)
) : null}
{claimedAmount > 0 && challengeState !== 'disbursed' ? (
<Text
variant='label'
color='subdued'
textAlign='center'
strength='strong'
>
{claimedAmountText}
</Text>
) : null}
{claimError ? <ClaimError aaoErrorCode={aaoErrorCode} /> : null}
</View>
</ScrollView>
{isClaimable &&
onClaim &&
isCooldownChallenge &&
isRewardsCooldownEnabled ? (
<View style={styles.stickyClaimRewardsContainer}>
<Button
key='claimButton'
style={styles.claimButton}
variant={claimInProgress ? 'secondary' : 'primary'}
isLoading={claimInProgress}
onPress={onClaim}
iconRight={IconArrowRight}
>
{messages.claimableAmountLabel(claimableAmount)}
</Button>
</View>
) : null}
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ export const ChallengeRewardsDrawerProvider = () => {
description={config.description(challenge)}
progressLabel={config.progressLabel ?? 'Completed'}
amount={challenge.totalAmount}
challengeId={challenge.challenge_id}
isCooldownChallenge={challenge && challenge.cooldown_days > 0}
challengeState={challenge.state}
currentStep={challenge.current_step_count}
stepCount={challenge.max_steps}
Expand Down

0 comments on commit 22280c6

Please sign in to comment.