Skip to content

Commit

Permalink
Merge pull request #681 from dappforce/deploy/epic
Browse files Browse the repository at this point in the history
Improvements
  • Loading branch information
teodorus-nathaniel authored Jun 21, 2024
2 parents 67776e2 + 523ceb9 commit 20f15d3
Show file tree
Hide file tree
Showing 50 changed files with 4,882 additions and 265 deletions.
3,531 changes: 3,531 additions & 0 deletions src/assets/animations/present.json

Large diffs are not rendered by default.

Binary file added src/assets/emojis/present.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/like-button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/like-message.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/graphics/present.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/tasks/calendar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/tasks/like.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/tasks/telegram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/graphics/tasks/twitter-x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/bottomNavbar/tasks.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/assets/icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions src/components/MediaLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export type MediaLoaderProps = Omit<ImageProps, 'src' | 'alt'> & {
loadingClassName?: string
placeholderClassName?: string
withSpinner?: boolean
eagerLoading?: boolean
}

export default function MediaLoader({
Expand All @@ -22,7 +21,6 @@ export default function MediaLoader({
loadingClassName,
placeholderClassName,
withSpinner,
eagerLoading,
...props
}: MediaLoaderProps) {
const [isLoaded, setIsLoaded] = useState(false)
Expand Down Expand Up @@ -91,12 +89,12 @@ export default function MediaLoader({
<Image
{...commonProps}
style={{ backfaceVisibility: 'hidden', ...commonProps.style }}
loading='eager'
onError={undefined}
onLoad={undefined}
width={10}
height={10}
alt={props.alt || ''}
loading='eager'
className={cx(
commonProps.className,
'absolute inset-0 m-0 h-full w-full p-0'
Expand Down
2 changes: 1 addition & 1 deletion src/components/chats/ChatForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default function ChatForm({
const isSufficient = await refetch()
if (!isSufficient.data) {
refetch()
setOpenMessageModal('should-stake')
setOpenMessageModal('not-enough-balance')
return
}
resetForm()
Expand Down
2 changes: 1 addition & 1 deletion src/components/chats/ChatItem/ChatItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export default function ChatItem({
e.preventDefault()
toggleDisplay?.(e)
}}
onDoubleClick={() => setMessageAsReply()}
// onDoubleClick={() => setMessageAsReply()}
{...referenceProps}
id={messageBubbleId}
>
Expand Down
98 changes: 98 additions & 0 deletions src/components/modals/DailyRewardModal/RewardAnimation.tsx
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>
)}
</>
)
}
162 changes: 162 additions & 0 deletions src/components/modals/DailyRewardModal/index.tsx
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
)
}
6 changes: 3 additions & 3 deletions src/components/modals/GlobalModals.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useMessageData } from '@/stores/message'
import ShouldStakeModal from '../content-staking/ShouldStakeModal'
import BlockedModal from '../moderation/BlockedModal'
import PostMemeThresholdModal from './PostMemeThresholdModal'

export default function GlobalModals() {
const isOpenMessageModal = useMessageData.use.isOpenMessageModal()
const setOpenMessageModal = useMessageData.use.setOpenMessageModal()

return (
<>
<ShouldStakeModal
isOpen={isOpenMessageModal === 'should-stake'}
<PostMemeThresholdModal
isOpen={isOpenMessageModal === 'not-enough-balance'}
closeModal={() => setOpenMessageModal('')}
/>
<BlockedModal
Expand Down
Loading

0 comments on commit 20f15d3

Please sign in to comment.