diff --git a/src/components/Announcement/helper.ts b/src/components/Announcement/helper.ts
index 6dfcf4dfca..0ba391456d 100644
--- a/src/components/Announcement/helper.ts
+++ b/src/components/Announcement/helper.ts
@@ -1,10 +1,7 @@
import { ChainId } from '@kyberswap/ks-sdk-core'
-import { useCallback } from 'react'
-import AnnouncementApi from 'services/announcement'
import { AnnouncementTemplatePopup, PopupContentAnnouncement, PopupItemType } from 'components/Announcement/type'
import { TIMES_IN_SECS } from 'constants/index'
-import { useAppDispatch } from 'state/hooks'
const LsKey = 'ack-announcements'
export const getAnnouncementsAckMap = () => JSON.parse(localStorage[LsKey] || '{}')
@@ -42,20 +39,3 @@ export const isPopupCanShow = (
const isExpired = Date.now() < startAt * 1000 || Date.now() > endAt * 1000
return !isRead && !isExpired && isRightChain && isOwn
}
-
-export const useInvalidateTags = (reducerPath: string) => {
- const dispatch = useAppDispatch()
- return useCallback(
- (tag: string | string[]) => {
- dispatch({
- type: `${reducerPath}/invalidateTags`,
- payload: Array.isArray(tag) ? tag : [tag],
- })
- },
- [dispatch, reducerPath],
- )
-}
-
-export const useInvalidateTagAnnouncement = () => {
- return useInvalidateTags(AnnouncementApi.reducerPath)
-}
diff --git a/src/components/Announcement/index.tsx b/src/components/Announcement/index.tsx
index 3abf63be97..dd56ff5b27 100644
--- a/src/components/Announcement/index.tsx
+++ b/src/components/Announcement/index.tsx
@@ -10,13 +10,14 @@ import styled, { css } from 'styled-components'
import AnnouncementView, { Tab } from 'components/Announcement/AnnoucementView'
import DetailAnnouncementPopup from 'components/Announcement/Popups/DetailAnnouncementPopup'
-import { formatNumberOfUnread, useInvalidateTagAnnouncement } from 'components/Announcement/helper'
+import { formatNumberOfUnread } from 'components/Announcement/helper'
import { Announcement, PrivateAnnouncement } from 'components/Announcement/type'
import NotificationIcon from 'components/Icons/NotificationIcon'
import MenuFlyout from 'components/MenuFlyout'
import Modal from 'components/Modal'
import { RTK_QUERY_TAGS } from 'constants/index'
import useInterval from 'hooks/useInterval'
+import { useInvalidateTagAnnouncement } from 'hooks/useInvalidateTags'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import { ApplicationModal } from 'state/application/actions'
import { useDetailAnnouncement, useModalOpen, useToggleNotificationCenter } from 'state/application/hooks'
diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx
index ff131bba05..326c38c5ed 100644
--- a/src/components/ProtectedRoute.tsx
+++ b/src/components/ProtectedRoute.tsx
@@ -3,9 +3,8 @@ import { Navigate } from 'react-router-dom'
import LocalLoader from 'components/LocalLoader'
import { RTK_QUERY_TAGS } from 'constants/index'
-import kyberAIapi from 'pages/TrueSightV2/hooks/useKyberAIData'
+import { useInvalidateTagKyberAi } from 'hooks/useInvalidateTags'
import { useSessionInfo } from 'state/authen/hooks'
-import { useAppDispatch } from 'state/hooks'
import { useIsWhiteListKyberAI } from 'state/user/hooks'
type Props = {
@@ -33,20 +32,15 @@ export const ProtectedRouteKyberAI = ({
const { userInfo } = useSessionInfo()
const loadedPage = useRef(false)
const canAccessPage = isWhiteList || waitUtilAuthenEndOnly
- const dispatch = useAppDispatch()
+ const invalidateTags = useInvalidateTagKyberAi()
useEffect(() => {
// change account sign in => refresh participant info
try {
refetch()
- dispatch(
- kyberAIapi.util.invalidateTags([
- RTK_QUERY_TAGS.GET_WATCHLIST_TOKENS_KYBER_AI,
- RTK_QUERY_TAGS.GET_WATCHLIST_INFO_KYBER_AI,
- ]),
- )
+ invalidateTags([RTK_QUERY_TAGS.GET_WATCHLIST_TOKENS_KYBER_AI, RTK_QUERY_TAGS.GET_WATCHLIST_INFO_KYBER_AI])
} catch (error) {}
- }, [userInfo?.identityId, refetch, dispatch])
+ }, [userInfo?.identityId, refetch, invalidateTags])
if (loading && !loadedPage.current) return
if (!canAccessPage) return
diff --git a/src/components/YourCampaignTransactionsModal/index.tsx b/src/components/YourCampaignTransactionsModal/index.tsx
index 52e151a255..68b3bc1962 100644
--- a/src/components/YourCampaignTransactionsModal/index.tsx
+++ b/src/components/YourCampaignTransactionsModal/index.tsx
@@ -5,11 +5,11 @@ import { CheckCircle, Copy, ExternalLink, Info, X } from 'react-feather'
import { useSelector } from 'react-redux'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
+import { useGetTxsCampaignQuery } from 'services/campaign'
import styled, { css } from 'styled-components'
-import useSWR from 'swr'
import Modal from 'components/Modal'
-import { CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE, SWR_KEYS } from 'constants/index'
+import { CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE } from 'constants/index'
import { NETWORKS_INFO } from 'constants/networks'
import { useActiveWeb3React } from 'hooks'
import useCopyClipboard from 'hooks/useCopyClipboard'
@@ -17,7 +17,6 @@ import useTheme from 'hooks/useTheme'
import { AppState } from 'state'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleYourCampaignTransactionsModal } from 'state/application/hooks'
-import { CampaignProofData } from 'state/campaigns/actions'
import { getEtherscanLink } from 'utils'
import getShortenAddress from 'utils/getShortenAddress'
@@ -32,37 +31,15 @@ export default function YourCampaignTransactionsModal() {
const above768 = useMedia('(min-width: 768px)')
const selectedCampaign = useSelector((state: AppState) => state.campaigns.selectedCampaign)
- const { data: userCampaignTransactions } = useSWR(
- account && selectedCampaign
- ? SWR_KEYS.getCampaignTransactions(
- selectedCampaign.id,
- CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE,
- CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE * (currentPage - 1),
- account,
- )
- : null,
- async (url: string) => {
- try {
- const response = await fetch(url)
- if (response.ok) {
- const data = await response.json()
- if (data && Array.isArray(data.data) && data.data.length) {
- return data.data.map(
- (item: any): CampaignProofData => ({
- id: item.id,
- chainId: parseInt(item.chainId),
- utcTimestamp: new Date(item.time).getTime(),
- txPoint: item.txPoint,
- txHash: item.tx,
- }),
- )
- }
- }
- return []
- } catch (err) {
- console.error(err)
- }
+
+ const { data: userCampaignTransactions } = useGetTxsCampaignQuery(
+ {
+ campaignId: selectedCampaign?.id || 0,
+ limit: CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE,
+ offset: CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE * (currentPage - 1),
+ userAddress: account ?? '',
},
+ { skip: !selectedCampaign?.id },
)
const [isCopied, setCopied] = useCopyClipboard()
diff --git a/src/components/swapv2/LimitOrder/ListOrder/index.tsx b/src/components/swapv2/LimitOrder/ListOrder/index.tsx
index e21d7fc949..fb99eed161 100644
--- a/src/components/swapv2/LimitOrder/ListOrder/index.tsx
+++ b/src/components/swapv2/LimitOrder/ListOrder/index.tsx
@@ -6,11 +6,10 @@ import { Trash } from 'react-feather'
import { useNavigate } from 'react-router-dom'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
-import limitOrderApi, { useGetListOrdersQuery } from 'services/limitOrder'
+import { useGetListOrdersQuery } from 'services/limitOrder'
import styled from 'styled-components'
import { ReactComponent as NoDataIcon } from 'assets/svg/no-data.svg'
-import { useInvalidateTags } from 'components/Announcement/helper'
import { ButtonLight } from 'components/Button'
import Column from 'components/Column'
import LocalLoader from 'components/LocalLoader'
@@ -22,6 +21,7 @@ import SubscribeNotificationButton from 'components/SubscribeButton'
import useRequestCancelOrder from 'components/swapv2/LimitOrder/ListOrder/useRequestCancelOrder'
import { EMPTY_ARRAY, RTK_QUERY_TAGS, TRANSACTION_STATE_DEFAULT } from 'constants/index'
import { useActiveWeb3React } from 'hooks'
+import { useInvalidateTagLimitOrder } from 'hooks/useInvalidateTags'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useParsedQueryString from 'hooks/useParsedQueryString'
import useShowLoadingAtLeastTime from 'hooks/useShowLoadingAtLeastTime'
@@ -203,7 +203,7 @@ export default function ListLimitOrder() {
onReset()
}, [chainId, orderType])
- const invalidateTag = useInvalidateTags(limitOrderApi.reducerPath)
+ const invalidateTag = useInvalidateTagLimitOrder()
const refetchOrders = useCallback(() => {
invalidateTag(RTK_QUERY_TAGS.GET_LIST_ORDERS)
}, [invalidateTag])
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 3959404bda..e181ef45c2 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid'
import { TransactionFlowState } from 'types/TransactionFlowState'
-import { CAMPAIGN_BASE_URL as CAMPAIGN_BASE_DOMAIN } from './env'
+import { CAMPAIGN_BASE_URL } from './env'
import * as ENV from './env'
import { EVM_MAINNET_NETWORKS, EVM_NETWORK, NETWORKS_INFO, SUPPORTED_NETWORKS, isEVM } from './networks'
@@ -186,16 +186,10 @@ export const CAMPAIGN_YOUR_TRANSACTIONS_ITEM_PER_PAGE = 10000
export const ELASTIC_BASE_FEE_UNIT = 100_000
export const KYBERSWAP_SOURCE = '{"source":"kyberswap"}'
-export const CAMPAIGN_BASE_URL = `${CAMPAIGN_BASE_DOMAIN}/api/v1/campaigns`
export const SWR_KEYS = {
- getGrantProgramLeaderBoard: (id: number | string) => `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions/${id}/leaderboard`,
- getListGrantPrograms: `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions`,
- getGrantProgram: (id: number | string) => `${CAMPAIGN_BASE_DOMAIN}/api/v1/competitions/${id}`,
- getListCampaign: CAMPAIGN_BASE_URL,
- getLeaderboard: (id: number) => CAMPAIGN_BASE_URL + '/' + id + '/leaderboard',
- getLuckyWinners: (id: number) => CAMPAIGN_BASE_URL + '/' + id + '/lucky-winners',
- getCampaignTransactions: (campaignId: number, limit: number, offset: number, account: string) =>
- `${CAMPAIGN_BASE_URL}/${campaignId}/proofs?limit=${limit}&offset=${offset}&userAddress=${account}`,
+ getGrantProgramLeaderBoard: (id: number | string) => `${CAMPAIGN_BASE_URL}/api/v1/competitions/${id}/leaderboard`,
+ getListGrantPrograms: `${CAMPAIGN_BASE_URL}/api/v1/competitions`,
+ getGrantProgram: (id: number | string) => `${CAMPAIGN_BASE_URL}/api/v1/competitions/${id}`,
}
// https://www.nasdaq.com/glossary/b/bip
diff --git a/src/hooks/useInvalidateTags.ts b/src/hooks/useInvalidateTags.ts
new file mode 100644
index 0000000000..3a1c9cb3e1
--- /dev/null
+++ b/src/hooks/useInvalidateTags.ts
@@ -0,0 +1,28 @@
+import { useCallback } from 'react'
+import announcementApi from 'services/announcement'
+import limitOrderApi from 'services/limitOrder'
+
+import kyberAIApi from 'pages/TrueSightV2/hooks/useKyberAIData'
+import { useAppDispatch } from 'state/hooks'
+
+const useInvalidateTags = (api: any) => {
+ const dispatch = useAppDispatch()
+ return useCallback(
+ (tag: string | string[]) => {
+ dispatch(api.util.invalidateTags(Array.isArray(tag) ? tag : [tag]))
+ },
+ [dispatch, api],
+ )
+}
+
+export const useInvalidateTagAnnouncement = () => {
+ return useInvalidateTags(announcementApi)
+}
+
+export const useInvalidateTagKyberAi = () => {
+ return useInvalidateTags(kyberAIApi)
+}
+
+export const useInvalidateTagLimitOrder = () => {
+ return useInvalidateTags(limitOrderApi)
+}
diff --git a/src/pages/Campaign/CampaignContent.tsx b/src/pages/Campaign/CampaignContent.tsx
index 27a96703e6..c43b010e8a 100644
--- a/src/pages/Campaign/CampaignContent.tsx
+++ b/src/pages/Campaign/CampaignContent.tsx
@@ -1,6 +1,6 @@
import { Trans, t } from '@lingui/macro'
import dayjs from 'dayjs'
-import { useEffect, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { isMobile } from 'react-device-detect'
import { BarChart, ChevronDown, Clock, Share2, Star, Users } from 'react-feather'
import { useSelector } from 'react-redux'
@@ -8,7 +8,6 @@ import { useNavigate } from 'react-router-dom'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
import styled, { css } from 'styled-components'
-import { useSWRConfig } from 'swr'
import { ButtonEmpty, ButtonLight } from 'components/Button'
import Divider from 'components/Divider'
@@ -18,7 +17,6 @@ import ProgressBar from 'components/ProgressBar'
import ShareModal from 'components/ShareModal'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import YourCampaignTransactionsModal from 'components/YourCampaignTransactionsModal'
-import { SWR_KEYS } from 'constants/index'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import useInterval from 'hooks/useInterval'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
@@ -57,6 +55,8 @@ import oembed2iframe from 'utils/oembed2iframe'
import ModalSelectCampaign from './ModalSelectCampaign'
+export const MINUTE_TO_REFRESH = 5 * 60
+
const LoaderParagraphs = () => (
<>
@@ -176,7 +176,7 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
const { mixpanelHandler } = useMixpanel()
- const above768 = useMedia(`(min-width: ${MEDIA_WIDTHS.upToSmall}px)`)
+ const upToSmall = useMedia(`(min-width: ${MEDIA_WIDTHS.upToSmall}px)`)
const campaignDetailImageRef = useRef(null)
const [campaignDetailMediaLoadedMap, setCampaignDetailMediaLoadedMap] = useState<{ [id: string]: boolean }>({})
@@ -313,9 +313,12 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
const toggleSelectCampaignModal = useSelectCampaignModalToggle()
const navigate = useNavigate()
- const onSelectCampaign = (campaign: CampaignData) => {
- navigate(getSlugUrlCampaign(campaign.id, campaign.name))
- }
+ const onSelectCampaign = useCallback(
+ (campaign: CampaignData) => {
+ navigate(getSlugUrlCampaign(campaign.id, campaign.name))
+ },
+ [navigate],
+ )
const now = Date.now()
@@ -323,13 +326,9 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
loadingCampaignData,
loadingCampaignDataError,
data: campaigns,
- selectedCampaignLeaderboardPageNumber,
- selectedCampaignLeaderboardLookupAddress,
} = useSelector((state: AppState) => state.campaigns)
- const MINUTE_TO_REFRESH = 5
- const [campaignsRefreshIn, setCampaignsRefreshIn] = useState(MINUTE_TO_REFRESH * 60)
- const { mutate } = useSWRConfig()
+ const [campaignsRefreshIn, setCampaignsRefreshIn] = useState(MINUTE_TO_REFRESH)
const dispatch = useAppDispatch()
useInterval(
() => {
@@ -339,10 +338,7 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
setCampaignData({
campaigns: campaigns.map(campaign => {
if (campaign.id === selectedCampaign.id) {
- return {
- ...campaign,
- status,
- }
+ return { ...campaign, status }
}
return campaign
}),
@@ -364,36 +360,12 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
) {
updateCampaignStatus(CampaignStatus.ENDED)
}
- setCampaignsRefreshIn(prev => {
- if (prev === 0) {
- return MINUTE_TO_REFRESH * 60
- }
- return prev - 1
- })
+ setCampaignsRefreshIn(prev => (prev === 0 ? MINUTE_TO_REFRESH : prev - 1))
},
selectedCampaign?.campaignState === CampaignState.CampaignStateReady ? 1000 : null,
true,
)
- useEffect(() => {
- if (campaignsRefreshIn === 0 && selectedCampaign) {
- mutate([
- selectedCampaign,
- SWR_KEYS.getLeaderboard(selectedCampaign.id),
- selectedCampaignLeaderboardPageNumber,
- selectedCampaignLeaderboardLookupAddress,
- account,
- ])
- }
- }, [
- mutate,
- campaignsRefreshIn,
- selectedCampaign,
- selectedCampaignLeaderboardPageNumber,
- selectedCampaignLeaderboardLookupAddress,
- account,
- ])
-
if (campaigns.length === 0 && loadingCampaignData) {
return
}
@@ -409,218 +381,214 @@ export default function Campaign({ refreshListCampaign, ...props }: CampaignProp
return (
<>
-
-
-
-
-
-
-
-
-
- Campaigns
-
-
-
-
-
-
-
-
-
-
-
-
- {
- setTimeout(() => {
- if (selectedCampaign)
- setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true }))
- }, 500)
- }}
- onError={() => {
+
+
+
+
+
+
+
+
+ Campaigns
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setTimeout(() => {
if (selectedCampaign)
setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true }))
- if (campaignDetailImageRef && campaignDetailImageRef.current) {
- campaignDetailImageRef.current.style.display = 'none'
- }
- }}
+ }, 500)
+ }}
+ onError={() => {
+ if (selectedCampaign)
+ setCampaignDetailMediaLoadedMap(prev => ({ ...prev, [selectedCampaign.id]: true }))
+ if (campaignDetailImageRef && campaignDetailImageRef.current) {
+ campaignDetailImageRef.current.style.display = 'none'
+ }
+ }}
+ />
+
+
+
+ {selectedCampaign?.name}
+
+
+
+
+
+
+
+ mixpanelHandler(MIXPANEL_TYPE.CAMPAIGN_SHARE_TRADING_CONTEST_CLICKED, {
+ campaign_name: selectedCampaign?.name,
+ })
+ }
/>
-
-
-
- {selectedCampaign?.name}
+
+
+
+
+
+ {selectedCampaign?.status === CampaignStatus.UPCOMING
+ ? t`Starting In`
+ : isOngoing
+ ? t`Ending In`
+ : t`Ended On`}
-
-
-
-
-
-
- mixpanelHandler(MIXPANEL_TYPE.CAMPAIGN_SHARE_TRADING_CONTEST_CLICKED, {
- campaign_name: selectedCampaign?.name,
- })
- }
- />
-
-
-
-
-
- {selectedCampaign?.status === CampaignStatus.UPCOMING
- ? t`Starting In`
- : isOngoing
- ? t`Ending In`
- : t`Ended On`}
+
+ {isSelectedCampaignMediaLoaded ? (
+ <>
+ {selectedCampaign.status === CampaignStatus.UPCOMING && (
+
+
+ {selectedCampaign
+ ? getFormattedTimeFromSecond((selectedCampaign.startTime - now) / 1000)
+ : '--'}
+
+
+ )}
+ {selectedCampaign.status === CampaignStatus.ONGOING && (
+
+
+ {selectedCampaign ? getFormattedTimeFromSecond((selectedCampaign.endTime - now) / 1000) : '--'}
+
+
+ )}
+ {selectedCampaign.status === CampaignStatus.ENDED && (
+
+ {dayjs(selectedCampaign.endTime).format('YYYY-MM-DD HH:mm')}
+
+ )}
+ >
+ ) : (
+
+ )}
+
+
+
+ Participants
+
+ {!isMobile && }
+ {isSelectedCampaignMediaLoaded ? (
+
+ {selectedCampaignLeaderboard?.totalParticipants
+ ? formatNumberWithPrecisionRange(selectedCampaignLeaderboard.totalParticipants, 0, 0)
+ : '--'}
-
- {isSelectedCampaignMediaLoaded ? (
- <>
- {selectedCampaign.status === CampaignStatus.UPCOMING && (
-
-
- {selectedCampaign
- ? getFormattedTimeFromSecond((selectedCampaign.startTime - now) / 1000)
- : '--'}
-
-
- )}
- {selectedCampaign.status === CampaignStatus.ONGOING && (
-
-
- {selectedCampaign
- ? getFormattedTimeFromSecond((selectedCampaign.endTime - now) / 1000)
- : '--'}
-
-
- )}
- {selectedCampaign.status === CampaignStatus.ENDED && (
-
- {dayjs(selectedCampaign.endTime).format('YYYY-MM-DD HH:mm')}
+ ) : (
+
+ )}
+
+
+
+ Your Rank
+ {isMobile && }
+
+ {!isMobile && }
+ {isSelectedCampaignMediaLoaded ? (
+ account ? (
+
+
+
+ {selectedCampaign?.userInfo?.rankNo
+ ? formatNumberWithPrecisionRange(selectedCampaign?.userInfo?.rankNo, 0, 2)
+ : '--'}
- )}
- >
- ) : (
-
- )}
-
-
-
- Participants
-
- {!isMobile && }
- {isSelectedCampaignMediaLoaded ? (
-
- {selectedCampaignLeaderboard?.totalParticipants
- ? formatNumberWithPrecisionRange(selectedCampaignLeaderboard.totalParticipants, 0, 0)
- : '--'}
-
- ) : (
-
- )}
-
-
-
- Your Rank
- {isMobile && }
-
- {!isMobile && }
- {isSelectedCampaignMediaLoaded ? (
- account ? (
-
-
-
- {selectedCampaign?.userInfo?.rankNo
- ? formatNumberWithPrecisionRange(selectedCampaign?.userInfo?.rankNo, 0, 2)
- : '--'}
-
- {!isMobile && }
-
-
- {above768 ? Your Transactions : History}
-
+ {!isMobile && }
- ) : (
-
- Connect
-
- )
+
+ {upToSmall ? Your Transactions : History}
+
+
) : (
-
- )}
-
-
-
-
- setActiveTab(CampaignTab.HOW_TO_WIN)}
- >
- How to win
-
- setActiveTab(CampaignTab.REWARDS)}
- >
- Rewards
-
+
+ Connect
+
+ )
+ ) : (
+
+ )}
+
+
+
+
+ setActiveTab(CampaignTab.HOW_TO_WIN)}
+ >
+ How to win
+
+ setActiveTab(CampaignTab.REWARDS)}
+ >
+ Rewards
+
+ setActiveTab(CampaignTab.LEADERBOARD)}
+ >
+ Leaderboard
+
+ {selectedCampaign && selectedCampaign.campaignState === CampaignState.CampaignStateDistributedRewards && (
setActiveTab(CampaignTab.LEADERBOARD)}
+ active={activeTab === CampaignTab.LUCKY_WINNER}
+ onClick={() => setActiveTab(CampaignTab.LUCKY_WINNER)}
>
- Leaderboard
+ Lucky Winners
- {selectedCampaign && selectedCampaign.campaignState === CampaignState.CampaignStateDistributedRewards && (
- setActiveTab(CampaignTab.LUCKY_WINNER)}
- >
- Lucky Winners
-
- )}
-
+ )}
+
-
- {activeTab === CampaignTab.HOW_TO_WIN && }
- {activeTab === CampaignTab.REWARDS && }
- {activeTab === CampaignTab.LEADERBOARD && (
-
- )}
- {activeTab === CampaignTab.LUCKY_WINNER && (
-
- )}
-
-
-
+
+ {activeTab === CampaignTab.HOW_TO_WIN && }
+ {activeTab === CampaignTab.REWARDS && }
+ {activeTab === CampaignTab.LEADERBOARD && (
+
+ )}
+ {activeTab === CampaignTab.LUCKY_WINNER && (
+
+ )}
+
+
>
@@ -753,7 +721,9 @@ const PageWrapper = styled.div`
padding: 32px 24px 50px;
width: 100%;
max-width: 1500px;
-
+ display: flex;
+ gap: 24px;
+ min-height: calc(100vh - 84.34px - 24px - 24px - 62px);
${({ theme }) => theme.mediaWidth.upToSmall`
${css`
padding: 24px 16px 100px;
@@ -761,13 +731,6 @@ const PageWrapper = styled.div`
`}
`
-const CampaignContainer = styled.div`
- display: flex;
- gap: 24px;
- min-height: calc(100vh - 84.34px - 24px - 24px - 62px);
- overflow: auto;
-`
-
const CampaignDetail = styled.div`
flex: 2;
overflow: auto;
diff --git a/src/pages/Campaign/CampaignListAndSearch.tsx b/src/pages/Campaign/CampaignListAndSearch.tsx
index c75ca9c18a..7457b1ccf4 100644
--- a/src/pages/Campaign/CampaignListAndSearch.tsx
+++ b/src/pages/Campaign/CampaignListAndSearch.tsx
@@ -1,5 +1,5 @@
import { Trans, t } from '@lingui/macro'
-import { useCallback, useEffect, useRef, useState } from 'react'
+import { memo, useCallback, useEffect, useRef, useState } from 'react'
import { useSelector } from 'react-redux'
import AutoSizer from 'react-virtualized-auto-sizer'
import { VariableSizeList } from 'react-window'
@@ -172,4 +172,4 @@ const CampaignListAndSearch = ({
)
}
-export default CampaignListAndSearch
+export default memo(CampaignListAndSearch)
diff --git a/src/pages/Campaign/LeaderboardLayout.tsx b/src/pages/Campaign/LeaderboardLayout.tsx
index 80ff77ca21..5e7b669170 100644
--- a/src/pages/Campaign/LeaderboardLayout.tsx
+++ b/src/pages/Campaign/LeaderboardLayout.tsx
@@ -1,11 +1,12 @@
import { Trans, t } from '@lingui/macro'
import dayjs from 'dayjs'
import { rgba } from 'polished'
-import { useEffect } from 'react'
+import { useEffect, useState } from 'react'
import { Clock } from 'react-feather'
import { useSelector } from 'react-redux'
import { useMedia, useSize } from 'react-use'
import { Flex, Text } from 'rebass'
+import { useGetLuckyWinnersQuery } from 'services/campaign'
import styled, { css } from 'styled-components'
import Bronze from 'assets/svg/bronze_icon.svg'
@@ -14,15 +15,13 @@ import Silver from 'assets/svg/silver_icon.svg'
import InfoHelper from 'components/InfoHelper'
import Pagination from 'components/Pagination'
import Search, { Container as SearchContainer, Wrapper as SearchWrapper } from 'components/Search'
-import { BIG_INT_ZERO, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, DEFAULT_SIGNIFICANT } from 'constants/index'
+import { BIG_INT_ZERO, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, DEFAULT_SIGNIFICANT, EMPTY_ARRAY } from 'constants/index'
import useTheme from 'hooks/useTheme'
import { AppState } from 'state'
import { CampaignState, CampaignStatus, RewardRandom } from 'state/campaigns/actions'
import {
useSelectedCampaignLeaderboardLookupAddressManager,
useSelectedCampaignLeaderboardPageNumberManager,
- useSelectedCampaignLuckyWinnerPageNumber,
- useSelectedCampaignLuckyWinnersLookupAddressManager,
} from 'state/campaigns/hooks'
import { formatNumberWithPrecisionRange } from 'utils'
import getShortenAddress from 'utils/getShortenAddress'
@@ -48,35 +47,44 @@ export default function LeaderboardLayout({
))
- const { selectedCampaignLeaderboard, selectedCampaignLuckyWinners, selectedCampaign } = useSelector(
- (state: AppState) => state.campaigns,
- )
-
- const [currentPage, setCurrentPage] = useSelectedCampaignLeaderboardPageNumberManager()
- const [currentPageLuckyWinner, setCurrentPageLuckyWinner] = useSelectedCampaignLuckyWinnerPageNumber()
+ const { selectedCampaignLeaderboard, selectedCampaign } = useSelector((state: AppState) => state.campaigns)
const [leaderboardSearchValue, setLeaderboardSearchValue] = useSelectedCampaignLeaderboardLookupAddressManager()
- const [luckyWinnersSearchValue, setLuckyWinnersSearchValue] = useSelectedCampaignLuckyWinnersLookupAddressManager()
+
+ const [luckyWinnersSearchValue, setLuckyWinnersSearchValue] = useState('')
+
const [searchValue, setSearchValue] =
type === 'leaderboard'
? [leaderboardSearchValue, setLeaderboardSearchValue]
: [luckyWinnersSearchValue, setLuckyWinnersSearchValue]
+ const [currentPageLuckyWinner, setCurrentPageLuckyWinner] = useState(0)
+ const { currentData: dataLuckWinners } = useGetLuckyWinnersQuery(
+ {
+ pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE,
+ pageNumber: currentPageLuckyWinner,
+ lookupAddress: luckyWinnersSearchValue,
+ campaignId: selectedCampaign?.id || 0,
+ },
+ { skip: !selectedCampaign?.id },
+ )
+
+ const luckyWinners =
+ (selectedCampaign?.campaignState === CampaignState.CampaignStateReady ? EMPTY_ARRAY : dataLuckWinners) ||
+ EMPTY_ARRAY
+
+ const [currentPage, setCurrentPage] = useSelectedCampaignLeaderboardPageNumberManager()
let totalItems = 0
- if (type === 'leaderboard') {
- if (selectedCampaignLeaderboard) {
- totalItems = leaderboardSearchValue ? 1 : selectedCampaignLeaderboard.totalParticipants
- }
+ if (type === 'leaderboard' && selectedCampaignLeaderboard) {
+ totalItems = leaderboardSearchValue ? 1 : selectedCampaignLeaderboard.totalParticipants
}
- if (type === 'lucky_winner') {
- if (selectedCampaign && selectedCampaignLeaderboard) {
- const randomRewards = selectedCampaign.rewardDistribution.filter(reward => reward.type === 'Random')
- const totalRandomRewardItems = randomRewards.reduce(
- (acc, reward) => acc + ((reward as RewardRandom).nWinners ?? 0),
- 0,
- )
-
- totalItems = searchValue ? 1 : Math.min(totalRandomRewardItems, selectedCampaignLeaderboard.totalParticipants)
- }
+ if (type === 'lucky_winner' && selectedCampaign && selectedCampaignLeaderboard) {
+ const randomRewards = selectedCampaign.rewardDistribution.filter(reward => reward.type === 'Random')
+ const totalRandomRewardItems = randomRewards.reduce(
+ (acc, reward) => acc + ((reward as RewardRandom).nWinners ?? 0),
+ 0,
+ )
+
+ totalItems = searchValue ? 1 : Math.min(totalRandomRewardItems, selectedCampaignLeaderboard.totalParticipants)
}
const refreshInMinute = Math.floor(refreshIn / 60)
@@ -143,7 +151,7 @@ export default function LeaderboardLayout({
)
})
- const luckyWinnersTableBody = selectedCampaignLuckyWinners.map((luckyWinner, index) => {
+ const luckyWinnersTableBody = luckyWinners.map((luckyWinner, index) => {
return (
diff --git a/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx b/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx
index 49a28fef71..5c1cb04d74 100644
--- a/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx
+++ b/src/pages/Campaign/ModalRegisterCampaignCaptcha.tsx
@@ -1,13 +1,12 @@
import { Trans } from '@lingui/macro'
-import axios from 'axios'
import { createRef, memo, useCallback } from 'react'
import ReCAPTCHA from 'react-google-recaptcha'
import { Text } from 'rebass'
+import { useJoinCampaignMutation } from 'services/campaign'
import styled from 'styled-components'
import { ModalCenter } from 'components/Modal'
import { GOOGLE_RECAPTCHA_KEY } from 'constants/env'
-import { CAMPAIGN_BASE_URL } from 'constants/index'
import { useActiveWeb3React } from 'hooks'
import useTheme from 'hooks/useTheme'
import { ApplicationModal } from 'state/application/actions'
@@ -44,7 +43,7 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp
const theme = useTheme()
const { account } = useActiveWeb3React()
-
+ const [joinCampaign] = useJoinCampaignMutation()
// Create an event handler, so you can call the verification on button click event or form submit
const handleReCaptchaVerify = useCallback(async () => {
if (!recaptchaCampaign.id || !account) return
@@ -64,18 +63,13 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp
const token = await recaptchaRef.current.getValue()
await new Promise(r => setTimeout(r, 750))
toggleRegisterCampaignCaptchaModal()
- const response = await axios({
- method: 'POST',
- url: `${CAMPAIGN_BASE_URL}/${recaptchaCampaign.id}/participants`,
- data: {
- token,
- address: account,
- },
- })
- if (response.status === 200) {
- refreshListCampaign()
- toggleRegisterCampaignSuccessModal()
- }
+ await joinCampaign({
+ token,
+ address: account,
+ recaptchaId: recaptchaCampaign.id,
+ }).unwrap()
+ refreshListCampaign()
+ toggleRegisterCampaignSuccessModal()
} catch (err) {
console.error(err)
} finally {
@@ -91,6 +85,7 @@ const ModalRegisterCampaignCaptcha = ({ refreshListCampaign }: { refreshListCamp
updateRecaptchaCampaignId,
updateRecaptchaCampaignLoading,
refreshListCampaign,
+ joinCampaign,
])
return (
diff --git a/src/pages/Campaign/ModalSelectCampaign.tsx b/src/pages/Campaign/ModalSelectCampaign.tsx
index 6d5d8cb6f0..52510faf5e 100644
--- a/src/pages/Campaign/ModalSelectCampaign.tsx
+++ b/src/pages/Campaign/ModalSelectCampaign.tsx
@@ -27,7 +27,7 @@ const ModalSelectCampaign = (props: {
}, 200)
}
return (
-
+
diff --git a/src/pages/Campaign/index.tsx b/src/pages/Campaign/index.tsx
index 77057cdc1f..7f073f2521 100644
--- a/src/pages/Campaign/index.tsx
+++ b/src/pages/Campaign/index.tsx
@@ -1,113 +1,28 @@
-import { ZERO } from '@kyberswap/ks-sdk-classic'
-import { Fraction } from '@kyberswap/ks-sdk-core'
-import axios from 'axios'
-import { parseUnits } from 'ethers/lib/utils'
-import JSBI from 'jsbi'
-import { stringify } from 'querystring'
import { useCallback, useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useLocation, useNavigate } from 'react-router-dom'
-import useSWR, { mutate } from 'swr'
-import useSWRImmutable from 'swr/immutable'
+import { useGetCampaignsQuery, useGetLeaderboardQuery } from 'services/campaign'
-import { APP_PATHS, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, RESERVE_USD_DECIMALS, SWR_KEYS } from 'constants/index'
+import { APP_PATHS, CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE, EMPTY_ARRAY } from 'constants/index'
import { useActiveWeb3React } from 'hooks'
import useParsedQueryString from 'hooks/useParsedQueryString'
import {
- CampaignData,
CampaignLeaderboard,
- CampaignLeaderboardRanking,
- CampaignLeaderboardReward,
- CampaignLuckyWinner,
- CampaignState,
- CampaignStatus,
- RewardDistribution,
setCampaignDataByPage,
setLastTimeRefreshData,
setLoadingCampaignData,
setLoadingCampaignDataError,
setLoadingSelectedCampaignLeaderboard,
- setLoadingSelectedCampaignLuckyWinners,
setSelectedCampaign,
setSelectedCampaignLeaderboard,
- setSelectedCampaignLuckyWinners,
} from 'state/campaigns/actions'
import { AppState } from 'state/index'
-import { SerializedToken } from 'state/user/actions'
import { getCampaignIdFromSlug, getSlugUrlCampaign } from 'utils/campaign'
-import CampaignContent from './CampaignContent'
+import CampaignContent, { MINUTE_TO_REFRESH } from './CampaignContent'
const MAXIMUM_ITEMS_PER_REQUEST = 10
-const getCampaignStatus = ({ endTime, startTime }: CampaignData) => {
- const now = Date.now()
- return endTime <= now ? CampaignStatus.ENDED : startTime >= now ? CampaignStatus.UPCOMING : CampaignStatus.ONGOING
-}
-
-const formatRewards = (rewards: CampaignLeaderboardReward[]) =>
- rewards?.map(
- (item: any): CampaignLeaderboardReward => ({
- rewardAmount: new Fraction(
- item.RewardAmount,
- JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.Token?.decimals ?? 18)),
- ),
- ref: item.Ref,
- claimed: item.Claimed,
- token: item.Token,
- }),
- ) || []
-
-const formatLeaderboardData = (data: CampaignLeaderboard) => {
- const leaderboard: CampaignLeaderboard = {
- ...data,
- rankings: data.rankings
- ? data.rankings.map(
- (item: any): CampaignLeaderboardRanking => ({
- userAddress: item.userAddress,
- totalPoint: item.totalPoint,
- rankNo: item.rankNo,
- rewardAmount: new Fraction(
- item.rewardAmount || ZERO,
- JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)),
- ),
- rewardAmountUsd: new Fraction(
- parseUnits(item?.rewardAmountUSD?.toString() || '0', RESERVE_USD_DECIMALS).toString(),
- JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(RESERVE_USD_DECIMALS)),
- ),
- rewardInUSD: item.rewardInUSD,
- token: item.token,
- }),
- )
- : [],
- rewards: formatRewards(data.rewards),
- }
- return leaderboard
-}
-
-const fetchLeaderBoard = ({
- pageNumber,
- userAddress,
- lookupAddress,
- campaignId,
-}: {
- pageNumber: number
- userAddress: string
- lookupAddress: string
- campaignId: number
-}) => {
- return axios({
- method: 'GET',
- url: SWR_KEYS.getLeaderboard(campaignId),
- params: {
- pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE,
- pageNumber,
- userAddress,
- lookupAddress,
- },
- }).then(({ data }) => formatLeaderboardData(data.data))
-}
-
const LEADERBOARD_DEFAULT: CampaignLeaderboard = {
finalizedAt: 0,
distributedRewardsAt: 0,
@@ -117,115 +32,6 @@ const LEADERBOARD_DEFAULT: CampaignLeaderboard = {
rewards: [],
}
-const formatListCampaign = (response: CampaignData[]) => {
- const campaigns: CampaignData[] = response.map((item: CampaignData) => ({
- ...item,
- startTime: item.startTime * 1000,
- endTime: item.endTime * 1000,
- }))
- const formattedCampaigns: CampaignData[] = campaigns.map((campaign: any) => {
- const rewardDistribution: RewardDistribution[] = []
- if (campaign.rewardDistribution.single) {
- campaign.rewardDistribution.single.forEach(
- ({
- amount,
- rank,
- token,
- rewardInUSD,
- }: {
- amount: string
- rank: number
- token: SerializedToken
- rewardInUSD: boolean
- }) => {
- rewardDistribution.push({
- type: 'Single',
- amount,
- rank,
- token,
- rewardInUSD,
- })
- },
- )
- }
- if (campaign.rewardDistribution.range) {
- campaign.rewardDistribution.range.forEach(
- ({
- from,
- to,
- amount,
- token,
- rewardInUSD,
- }: {
- from: number
- to: number
- amount: string
- token: SerializedToken
- rewardInUSD: boolean
- }) => {
- rewardDistribution.push({
- type: 'Range',
- from,
- to,
- amount,
- token,
- rewardInUSD,
- })
- },
- )
- }
- if (campaign.rewardDistribution.random) {
- campaign.rewardDistribution.random.forEach(
- ({
- from,
- to,
- amount,
- numberOfWinners,
- token,
- rewardInUSD,
- }: {
- from: number
- to: number
- amount: string
- numberOfWinners: number
- token: SerializedToken
- rewardInUSD: boolean
- }) => {
- rewardDistribution.push({
- type: 'Random',
- from,
- to,
- amount,
- nWinners: numberOfWinners,
- token,
- rewardInUSD,
- })
- },
- )
- }
- if (campaign?.userInfo?.tradingVolume) campaign.userInfo.tradingVolume = Number(campaign.userInfo.tradingVolume)
- if (campaign.userInfo) campaign.userInfo.rewards = formatRewards(campaign.userInfo.rewards)
- return {
- ...campaign,
- rewardDistribution,
- status: getCampaignStatus(campaign),
- eligibleTokens: campaign.eligibleTokens.map(
- ({ chainId, name, symbol, address, logoURI, decimals }: SerializedToken) => {
- return {
- chainId,
- name,
- symbol,
- address,
- logoURI,
- decimals,
- }
- },
- ),
- }
- })
- return formattedCampaigns
-}
-
const getQueryDefault = (userAddress: string | undefined) => ({
campaignName: '',
userAddress,
@@ -247,7 +53,6 @@ export default function CampaignsUpdater() {
}, [])
const { data: currentCampaigns } = useSelector((state: AppState) => state.campaigns)
- const getCampaignUrl = useCallback(() => `${SWR_KEYS.getListCampaign}?${stringify(queryParams)}`, [queryParams])
const loadMoreCampaign = useCallback(() => {
if (!currentCampaigns.length) return
@@ -259,24 +64,22 @@ export default function CampaignsUpdater() {
}, [account, setQueryParams])
const {
- data: campaignData,
- isValidating: isLoadingCampaignData,
+ data: campaignData = EMPTY_ARRAY,
+ isFetching: isLoadingCampaignData,
error: loadingCampaignDataError,
- } = useSWR(getCampaignUrl(), async url => {
- try {
- const { data: response } = await axios.get(url)
- const campaigns: CampaignData[] = response.data
- setHasMoreCampaign(campaigns.length === MAXIMUM_ITEMS_PER_REQUEST)
- return formatListCampaign(campaigns)
- } catch (error) {
- return []
- }
- })
+ refetch,
+ } = useGetCampaignsQuery(queryParams)
+
+ useEffect(() => {
+ setHasMoreCampaign(campaignData.length === MAXIMUM_ITEMS_PER_REQUEST)
+ }, [campaignData])
const refreshListCampaign = useCallback(async () => {
- await mutate(getCampaignUrl())
- dispatch(setLastTimeRefreshData())
- }, [getCampaignUrl, dispatch])
+ try {
+ await refetch().unwrap()
+ dispatch(setLastTimeRefreshData())
+ } catch (error) {}
+ }, [refetch, dispatch])
const slug = pathname.replace(APP_PATHS.CAMPAIGN, '')
const { selectedCampaignId = getCampaignIdFromSlug(slug) } = useParsedQueryString<{ selectedCampaignId: string }>()
@@ -294,7 +97,7 @@ export default function CampaignsUpdater() {
replace: true,
})
}
- if (selectedCampaignId === undefined) {
+ if (!selectedCampaignId) {
navigateFirsOne()
return
}
@@ -311,7 +114,7 @@ export default function CampaignsUpdater() {
}, [dispatch, isLoadingCampaignData])
useEffect(() => {
- dispatch(setLoadingCampaignDataError(loadingCampaignDataError))
+ dispatch(setLoadingCampaignDataError(!!loadingCampaignDataError))
}, [dispatch, loadingCampaignDataError])
/**********************CAMPAIGN LEADERBOARD**********************/
@@ -319,33 +122,15 @@ export default function CampaignsUpdater() {
const { selectedCampaignLeaderboardPageNumber, selectedCampaignLeaderboardLookupAddress, selectedCampaign } =
useSelector((state: AppState) => state.campaigns)
- const { data: leaderboard, isValidating: isLoadingLeaderboard } = useSWRImmutable(
- selectedCampaign
- ? [
- selectedCampaign,
- SWR_KEYS.getLeaderboard(selectedCampaign.id),
- selectedCampaignLeaderboardPageNumber,
- selectedCampaignLeaderboardLookupAddress,
- account,
- ]
- : null,
- async () => {
- if (!selectedCampaign) {
- return LEADERBOARD_DEFAULT
- }
-
- try {
- return fetchLeaderBoard({
- campaignId: selectedCampaign.id,
- pageNumber: selectedCampaignLeaderboardPageNumber,
- userAddress: account ?? '',
- lookupAddress: selectedCampaignLeaderboardLookupAddress,
- })
- } catch (err) {
- console.error(err)
- return LEADERBOARD_DEFAULT
- }
+ const { currentData: leaderboard = LEADERBOARD_DEFAULT, isFetching: isLoadingLeaderboard } = useGetLeaderboardQuery(
+ {
+ campaignId: selectedCampaign?.id || 0,
+ pageNumber: selectedCampaignLeaderboardPageNumber,
+ userAddress: account ?? '',
+ lookupAddress: selectedCampaignLeaderboardLookupAddress,
+ pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE,
},
+ { skip: !selectedCampaign?.id, pollingInterval: MINUTE_TO_REFRESH * 1000 },
)
useEffect(() => {
@@ -358,63 +143,6 @@ export default function CampaignsUpdater() {
dispatch(setLoadingSelectedCampaignLeaderboard(isLoadingLeaderboard))
}, [dispatch, isLoadingLeaderboard])
- /**********************CAMPAIGN LUCKY WINNERS**********************/
-
- const { selectedCampaignLuckyWinnersPageNumber, selectedCampaignLuckyWinnersLookupAddress } = useSelector(
- (state: AppState) => state.campaigns,
- )
-
- const { data: luckyWinners, isValidating: isLoadingLuckyWinners } = useSWRImmutable(
- selectedCampaign
- ? [
- selectedCampaign,
- SWR_KEYS.getLuckyWinners(selectedCampaign.id),
- selectedCampaignLuckyWinnersPageNumber,
- selectedCampaignLuckyWinnersLookupAddress,
- ]
- : null,
- async () => {
- if (!selectedCampaign || selectedCampaign.campaignState === CampaignState.CampaignStateReady) return []
-
- try {
- const response = await axios({
- method: 'GET',
- url: SWR_KEYS.getLuckyWinners(selectedCampaign.id),
- params: {
- pageSize: CAMPAIGN_LEADERBOARD_ITEM_PER_PAGE,
- pageNumber: selectedCampaignLuckyWinnersPageNumber,
- lookupAddress: selectedCampaignLuckyWinnersLookupAddress,
- },
- })
- const data = response.data.data
- const luckyWinners: CampaignLuckyWinner[] = data.map(
- (item: any): CampaignLuckyWinner => ({
- userAddress: item.userAddress,
- rewardAmount: new Fraction(
- item.rewardAmount,
- JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)),
- ),
- token: item.token,
- }),
- )
- return luckyWinners
- } catch (err) {
- console.error(err)
- return []
- }
- },
- )
-
- useEffect(() => {
- if (luckyWinners !== undefined) {
- dispatch(setSelectedCampaignLuckyWinners({ luckyWinners: luckyWinners }))
- }
- }, [dispatch, luckyWinners])
-
- useEffect(() => {
- dispatch(setLoadingSelectedCampaignLuckyWinners(isLoadingLuckyWinners))
- }, [dispatch, isLoadingLuckyWinners])
-
return (
{
+ const now = Date.now()
+ return endTime <= now ? CampaignStatus.ENDED : startTime >= now ? CampaignStatus.UPCOMING : CampaignStatus.ONGOING
+}
+
+const formatRewards = (rewards: CampaignLeaderboardReward[]) =>
+ rewards?.map(
+ (item: any): CampaignLeaderboardReward => ({
+ rewardAmount: new Fraction(
+ item.RewardAmount,
+ JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.Token?.decimals ?? 18)),
+ ),
+ ref: item.Ref,
+ claimed: item.Claimed,
+ token: item.Token,
+ }),
+ ) || []
+
+const formatListCampaign = (response: CampaignData[]) => {
+ const campaigns: CampaignData[] = response.map((item: CampaignData) => ({
+ ...item,
+ startTime: item.startTime * 1000,
+ endTime: item.endTime * 1000,
+ }))
+ const formattedCampaigns: CampaignData[] = campaigns.map((campaign: any) => {
+ const rewardDistribution: RewardDistribution[] = []
+ if (campaign.rewardDistribution.single) {
+ campaign.rewardDistribution.single.forEach(
+ ({
+ amount,
+ rank,
+ token,
+ rewardInUSD,
+ }: {
+ amount: string
+ rank: number
+ token: SerializedToken
+ rewardInUSD: boolean
+ }) => {
+ rewardDistribution.push({
+ type: 'Single',
+ amount,
+ rank,
+ token,
+ rewardInUSD,
+ })
+ },
+ )
+ }
+ if (campaign.rewardDistribution.range) {
+ campaign.rewardDistribution.range.forEach(
+ ({
+ from,
+ to,
+ amount,
+ token,
+ rewardInUSD,
+ }: {
+ from: number
+ to: number
+ amount: string
+ token: SerializedToken
+ rewardInUSD: boolean
+ }) => {
+ rewardDistribution.push({
+ type: 'Range',
+ from,
+ to,
+ amount,
+ token,
+ rewardInUSD,
+ })
+ },
+ )
+ }
+ if (campaign.rewardDistribution.random) {
+ campaign.rewardDistribution.random.forEach(
+ ({
+ from,
+ to,
+ amount,
+ numberOfWinners,
+ token,
+ rewardInUSD,
+ }: {
+ from: number
+ to: number
+ amount: string
+ numberOfWinners: number
+ token: SerializedToken
+ rewardInUSD: boolean
+ }) => {
+ rewardDistribution.push({
+ type: 'Random',
+ from,
+ to,
+ amount,
+ nWinners: numberOfWinners,
+ token,
+ rewardInUSD,
+ })
+ },
+ )
+ }
+ if (campaign?.userInfo?.tradingVolume) campaign.userInfo.tradingVolume = Number(campaign.userInfo.tradingVolume)
+ if (campaign.userInfo) campaign.userInfo.rewards = formatRewards(campaign.userInfo.rewards)
+ return {
+ ...campaign,
+ rewardDistribution,
+ status: getCampaignStatus(campaign),
+ eligibleTokens: campaign.eligibleTokens.map(
+ ({ chainId, name, symbol, address, logoURI, decimals }: SerializedToken) => {
+ return {
+ chainId,
+ name,
+ symbol,
+ address,
+ logoURI,
+ decimals,
+ }
+ },
+ ),
+ }
+ })
+ return formattedCampaigns
+}
+
+const formatLeaderboardData = (data: CampaignLeaderboard) => {
+ const leaderboard: CampaignLeaderboard = {
+ ...data,
+ rankings: data.rankings
+ ? data.rankings.map(
+ (item: any): CampaignLeaderboardRanking => ({
+ userAddress: item.userAddress,
+ totalPoint: item.totalPoint,
+ rankNo: item.rankNo,
+ rewardAmount: new Fraction(
+ item.rewardAmount || ZERO,
+ JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)),
+ ),
+ rewardAmountUsd: new Fraction(
+ parseUnits(item?.rewardAmountUSD?.toString() || '0', RESERVE_USD_DECIMALS).toString(),
+ JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(RESERVE_USD_DECIMALS)),
+ ),
+ rewardInUSD: item.rewardInUSD,
+ token: item.token,
+ }),
+ )
+ : [],
+ rewards: formatRewards(data.rewards),
+ }
+ return leaderboard
+}
+
+const formatLuckyWinners = (data: any[]) => {
+ const luckyWinners: CampaignLuckyWinner[] = data.map(
+ (item: any): CampaignLuckyWinner => ({
+ userAddress: item.userAddress,
+ rewardAmount: new Fraction(
+ item.rewardAmount,
+ JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(item?.token?.decimals ?? 18)),
+ ),
+ token: item.token,
+ }),
+ )
+ return luckyWinners
+}
+
+const formatTxs = (data: any[]) => {
+ return data.map(
+ (item: any): CampaignProofData => ({
+ id: item.id,
+ chainId: parseInt(item.chainId),
+ utcTimestamp: new Date(item.time).getTime(),
+ txPoint: item.txPoint,
+ txHash: item.tx,
+ }),
+ )
+}
+
+const campaignApi = createApi({
+ reducerPath: 'campaignApi',
+ baseQuery: fetchBaseQuery({ baseUrl: `${CAMPAIGN_BASE_URL}/api/v1/campaigns` }),
+ endpoints: builder => ({
+ getCampaigns: builder.query({
+ query: params => ({
+ params,
+ url: '',
+ }),
+ transformResponse: (data: any) => formatListCampaign(data?.data || []),
+ }),
+ getLeaderboard: builder.query<
+ any,
+ { pageSize: number; pageNumber: number; userAddress: string; lookupAddress: string; campaignId: number }
+ >({
+ query: ({ campaignId, ...params }) => ({
+ params,
+ url: `/${campaignId}/leaderboard`,
+ }),
+ transformResponse: (data: any) => formatLeaderboardData(data?.data),
+ }),
+ getLuckyWinners: builder.query<
+ CampaignLuckyWinner[],
+ { pageSize: number; pageNumber: number; lookupAddress: string; campaignId: number }
+ >({
+ query: ({ campaignId, ...params }) => ({
+ params,
+ url: `/${campaignId}/lucky-winners`,
+ }),
+ transformResponse: (data: any) => formatLuckyWinners(data?.data || []),
+ }),
+ getTxsCampaign: builder.query<
+ CampaignProofData[],
+ { limit: number; offset: number; userAddress: string; campaignId: number }
+ >({
+ query: ({ campaignId, ...params }) => ({
+ params,
+ url: `/${campaignId}/proofs`,
+ }),
+ transformResponse: (data: any) => formatTxs(data?.data || []),
+ }),
+ joinCampaign: builder.mutation({
+ query: ({ recaptchaId, ...body }) => ({
+ body,
+ method: 'POST',
+ url: `/${recaptchaId}/participants`,
+ }),
+ }),
+ }),
+})
+
+export const {
+ useGetCampaignsQuery,
+ useGetLeaderboardQuery,
+ useGetLuckyWinnersQuery,
+ useJoinCampaignMutation,
+ useGetTxsCampaignQuery,
+} = campaignApi
+
+export default campaignApi
diff --git a/src/state/campaigns/actions.ts b/src/state/campaigns/actions.ts
index d8c3013db9..79e77b3f85 100644
--- a/src/state/campaigns/actions.ts
+++ b/src/state/campaigns/actions.ts
@@ -145,7 +145,7 @@ export const setLoadingCampaignData = createAction('campaigns/setLoadin
export const setLastTimeRefreshData = createAction('campaigns/setLastTimeRefreshData')
-export const setLoadingCampaignDataError = createAction('campaigns/setLoadingCampaignDataError')
+export const setLoadingCampaignDataError = createAction('campaigns/setLoadingCampaignDataError')
export const setSelectedCampaign = createAction<{ campaign: CampaignData }>('campaigns/setSelectedCampaign')
@@ -164,18 +164,5 @@ export const setSelectedCampaignLeaderboardLookupAddress = createAction(
export const setClaimingCampaignRewardId = createAction('campaigns/setClaimingCampaignRewardId')
-export const setSelectedCampaignLuckyWinners = createAction<{ luckyWinners: CampaignLuckyWinner[] }>(
- 'campaigns/setSelectedCampaignLuckyWinners',
-)
-export const setLoadingSelectedCampaignLuckyWinners = createAction(
- 'campaigns/setLoadingSelectedCampaignLuckyWinners',
-)
-export const setSelectedCampaignLuckyWinnersPageNumber = createAction(
- 'campaigns/setSelectedCampaignLuckyWinnersPageNumber',
-)
-export const setSelectedCampaignLuckyWinnersLookupAddress = createAction(
- 'campaigns/setSelectedCampaignLuckyWinnersLookupAddress',
-)
-
export const setRecaptchaCampaignId = createAction('campaigns/setRecaptchaCampaignId')
export const setRecaptchaCampaignLoading = createAction('campaigns/setRecaptchaCampaignLoading')
diff --git a/src/state/campaigns/hooks.ts b/src/state/campaigns/hooks.ts
index b38df444a7..2151d9f883 100644
--- a/src/state/campaigns/hooks.ts
+++ b/src/state/campaigns/hooks.ts
@@ -10,8 +10,6 @@ import {
setRecaptchaCampaignLoading,
setSelectedCampaignLeaderboardLookupAddress,
setSelectedCampaignLeaderboardPageNumber,
- setSelectedCampaignLuckyWinnersLookupAddress,
- setSelectedCampaignLuckyWinnersPageNumber,
} from 'state/campaigns/actions'
import { AppState } from 'state/index'
@@ -31,20 +29,6 @@ export function useSelectedCampaignLeaderboardPageNumberManager(): [number, (pag
return [selectedCampaignLeaderboardPageNumber, updateSelectedCampaignLeaderboardPageNumberCallback]
}
-export function useSelectedCampaignLuckyWinnerPageNumber(): [number, (page: number) => void] {
- const page = useSelector((state: AppState) => state.campaigns.selectedCampaignLuckyWinnersPageNumber)
- const dispatch = useDispatch()
-
- const setPage = useCallback(
- (newPageNumber: number) => {
- dispatch(setSelectedCampaignLuckyWinnersPageNumber(newPageNumber))
- },
- [dispatch],
- )
-
- return [page, setPage]
-}
-
export function useSelectedCampaignLeaderboardLookupAddressManager() {
const selectedCampaignLeaderboardLookupAddress = useSelector(
(state: AppState) => state.campaigns.selectedCampaignLeaderboardLookupAddress,
@@ -64,25 +48,6 @@ export function useSelectedCampaignLeaderboardLookupAddressManager() {
)
}
-export function useSelectedCampaignLuckyWinnersLookupAddressManager() {
- const selectedCampaignLuckyWinnersLookupAddress = useSelector(
- (state: AppState) => state.campaigns.selectedCampaignLuckyWinnersLookupAddress,
- )
- const dispatch = useDispatch()
-
- const updateSelectedCampaignLuckyWinnersLookupAddressCallback = useCallback(
- (newLookupAddress: string) => {
- dispatch(setSelectedCampaignLuckyWinnersLookupAddress(newLookupAddress))
- },
- [dispatch],
- )
-
- return useMemo(
- () => [selectedCampaignLuckyWinnersLookupAddress, updateSelectedCampaignLuckyWinnersLookupAddressCallback] as const,
- [selectedCampaignLuckyWinnersLookupAddress, updateSelectedCampaignLuckyWinnersLookupAddressCallback],
- )
-}
-
export function useRecaptchaCampaignManager() {
const recaptchaCampaign = useSelector((state: AppState) => state.campaigns.recaptchaCampaign)
const dispatch = useDispatch()
diff --git a/src/state/campaigns/reducer.ts b/src/state/campaigns/reducer.ts
index 35c921bb91..e9d12693dc 100644
--- a/src/state/campaigns/reducer.ts
+++ b/src/state/campaigns/reducer.ts
@@ -3,7 +3,6 @@ import { createReducer } from '@reduxjs/toolkit'
import {
CampaignData,
CampaignLeaderboard,
- CampaignLuckyWinner,
setCampaignData,
setCampaignDataByPage,
setClaimingCampaignRewardId,
@@ -11,35 +10,25 @@ import {
setLoadingCampaignData,
setLoadingCampaignDataError,
setLoadingSelectedCampaignLeaderboard,
- setLoadingSelectedCampaignLuckyWinners,
setRecaptchaCampaignId,
setRecaptchaCampaignLoading,
setSelectedCampaign,
setSelectedCampaignLeaderboard,
setSelectedCampaignLeaderboardLookupAddress,
setSelectedCampaignLeaderboardPageNumber,
- setSelectedCampaignLuckyWinners,
- setSelectedCampaignLuckyWinnersLookupAddress,
- setSelectedCampaignLuckyWinnersPageNumber,
} from './actions'
interface CampaignsState {
readonly data: CampaignData[]
readonly loadingCampaignData: boolean
- readonly loadingCampaignDataError: Error | undefined
+ readonly loadingCampaignDataError: boolean
readonly selectedCampaign: CampaignData | undefined
readonly selectedCampaignLeaderboard: CampaignLeaderboard | undefined
- readonly loadingCampaignLeaderboard: boolean
readonly selectedCampaignLeaderboardPageNumber: number
readonly selectedCampaignLeaderboardLookupAddress: string
- readonly selectedCampaignLuckyWinners: CampaignLuckyWinner[]
- readonly loadingCampaignLuckyWinners: boolean
- readonly selectedCampaignLuckyWinnersPageNumber: number
- readonly selectedCampaignLuckyWinnersLookupAddress: string
-
readonly claimingCampaignRewardId: number | null // id that is being claimed
readonly recaptchaCampaign: {
@@ -53,20 +42,14 @@ interface CampaignsState {
const initialState: CampaignsState = {
data: [],
loadingCampaignData: true,
- loadingCampaignDataError: undefined,
+ loadingCampaignDataError: false,
selectedCampaign: undefined,
selectedCampaignLeaderboard: undefined,
- loadingCampaignLeaderboard: false,
selectedCampaignLeaderboardPageNumber: 0,
selectedCampaignLeaderboardLookupAddress: '',
- selectedCampaignLuckyWinners: [],
- loadingCampaignLuckyWinners: false,
- selectedCampaignLuckyWinnersPageNumber: 0,
- selectedCampaignLuckyWinnersLookupAddress: '',
-
claimingCampaignRewardId: null,
recaptchaCampaign: {
@@ -136,30 +119,7 @@ export default createReducer(initialState, builder =>
selectedCampaignLeaderboardLookupAddress: lookupAddress,
}
})
- .addCase(setSelectedCampaignLuckyWinners, (state, { payload: { luckyWinners } }) => {
- return {
- ...state,
- selectedCampaignLuckyWinners: luckyWinners,
- }
- })
- .addCase(setLoadingSelectedCampaignLuckyWinners, (state, { payload: loading }) => {
- return {
- ...state,
- loadingCampaignLuckyWinners: loading,
- }
- })
- .addCase(setSelectedCampaignLuckyWinnersPageNumber, (state, { payload: pageNumber }) => {
- return {
- ...state,
- selectedCampaignLuckyWinnersPageNumber: pageNumber,
- }
- })
- .addCase(setSelectedCampaignLuckyWinnersLookupAddress, (state, { payload: lookupAddress }) => {
- return {
- ...state,
- selectedCampaignLuckyWinnersLookupAddress: lookupAddress,
- }
- })
+
.addCase(setRecaptchaCampaignId, (state, { payload: id }) => {
return {
...state,
diff --git a/src/state/index.ts b/src/state/index.ts
index caffdcdc0c..337177cb2d 100644
--- a/src/state/index.ts
+++ b/src/state/index.ts
@@ -1,26 +1,27 @@
import { configureStore } from '@reduxjs/toolkit'
import { load, save } from 'redux-localstorage-simple'
+import announcementApi, { publicAnnouncementApi } from 'services/announcement'
import blockServiceApi from 'services/blockService'
+import campaignApi from 'services/campaign'
import coingeckoApi from 'services/coingecko'
+import crosschainApi from 'services/crossChain'
+import earningApi from 'services/earning'
+import geckoTerminalApi from 'services/geckoTermial'
+import identifyApi from 'services/identity'
+import knProtocolApi from 'services/knprotocol'
+import ksSettingApi from 'services/ksSetting'
import kyberAISubscriptionApi from 'services/kyberAISubscription'
+import kyberDAO from 'services/kyberDAO'
+import limitOrderApi from 'services/limitOrder'
import priceAlertApi from 'services/priceAlert'
import routeApi from 'services/route'
+import socialApi from 'services/social'
import tokenApi from 'services/token'
import { ENV_LEVEL } from 'constants/env'
import { ENV_TYPE } from 'constants/type'
import kyberAIApi from 'pages/TrueSightV2/hooks/useKyberAIData'
-import announcementApi, { publicAnnouncementApi } from '../services/announcement'
-import crosschainApi from '../services/crossChain'
-import earningApi from '../services/earning'
-import geckoTerminalApi from '../services/geckoTermial'
-import identifyApi from '../services/identity'
-import knProtocolApi from '../services/knprotocol'
-import ksSettingApi from '../services/ksSetting'
-import kyberDAO from '../services/kyberDAO'
-import limitOrderApi from '../services/limitOrder'
-import socialApi from '../services/social'
import application from './application/reducer'
import authen from './authen/reducer'
import burnProAmm from './burn/proamm/reducer'
@@ -97,6 +98,7 @@ const store = configureStore({
[coingeckoApi.reducerPath]: coingeckoApi.reducer,
[limitOrderApi.reducerPath]: limitOrderApi.reducer,
+ [campaignApi.reducerPath]: campaignApi.reducer,
[kyberAIApi.reducerPath]: kyberAIApi.reducer,
[kyberAISubscriptionApi.reducerPath]: kyberAISubscriptionApi.reducer,
[kyberDAO.reducerPath]: kyberDAO.reducer,
@@ -128,6 +130,7 @@ const store = configureStore({
.concat(coingeckoApi.middleware)
.concat(limitOrderApi.middleware)
.concat(kyberAIApi.middleware)
+ .concat(campaignApi.middleware)
.concat(kyberAISubscriptionApi.middleware)
.concat(announcementApi.middleware)
.concat(publicAnnouncementApi.middleware)