Commit fa3f8d98 authored by Max Alekseenko's avatar Max Alekseenko

implement claim

parent 0657ea50
...@@ -15,8 +15,10 @@ type TRewardsContext = { ...@@ -15,8 +15,10 @@ type TRewardsContext = {
isLoginModalOpen: boolean; isLoginModalOpen: boolean;
openLoginModal: () => void; openLoginModal: () => void;
closeLoginModal: () => void; closeLoginModal: () => void;
balances: RewardsUserBalancesResponse | undefined; balance: RewardsUserBalancesResponse | undefined;
refetchBalance: () => void;
dailyReward: RewardsUserDailyCheckResponse | undefined; dailyReward: RewardsUserDailyCheckResponse | undefined;
refetchDailyReward: () => void;
isLogedIn: boolean; isLogedIn: boolean;
} }
...@@ -24,8 +26,10 @@ const RewardsContext = createContext<TRewardsContext>({ ...@@ -24,8 +26,10 @@ const RewardsContext = createContext<TRewardsContext>({
isLoginModalOpen: false, isLoginModalOpen: false,
openLoginModal: () => {}, openLoginModal: () => {},
closeLoginModal: () => {}, closeLoginModal: () => {},
balances: undefined, balance: undefined,
refetchBalance: () => {},
dailyReward: undefined, dailyReward: undefined,
refetchDailyReward: () => {},
isLogedIn: false, isLogedIn: false,
}); });
...@@ -57,10 +61,12 @@ export function RewardsContextProvider({ children }: Props) { ...@@ -57,10 +61,12 @@ export function RewardsContextProvider({ children }: Props) {
isLoginModalOpen, isLoginModalOpen,
openLoginModal: setIsLoginModalOpen.on, openLoginModal: setIsLoginModalOpen.on,
closeLoginModal: setIsLoginModalOpen.off, closeLoginModal: setIsLoginModalOpen.off,
balances: balancesQuery.data, balance: balancesQuery.data,
refetchBalance: balancesQuery.refetch,
dailyReward: dailyRewardQuery.data, dailyReward: dailyRewardQuery.data,
refetchDailyReward: dailyRewardQuery.refetch,
isLogedIn: Boolean(apiToken), isLogedIn: Boolean(apiToken),
}), [ isLoginModalOpen, setIsLoginModalOpen, balancesQuery.data, dailyRewardQuery.data, apiToken ]); }), [ isLoginModalOpen, setIsLoginModalOpen, balancesQuery, dailyRewardQuery, apiToken ]);
return ( return (
<RewardsContext.Provider value={ value }> <RewardsContext.Provider value={ value }>
......
...@@ -27,7 +27,7 @@ export default function useNavItems(): ReturnType { ...@@ -27,7 +27,7 @@ export default function useNavItems(): ReturnType {
const pathname = router.pathname; const pathname = router.pathname;
const { const {
openLoginModal: openRewardsLoginModal, openLoginModal: openRewardsLoginModal,
balances: rewardsBalances, balance: rewardsBalance,
isLogedIn: isLoggedInToRewards, isLogedIn: isLoggedInToRewards,
} = useRewardsContext(); } = useRewardsContext();
...@@ -272,7 +272,7 @@ export default function useNavItems(): ReturnType { ...@@ -272,7 +272,7 @@ export default function useNavItems(): ReturnType {
const accountNavItems: ReturnType['accountNavItems'] = [ const accountNavItems: ReturnType['accountNavItems'] = [
config.features.rewards.isEnabled ? { 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, nextRoute: isLoggedInToRewards ? { pathname: '/account/rewards' as const } : undefined,
onClick: isLoggedInToRewards ? undefined : openRewardsLoginModal, onClick: isLoggedInToRewards ? undefined : openRewardsLoginModal,
icon: 'merits', icon: 'merits',
...@@ -318,5 +318,5 @@ export default function useNavItems(): ReturnType { ...@@ -318,5 +318,5 @@ export default function useNavItems(): ReturnType {
}; };
return { mainNavItems, accountNavItems, profileItem }; return { mainNavItems, accountNavItems, profileItem };
}, [ pathname, openRewardsLoginModal, rewardsBalances, isLoggedInToRewards ]); }, [ pathname, openRewardsLoginModal, rewardsBalance, isLoggedInToRewards ]);
} }
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 { useRouter } from 'next/router';
import React from 'react'; import React, { useCallback, useEffect } from 'react';
import { useRewardsContext } from 'lib/contexts/rewards'; import { useRewardsContext } from 'lib/contexts/rewards';
import splitSecondsInPeriods from 'ui/blockCountdown/splitSecondsInPeriods';
import CopyField from 'ui/rewards/CopyField'; import CopyField from 'ui/rewards/CopyField';
import RewardsDashboardCard from 'ui/rewards/RewardsDashboardCard'; import RewardsDashboardCard from 'ui/rewards/RewardsDashboardCard';
import useClaim from 'ui/rewards/useClaim';
import useReferrals from 'ui/rewards/useReferrals'; import useReferrals from 'ui/rewards/useReferrals';
import useRewardsConfig from 'ui/rewards/useRewardsConfig'; import useRewardsConfig from 'ui/rewards/useRewardsConfig';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -13,14 +15,51 @@ import PageTitle from 'ui/shared/Page/PageTitle'; ...@@ -13,14 +15,51 @@ import PageTitle from 'ui/shared/Page/PageTitle';
const RewardsDashboard = () => { const RewardsDashboard = () => {
const router = useRouter(); const router = useRouter();
const { balances, dailyReward, isLogedIn } = useRewardsContext(); const { balance, refetchBalance, dailyReward, refetchDailyReward, isLogedIn } = useRewardsContext();
const referralsQuery = useReferrals(); const referralsQuery = useReferrals();
const rewardsConfigQuery = useRewardsConfig(); const rewardsConfigQuery = useRewardsConfig();
const claim = useClaim();
const [ isClaiming, setIsClaiming ] = useBoolean(false);
const [ timeLeft, setTimeLeft ] = React.useState<string>('');
if (!isLogedIn) { if (!isLogedIn) {
router.replace({ pathname: '/' }, undefined, { shallow: true }); 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 ( return (
<> <>
<PageTitle <PageTitle
...@@ -39,8 +78,15 @@ const RewardsDashboard = () => { ...@@ -39,8 +78,15 @@ const RewardsDashboard = () => {
<Flex gap={ 6 }> <Flex gap={ 6 }>
<RewardsDashboardCard <RewardsDashboardCard
description="Claim your daily merits and any merits received from referrals." description="Claim your daily merits and any merits received from referrals."
values={ [ { label: 'Total balance', value: balances?.total } ] } values={ [ { label: 'Total balance', value: balance?.total } ] }
contentAfter={ <Button>Claim { dailyReward?.daily_reward } Merits</Button> } contentAfter={ (
<Button isDisabled={ !dailyReward?.available } onClick={ handleClaim } isLoading={ isClaiming }>
{ dailyReward?.available ?
`Claim ${ dailyRewardValue } Merits` :
`Next claim in ${ timeLeft }`
}
</Button>
) }
/> />
<RewardsDashboardCard <RewardsDashboardCard
title="Title" title="Title"
......
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 ]);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment