mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
implement claim
This commit is contained in:
@@ -15,8 +15,10 @@ type TRewardsContext = {
|
||||
isLoginModalOpen: boolean;
|
||||
openLoginModal: () => void;
|
||||
closeLoginModal: () => void;
|
||||
balances: RewardsUserBalancesResponse | undefined;
|
||||
balance: RewardsUserBalancesResponse | undefined;
|
||||
refetchBalance: () => void;
|
||||
dailyReward: RewardsUserDailyCheckResponse | undefined;
|
||||
refetchDailyReward: () => void;
|
||||
isLogedIn: boolean;
|
||||
}
|
||||
|
||||
@@ -24,8 +26,10 @@ const RewardsContext = createContext<TRewardsContext>({
|
||||
isLoginModalOpen: false,
|
||||
openLoginModal: () => {},
|
||||
closeLoginModal: () => {},
|
||||
balances: undefined,
|
||||
balance: undefined,
|
||||
refetchBalance: () => {},
|
||||
dailyReward: undefined,
|
||||
refetchDailyReward: () => {},
|
||||
isLogedIn: false,
|
||||
});
|
||||
|
||||
@@ -57,10 +61,12 @@ export function RewardsContextProvider({ children }: Props) {
|
||||
isLoginModalOpen,
|
||||
openLoginModal: setIsLoginModalOpen.on,
|
||||
closeLoginModal: setIsLoginModalOpen.off,
|
||||
balances: balancesQuery.data,
|
||||
balance: balancesQuery.data,
|
||||
refetchBalance: balancesQuery.refetch,
|
||||
dailyReward: dailyRewardQuery.data,
|
||||
refetchDailyReward: dailyRewardQuery.refetch,
|
||||
isLogedIn: Boolean(apiToken),
|
||||
}), [ isLoginModalOpen, setIsLoginModalOpen, balancesQuery.data, dailyRewardQuery.data, apiToken ]);
|
||||
}), [ isLoginModalOpen, setIsLoginModalOpen, balancesQuery, dailyRewardQuery, apiToken ]);
|
||||
|
||||
return (
|
||||
<RewardsContext.Provider value={ value }>
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function useNavItems(): ReturnType {
|
||||
const pathname = router.pathname;
|
||||
const {
|
||||
openLoginModal: openRewardsLoginModal,
|
||||
balances: rewardsBalances,
|
||||
balance: rewardsBalance,
|
||||
isLogedIn: isLoggedInToRewards,
|
||||
} = useRewardsContext();
|
||||
|
||||
@@ -272,7 +272,7 @@ export default function useNavItems(): ReturnType {
|
||||
|
||||
const accountNavItems: ReturnType['accountNavItems'] = [
|
||||
config.features.rewards.isEnabled ? {
|
||||
text: rewardsBalances?.total ? `${ rewardsBalances?.total } Merits` : 'Merits',
|
||||
text: rewardsBalance?.total ? `${ rewardsBalance?.total } Merits` : 'Merits',
|
||||
nextRoute: isLoggedInToRewards ? { pathname: '/account/rewards' as const } : undefined,
|
||||
onClick: isLoggedInToRewards ? undefined : openRewardsLoginModal,
|
||||
icon: 'merits',
|
||||
@@ -318,5 +318,5 @@ export default function useNavItems(): ReturnType {
|
||||
};
|
||||
|
||||
return { mainNavItems, accountNavItems, profileItem };
|
||||
}, [ pathname, openRewardsLoginModal, rewardsBalances, isLoggedInToRewards ]);
|
||||
}, [ pathname, openRewardsLoginModal, rewardsBalance, isLoggedInToRewards ]);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Button, Flex, Skeleton, Text, useColorModeValue } from '@chakra-ui/react';
|
||||
import { Button, Flex, Skeleton, Text, useBoolean, useColorModeValue } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
||||
import { useRewardsContext } from 'lib/contexts/rewards';
|
||||
import splitSecondsInPeriods from 'ui/blockCountdown/splitSecondsInPeriods';
|
||||
import CopyField from 'ui/rewards/CopyField';
|
||||
import RewardsDashboardCard from 'ui/rewards/RewardsDashboardCard';
|
||||
import useClaim from 'ui/rewards/useClaim';
|
||||
import useReferrals from 'ui/rewards/useReferrals';
|
||||
import useRewardsConfig from 'ui/rewards/useRewardsConfig';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
@@ -13,14 +15,51 @@ import PageTitle from 'ui/shared/Page/PageTitle';
|
||||
|
||||
const RewardsDashboard = () => {
|
||||
const router = useRouter();
|
||||
const { balances, dailyReward, isLogedIn } = useRewardsContext();
|
||||
const { balance, refetchBalance, dailyReward, refetchDailyReward, isLogedIn } = useRewardsContext();
|
||||
const referralsQuery = useReferrals();
|
||||
const rewardsConfigQuery = useRewardsConfig();
|
||||
const claim = useClaim();
|
||||
const [ isClaiming, setIsClaiming ] = useBoolean(false);
|
||||
const [ timeLeft, setTimeLeft ] = React.useState<string>('');
|
||||
|
||||
if (!isLogedIn) {
|
||||
router.replace({ pathname: '/' }, undefined, { shallow: true });
|
||||
}
|
||||
|
||||
const dailyRewardValue = Number(dailyReward?.daily_reward || 0) + Number(dailyReward?.pending_referral_rewards || 0);
|
||||
|
||||
const handleClaim = useCallback(async() => {
|
||||
setIsClaiming.on();
|
||||
try {
|
||||
await claim();
|
||||
refetchBalance();
|
||||
refetchDailyReward();
|
||||
} catch (error) {}
|
||||
setIsClaiming.off();
|
||||
}, [ claim, setIsClaiming, refetchBalance, refetchDailyReward ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dailyReward?.reset_at) {
|
||||
return;
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
const now = new Date().getTime();
|
||||
const target = new Date(dailyReward.reset_at).getTime();
|
||||
const difference = target - now;
|
||||
|
||||
if (difference > 0) {
|
||||
const { hours, minutes, seconds } = splitSecondsInPeriods(Math.floor(difference / 1000));
|
||||
setTimeLeft(`${ hours }:${ minutes }:${ seconds }`);
|
||||
} else {
|
||||
setTimeLeft('00:00:00');
|
||||
refetchDailyReward();
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [ dailyReward?.reset_at, refetchDailyReward ]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle
|
||||
@@ -39,8 +78,15 @@ const RewardsDashboard = () => {
|
||||
<Flex gap={ 6 }>
|
||||
<RewardsDashboardCard
|
||||
description="Claim your daily merits and any merits received from referrals."
|
||||
values={ [ { label: 'Total balance', value: balances?.total } ] }
|
||||
contentAfter={ <Button>Claim { dailyReward?.daily_reward } Merits</Button> }
|
||||
values={ [ { label: 'Total balance', value: balance?.total } ] }
|
||||
contentAfter={ (
|
||||
<Button isDisabled={ !dailyReward?.available } onClick={ handleClaim } isLoading={ isClaiming }>
|
||||
{ dailyReward?.available ?
|
||||
`Claim ${ dailyRewardValue } Merits` :
|
||||
`Next claim in ${ timeLeft }`
|
||||
}
|
||||
</Button>
|
||||
) }
|
||||
/>
|
||||
<RewardsDashboardCard
|
||||
title="Title"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import type { RewardsUserDailyClaimResponse } from 'types/api/rewards';
|
||||
|
||||
import type { ResourceError } from 'lib/api/resources';
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import * as cookies from 'lib/cookies';
|
||||
import useToast from 'lib/hooks/useToast';
|
||||
|
||||
export default function useClaim() {
|
||||
const apiFetch = useApiFetch();
|
||||
const toast = useToast();
|
||||
|
||||
return useCallback(async() => {
|
||||
try {
|
||||
const claimResponse = await apiFetch<'rewards_user_daily_claim', RewardsUserDailyClaimResponse>('rewards_user_daily_claim', {
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${ cookies.get(cookies.NAMES.REWARDS_API_TOKEN) }`,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!('daily_reward' in claimResponse)) {
|
||||
throw claimResponse;
|
||||
}
|
||||
} catch (_error) {
|
||||
toast({
|
||||
position: 'top-right',
|
||||
title: 'Error',
|
||||
description: (_error as ResourceError<{ message: string }>)?.payload?.message || 'Something went wrong. Try again later.',
|
||||
status: 'error',
|
||||
variant: 'subtle',
|
||||
isClosable: true,
|
||||
});
|
||||
throw _error;
|
||||
}
|
||||
}, [ apiFetch, toast ]);
|
||||
}
|
||||
Reference in New Issue
Block a user