-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #681 from dappforce/deploy/epic
Improvements
- Loading branch information
Showing
50 changed files
with
4,882 additions
and
265 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
src/components/modals/DailyRewardModal/RewardAnimation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import PresentAnimation from '@/assets/animations/present.json' | ||
import Diamond from '@/assets/emojis/diamond.png' | ||
import { GetDailyRewardQuery } from '@/services/datahub/generated-query' | ||
import { cx } from '@/utils/class-names' | ||
import { formatNumber } from '@/utils/strings' | ||
import { Transition } from '@headlessui/react' | ||
import Image from 'next/image' | ||
import { useState } from 'react' | ||
import Lottie, { LottieProps } from 'react-lottie' | ||
|
||
export type RewardAnimationProps = Omit<LottieProps, 'options'> & { | ||
claim: NonNullable< | ||
GetDailyRewardQuery['gamificationEntranceDailyRewardSequence'] | ||
>['claims'][number] | ||
close: () => void | ||
} | ||
|
||
export default function RewardAnimation({ | ||
claim, | ||
close, | ||
...props | ||
}: RewardAnimationProps) { | ||
const isMysteryBox = !!claim.claimRewardPointsRange | ||
|
||
const [showPointsEarned, setShowPointsEarned] = useState(!isMysteryBox) | ||
const [isPaused, setIsPaused] = useState(true) | ||
const defaultOptions: LottieProps = { | ||
...props, | ||
options: { | ||
loop: false, | ||
autoplay: false, | ||
animationData: PresentAnimation, | ||
rendererSettings: { | ||
preserveAspectRatio: 'xMidYMid slice', | ||
}, | ||
}, | ||
} | ||
|
||
return ( | ||
<> | ||
{!showPointsEarned && ( | ||
<Transition | ||
appear | ||
show | ||
className='fixed inset-0 z-40 flex h-full w-full max-w-screen-md origin-center flex-col items-center justify-center gap-2 transition duration-300' | ||
enterFrom={cx('opacity-0 scale-75')} | ||
enterTo={cx('opacity-100 scale-100')} | ||
leaveFrom={cx('opacity-100 scale-100')} | ||
leaveTo={cx('opacity-0 scale-75')} | ||
onClick={() => { | ||
setIsPaused(!isPaused) | ||
setTimeout(() => { | ||
setShowPointsEarned(true) | ||
}, 800) | ||
}} | ||
> | ||
<div className='absolute left-1/2 top-1/2 h-[300px] w-[300px] -translate-x-1/2 -translate-y-1/2 animate-[pulse_3s_ease-in-out_infinite] rounded-full bg-background-primary/20 blur-3xl' /> | ||
<Lottie | ||
{...defaultOptions} | ||
isPaused={isPaused} | ||
height={250 || props.height} | ||
width={250 || props.width} | ||
/> | ||
<span | ||
className={cx( | ||
'text-text/50 opacity-100 transition', | ||
!isPaused && 'opacity-0' | ||
)} | ||
> | ||
Tap to open | ||
</span> | ||
</Transition> | ||
)} | ||
{showPointsEarned && ( | ||
<Transition | ||
appear | ||
show | ||
className='fixed inset-0 z-40 flex h-full w-full max-w-screen-md origin-center items-center justify-center transition duration-300' | ||
enterFrom={cx('opacity-0 scale-75')} | ||
enterTo={cx('opacity-100 scale-100')} | ||
leaveFrom={cx('opacity-100 scale-100')} | ||
leaveTo={cx('opacity-0 scale-75')} | ||
onClick={() => close()} | ||
> | ||
<div className='absolute left-1/2 top-1/2 h-[300px] w-[300px] -translate-x-1/2 -translate-y-1/2 animate-[pulse_3s_ease-in-out_infinite] rounded-full bg-background-primary/20 blur-3xl' /> | ||
<div className='relative flex flex-1 flex-col items-center justify-center gap-1 px-4 py-3'> | ||
<Image src={Diamond} alt='' className='h-12 w-12' /> | ||
<span className='text-3xl font-bold'> | ||
{formatNumber(claim.claimRewardPoints)} | ||
</span> | ||
<span className='text-text/70'>Points earned!</span> | ||
<span className='mt-8 text-text/50'>Tap anywhere to close</span> | ||
</div> | ||
</Transition> | ||
)} | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import Diamond from '@/assets/emojis/diamond.png' | ||
import Present from '@/assets/graphics/present.svg' | ||
import useToastError from '@/hooks/useToastError' | ||
import { getServerDayQuery } from '@/services/api/query' | ||
import { useClaimDailyReward } from '@/services/datahub/content-staking/mutation' | ||
import { getDailyRewardQuery } from '@/services/datahub/content-staking/query' | ||
import { useSendEvent } from '@/stores/analytics' | ||
import { useMyMainAddress } from '@/stores/my-account' | ||
import { cx } from '@/utils/class-names' | ||
import { formatNumber } from '@/utils/strings' | ||
import { Transition } from '@headlessui/react' | ||
import Image from 'next/image' | ||
import { useEffect, useState } from 'react' | ||
import { createPortal } from 'react-dom' | ||
import { HiXMark } from 'react-icons/hi2' | ||
import Button from '../../Button' | ||
import RewardAnimation from './RewardAnimation' | ||
|
||
export default function DailyRewardModal({ | ||
close, | ||
isOpen, | ||
}: { | ||
isOpen: boolean | ||
close: () => void | ||
}) { | ||
const [isOpenAnimation, setIsOpenAnimation] = useState(false) | ||
const closeModal = () => { | ||
setIsOpenAnimation(true) | ||
close() | ||
} | ||
|
||
useEffect(() => { | ||
if (isOpen) { | ||
setIsOpenAnimation(false) | ||
} | ||
}, [isOpen]) | ||
|
||
const sendEvent = useSendEvent() | ||
const myAddress = useMyMainAddress() | ||
const { data } = getDailyRewardQuery.useQuery(myAddress ?? '') | ||
const { data: serverDay } = getServerDayQuery.useQuery(null) | ||
const { mutate: claim, isLoading, error } = useClaimDailyReward() | ||
useToastError(error, 'Failed to claim daily reward') | ||
|
||
const claimable = data?.claims.find( | ||
(claim) => | ||
Number(claim.claimValidDay) === serverDay?.day && claim.openToClaim | ||
) | ||
const isMysteryBoxClaimable = claimable?.claimRewardPointsRange | ||
|
||
return createPortal( | ||
<> | ||
<Transition | ||
show={isOpen} | ||
appear | ||
className='fixed inset-0 z-40 h-full w-full bg-black/50 backdrop-blur-md transition duration-300' | ||
enterFrom={cx('opacity-0')} | ||
enterTo='opacity-100' | ||
leaveFrom='h-auto' | ||
leaveTo='opacity-0 !duration-150' | ||
onClick={close} | ||
/> | ||
{isOpenAnimation && isOpen && ( | ||
<RewardAnimation claim={claimable!} close={closeModal} /> | ||
)} | ||
<Transition | ||
show={isOpen && !isOpenAnimation} | ||
appear | ||
className='fixed bottom-0 left-1/2 z-40 mx-auto flex h-auto w-full max-w-screen-md -translate-x-1/2 rounded-t-[10px] bg-background-light outline-none transition duration-300' | ||
enterFrom={cx('opacity-0 translate-y-48')} | ||
enterTo='opacity-100 translate-y-0' | ||
leaveFrom='h-auto' | ||
leaveTo='opacity-0 translate-y-24 !duration-150' | ||
> | ||
<Button | ||
size='circleSm' | ||
variant='transparent' | ||
className='absolute right-4 top-4' | ||
onClick={close} | ||
> | ||
<HiXMark className='text-lg' /> | ||
</Button> | ||
<div className='mx-auto flex w-full max-w-screen-md flex-col gap-6 overflow-auto px-5 py-6 pb-12'> | ||
<div className='flex flex-col gap-2'> | ||
<span className='text-2xl font-medium'>Your daily rewards</span> | ||
<span className='text-text-muted'> | ||
Claim rewards and keep the streak going! | ||
</span> | ||
</div> | ||
<div className='grid w-full grid-cols-4 gap-4 gap-x-2 gap-y-6'> | ||
{data?.claims.map((claim) => { | ||
const isClaimed = | ||
claim.claimValidDay && | ||
!claim.openToClaim && | ||
Number(claim.claimValidDay) <= (serverDay?.day ?? 0) | ||
const isClaimable = | ||
Number(claim.claimValidDay) === serverDay?.day && | ||
claim.openToClaim | ||
|
||
const isMysteryBox = !!claim.claimRewardPointsRange | ||
return ( | ||
<div | ||
key={claim.index} | ||
className={cx( | ||
'flex flex-col overflow-clip rounded-2xl border border-background-lighter bg-background-light', | ||
isClaimable && | ||
'border-background-primary bg-background-lighter', | ||
isClaimed && | ||
'border-background-primary bg-background-primary/30' | ||
)} | ||
> | ||
{isMysteryBox ? ( | ||
<div className='flex flex-1 flex-col items-center justify-center gap-1 px-4 py-3'> | ||
<Present /> | ||
</div> | ||
) : ( | ||
<div className='flex flex-1 flex-col items-center justify-center gap-1 px-4 py-3'> | ||
<Image src={Diamond} alt='' className='h-8 w-8' /> | ||
<span className='text-xl font-bold'> | ||
{formatNumber(claim.claimRewardPoints, { | ||
shorten: true, | ||
})} | ||
</span> | ||
</div> | ||
)} | ||
<div | ||
className={cx( | ||
'mt-auto bg-background-lighter pb-1 pt-0.5 text-center', | ||
isClaimable && 'bg-background-primary', | ||
isClaimed && 'bg-transparent' | ||
)} | ||
> | ||
<span className='text-sm'>Day {claim.index + 1}</span> | ||
</div> | ||
</div> | ||
) | ||
})} | ||
</div> | ||
<div className='grid w-full grid-cols-1 gap-4'> | ||
<Button | ||
size='lg' | ||
disabled={!claimable} | ||
isLoading={isLoading} | ||
onClick={() => { | ||
sendEvent('daily_reward_claimed') | ||
claim(undefined) | ||
setIsOpenAnimation(true) | ||
}} | ||
> | ||
{!claimable | ||
? 'You have claimed your daily reward' | ||
: isMysteryBoxClaimable | ||
? 'Open Mystery Box' | ||
: 'Claim'} | ||
</Button> | ||
</div> | ||
</div> | ||
</Transition> | ||
</>, | ||
document.body | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.