diff --git a/src/App.js b/src/App.js
index d66f860..1b36813 100755
--- a/src/App.js
+++ b/src/App.js
@@ -18,6 +18,7 @@ import PinnedData from './components/PinnedData'
import SideNav from './components/SideNav'
import AccountLookup from './pages/AccountLookup'
import LpContestLookup from './pages/LpContestLookup'
+import VolumeContestDashboard from './pages/VolumeContestDashboard'
import LpContestAccountPage from './pages/LpContestPage'
import LocalLoader from './components/LocalLoader'
import { useLatestBlocks, useWhitelistedTokens } from './contexts/Application'
@@ -123,10 +124,10 @@ function App() {
)}
{globalData &&
- Object.keys(globalData).length > 0 &&
- globalChartData &&
- Object.keys(globalChartData).length > 0 &&
- !isEmpty(whitelistedTokens) ? (
+ Object.keys(globalData).length > 0 &&
+ globalChartData &&
+ Object.keys(globalChartData).length > 0 &&
+ !isEmpty(whitelistedTokens) ? (
@@ -226,6 +227,29 @@ function App() {
+ {
+ if (isStarknetAddress(match.params.accountAddress.toLowerCase())) {
+ return (
+
+
+
+ )
+ } else {
+ return
+ }
+ }}
+ />
+
+
+
+
+
+
+
diff --git a/src/components/VolumeContestSearch/index.js b/src/components/VolumeContestSearch/index.js
new file mode 100644
index 0000000..84fd62e
--- /dev/null
+++ b/src/components/VolumeContestSearch/index.js
@@ -0,0 +1,253 @@
+import React, { useState, useEffect, useMemo, useCallback } from 'react'
+import dayjs from 'dayjs'
+import utc from 'dayjs/plugin/utc'
+import { Box, Flex } from 'rebass'
+import styled from 'styled-components'
+
+import Switch from 'react-switch'
+import 'react-tooltip/dist/react-tooltip.css'
+
+import { Tooltip as ReactTooltip } from 'react-tooltip'
+import { Search as SearchIcon } from 'react-feather'
+
+import { CustomLink } from '../Link'
+import { Divider, EmptyCard } from '..'
+import { formattedNum, isStarknetAddress, shortenStraknetAddress, zeroStarknetAddress } from '../../utils'
+import { TYPE } from '../../Theme'
+import Panel from '../Panel'
+
+import eligibilityBadgeIcon from '../../../src/assets/starBadge.svg'
+import { AutoRow } from '../Row'
+import { AutoColumn } from '../Column'
+import { ButtonDark } from '../ButtonStyled'
+import { withRouter } from 'react-router-dom'
+
+dayjs.extend(utc)
+
+const PageButtons = styled.div`
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ margin-top: 2em;
+ margin-bottom: 0.5em;
+`
+
+const Arrow = styled.div`
+ color: ${({ theme }) => theme.primary1};
+ opacity: ${(props) => (props.faded ? 0.3 : 1)};
+ padding: 0 20px;
+ user-select: none;
+
+ :hover {
+ cursor: pointer;
+ }
+`
+
+const SearchWrapper = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-end;
+ width: 100%;
+ border-radius: 12px;
+`
+
+const Input = styled.input`
+ position: relative;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ white-space: nowrap;
+ outline: none;
+ padding: 12px 16px;
+ border-radius: 12px;
+ color: ${({ theme }) => theme.text1};
+ background-color: ${({ theme }) => theme.bg1};
+ font-size: 16px;
+
+ border: 1px solid ${({ theme }) => theme.bg3};
+
+ ::placeholder {
+ color: ${({ theme }) => theme.text3};
+ font-size: 14px;
+ }
+
+ @media screen and (max-width: 640px) {
+ ::placeholder {
+ font-size: 1rem;
+ }
+ }
+`
+
+const EligibilityBadge = styled.img``
+
+const EligibilityBadgeWrapper = styled.a`
+ display: flex;
+ cursor: help;
+`
+
+const List = styled(Box)`
+ -webkit-overflow-scrolling: touch;
+`
+
+const DashGrid = styled.div`
+ display: grid;
+ grid-gap: 1em;
+ grid-template-columns: 0.5fr 1fr 1fr;
+ grid-template-areas: 'number name value';
+ padding: 0 4px;
+
+ > * {
+ justify-content: flex-end;
+ }
+
+ @media screen and (max-width: 1080px) {
+ grid-template-columns: 0.5fr 1fr 1fr;
+ grid-template-areas: 'number name value';
+ }
+
+ @media screen and (max-width: 600px) {
+ grid-template-columns: 0.5fr 1fr 1fr;
+ grid-template-areas: 'number name value';
+ }
+`
+
+const Switcher = styled(Switch)`
+ .react-switch-bg {
+ opacity: 0.32;
+ }
+`
+
+const ListWrapper = styled.div``
+
+const LeaderboardNote = styled.div`
+ display: flex;
+ align-items: center;
+ font-size: 12px;
+ font-weight: 400;
+ color: #fff;
+`
+
+const DataText = styled(Flex)`
+ align-items: center;
+ text-align: center;
+ color: ${({ theme }) => theme.text1};
+
+ & > * {
+ font-size: 14px;
+ }
+
+ @media screen and (max-width: 600px) {
+ font-size: 13px;
+ }
+`
+
+function VolumeContestSearch({ history, players, maxItems = 10 }) {
+ const [isEligibilityFilterChecked, setIsEligibilityFilterChecked] = useState(false)
+ const [checkAccountQuery, setCheckAccountQuery] = useState('')
+ const [isCheckAccountAddressValid, setIsCheckAccountAddressValid] = useState(false)
+ const [page, setPage] = useState(1)
+ const [maxPage, setMaxPage] = useState(1)
+ const ITEMS_PER_PAGE = maxItems
+ const arePlayersAvailable = !!Object.keys(players).length
+
+ const filteredPlayers = useMemo(() => {
+ if (!arePlayersAvailable) {
+ return
+ }
+ return Object.keys(players)
+ .filter((playerId) => {
+ return isEligibilityFilterChecked ? players[playerId]?.isEligible : true
+ })
+ .map((key) => players[key])
+ }, [arePlayersAvailable, players, isEligibilityFilterChecked])
+
+ const handleCheckAccountInputChange = useCallback(
+ (e) => {
+ const value = e.currentTarget.value
+ if (!value) {
+ setCheckAccountQuery('')
+ setIsCheckAccountAddressValid(false)
+ return
+ }
+ setCheckAccountQuery(value)
+ setIsCheckAccountAddressValid(isStarknetAddress(value, true))
+ },
+ [setCheckAccountQuery]
+ )
+
+ const handleAccountSearch = useCallback(
+ (e) => {
+ if (!(isCheckAccountAddressValid && checkAccountQuery)) {
+ return
+ }
+ history.push('/lp-contest/' + checkAccountQuery)
+ },
+ [isCheckAccountAddressValid, checkAccountQuery, history]
+ )
+
+ useEffect(() => {
+ setMaxPage(1) // edit this to do modular
+ setPage(1)
+ }, [filteredPlayers])
+
+ useEffect(() => {
+ if (filteredPlayers?.length) {
+ let extraPages = 1
+ if (filteredPlayers.length % ITEMS_PER_PAGE === 0) {
+ extraPages = 0
+ }
+ setMaxPage(Math.floor(filteredPlayers.length / ITEMS_PER_PAGE) + extraPages)
+ }
+ }, [ITEMS_PER_PAGE, filteredPlayers])
+
+ const ListItem = ({ player, index }) => {
+ return (
+
+
+ {index}
+
+
+
+ {player.starknetIdDomain ? player.starknetIdDomain : shortenStraknetAddress(player.user.id, 6)}
+
+ {player?.isEligible && (
+
+
+
+ )}
+
+
+ {formattedNum(player.contestValue)}
+
+
+ )
+ }
+
+ return (
+ <>
+
+
+
+
+ {}
+
+
+
+ View Profile
+
+
+
+
+
+ >
+ )
+}
+
+export default withRouter(VolumeContestSearch)
diff --git a/src/pages/LpContestPage.js b/src/pages/LpContestPage.js
index 2805f5d..9b7190d 100755
--- a/src/pages/LpContestPage.js
+++ b/src/pages/LpContestPage.js
@@ -103,7 +103,7 @@ function LpContestAccountPage({ account }) {
if (account) {
try {
fetchData()
- } catch (e) {}
+ } catch (e) { }
}
}, [account])
diff --git a/src/pages/VolumeContestDashboard.js b/src/pages/VolumeContestDashboard.js
new file mode 100644
index 0000000..cc28697
--- /dev/null
+++ b/src/pages/VolumeContestDashboard.js
@@ -0,0 +1,146 @@
+import React, { useMemo } from 'react'
+import 'feather-icons'
+import { withRouter } from 'react-router-dom'
+import dayjs from 'dayjs'
+
+import { TYPE } from '../Theme'
+import { PageWrapper, FullWrapper } from '../components'
+
+import styled from 'styled-components'
+
+import { AutoRow, RowBetween } from '../components/Row'
+import { Banner } from '../components/Banner'
+import { Flag, Watch, Box } from 'react-feather'
+import VolumeContestSearch from '../components/VolumeContestSearch'
+import { useLpContestPlayersData } from '../contexts/LpContestData'
+
+import contestFlagIcon from '../../src/assets/flag.svg'
+import { AutoColumn } from '../components/Column'
+//import VolumeContestNftCategories from '../components/LpContestNftCategories'
+
+const Title = styled.div`
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: 500;
+ margin-bottom: 14px;
+`
+
+const TitleIconWrapper = styled.div`
+ display: flex;
+ margin-right: 0.75rem;
+ font-size: 30px;
+
+ img {
+ width: 1em;
+ }
+`
+
+const BannerGridRow = styled.div`
+ display: grid;
+ width: 100%;
+ grid-template-columns: 1fr 1fr 1fr;
+ column-gap: 20px;
+ align-items: start;
+ justify-content: space-between;
+
+ @media screen and (max-width: 800px) {
+ grid-template-columns: 1fr;
+ row-gap: 20px;
+ }
+`
+
+const LeaderboardGridRow = styled.div`
+ display: grid;
+ width: 100%;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+ column-gap: 20px;
+ align-items: flex-start;
+ justify-content: space-between;
+
+ @media screen and (max-width: 1180px) {
+ grid-template-columns: minmax(0, 1fr);
+ row-gap: 20px;
+ }
+`
+
+const ListOptions = styled(AutoRow)`
+ height: 40px;
+ width: 100%;
+ font-size: 1.25rem;
+ font-weight: 600;
+
+ @media screen and (max-width: 640px) {
+ font-size: 1rem;
+ }
+`
+
+const ONGOING_WEEK_START_DATE_ISO = '2023-09-17T00:00:00.000Z'
+const ONGOING_WEEK_END_DATE_ISO = '2023-09-24T07:24:00.000Z'
+
+function VolumeContestDashboard() {
+ const allPlayersData = useLpContestPlayersData()
+
+ let latestLpBlockNumber = useMemo(() => {
+ if (!allPlayersData) {
+ return null
+ }
+ const data = Object.values(allPlayersData)
+ return data?.length ? data[0].block : null
+ }, [allPlayersData])
+ return (
+
+
+
+
+
+
+ The Trade Federation Awakens
+
+
+
+
+ } showPollingDot={false} />
+
+
+
+
+
+
+
+ NFT Rewards
+
+
+
+ {/* */}
+
+ {/*
+
+
+
+
+
+
+ */}
+
+
+
+
+ )
+}
+
+export default withRouter(VolumeContestDashboard)