diff --git a/.env.development b/.env.development index 2560ba79..9ada5687 100644 --- a/.env.development +++ b/.env.development @@ -14,3 +14,4 @@ NEXT_PUBLIC_OPTIMISM_API_KEY=ZRfPzBcHouE1y4JWU3_ikY6J7YQshjbW NEXT_PUBLIC_FUSE_ACCOUNT_API_BASE_URL= NEXT_PUBLIC_FUSE_API_BASE_URL= NEXT_PUBLIC_AMPLITUDE_SERVER_URL= +NEXT_PUBLIC_AIRDROP_API_BASE_URL= diff --git a/.env.production b/.env.production index e92e2421..dd64b49f 100644 --- a/.env.production +++ b/.env.production @@ -15,3 +15,4 @@ NEXT_PUBLIC_BASE_API_KEY= NEXT_PUBLIC_FUSE_ACCOUNT_API_BASE_URL= NEXT_PUBLIC_AMPLITUDE_SERVER_URL= NEXT_PUBLIC_FUSE_API_BASE_URL= +NEXT_PUBLIC_AIRDROP_API_BASE_URL= diff --git a/app/Home.tsx b/app/Home.tsx index dd94b48e..1d43498e 100644 --- a/app/Home.tsx +++ b/app/Home.tsx @@ -11,6 +11,7 @@ import faucet from "@/assets/faucet.svg"; import fusebox from "@/assets/fusebox.svg"; import DocumentSupport from "@/components/DocumentSupport"; import * as amplitude from "@amplitude/analytics-browser"; +import pointsPhases from "@/assets/points-phases.png"; const Home = () => { const dispatch = useAppDispatch(); @@ -23,8 +24,8 @@ const Home = () => {

Welcome to Fuse Console

-

- Start your journey on Fuse +

+ Your suite of financial products and payment solutions. fully customizable. Made with love for Web3 businesses and users.

{!isConnected && +
+ + + Learn more + right caret + + + + ); +}; + +const FloatingParachute = () => { + const parachuteRef = useRef(null); + + useEffect(() => { + let frameId: number; + let startTime: number; + + const animate = (time: number) => { + if (!startTime) startTime = time; + const elapsed = time - startTime; + + const translateY = Math.sin(elapsed / 1000) * 30; + const rotateZ = Math.sin(elapsed / 2000) * 12; + + if (parachuteRef.current) { + parachuteRef.current.style.transform = `translateY(${translateY}px) rotateZ(${rotateZ}deg)`; + } + + frameId = requestAnimationFrame(animate); + }; + + frameId = requestAnimationFrame(animate); + + return () => cancelAnimationFrame(frameId); + }, []); + + return ( + airdrop + ); +}; + +const Giveaway = () => { + return ( +
+
+

+ Giving away +

+
+ +

+ 10,400,000 FUSE +

+
+

+ Phase 1 is live now! +

+
+
+ Fuse Foundation + Fuse Founders + Fuse Flash + Fuse Ember +
+
+ + + + +
+ +
+
+
+

+ Ecosystem +

+

+ Builders Grant +

+

+ Flash +

+

+ Ember +

+
+
+
+
+ ); +}; + +const Phases = () => { + const dispatch = useAppDispatch(); + const { isConnected } = useAccount(); + const router = useRouter(); + + return ( +
+
+
+
+ +
+
+

+ Phase 1 +

+

+ Live +

+
+

+ Fuse Ecosystem +

+

+ Complete various quests to explore the Fuse ecosystem, find new ways to earn and always be the first to receive the latest news. +

+
+ + + Learn more + +
+
+
+ Fuse Foundation +
+
+
+ +
+
+

+ Phase 2 +

+

+ Coming soon +

+
+

+ Builder Grants +

+

+ {"If you're a developer, start building an app on the new testnet today to get support and a grant from the Fuse team to help grow your project."} +

+
+ + Learn more + +
+
+
+ Fuse Founders +
+
+
+ +
+
+

+ Phase 3 +

+

+ Coming soon +

+
+

+ Fuse Flash +

+

+ By playing games on the Fuse Flash testnet, you will help us verify that the network is stable and reliable, and we will be happy to reward you for being with us! +

+ + Learn more + +
+
+ Fuse Flash +
+
+
+ +
+
+

+ Phase 4 +

+

+ Coming soon +

+
+

+ Fuse Ember +

+

+ Migrate all your funds from old L1 Fuse Network mainnet to L2 Fuse Ember mainnet and earn airdrop points. The more funds you migrate, the more points you get. +

+ + Learn more + +
+
+ Fuse Ember +
+
+ ); +}; + +const Home = () => { + return ( +
+ + + +
+ ); +}; + +export default Home; diff --git a/app/points/ecosystem/Home.tsx b/app/points/ecosystem/Home.tsx new file mode 100644 index 00000000..5aa0cb87 --- /dev/null +++ b/app/points/ecosystem/Home.tsx @@ -0,0 +1,512 @@ +import { useEffect, useState } from "react"; +import Image from "next/image"; +import { useRouter, useSearchParams } from "next/navigation"; +import Link from "next/link"; + +import Copy from "@/components/ui/Copy"; +import { convertTimestampToUTC, IS_SERVER, isFloat, isSocialFollowed, path } from "@/lib/helpers"; +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { selectAirdropSlice, setIsClaimTestnetFuseModalOpen, setIsQuestModalOpen, setSelectedQuest } from "@/store/airdropSlice"; +import Avatar from "@/components/ui/Avatar"; +import { CardBody, CardContainer, CardItem } from "@/components/ui/Card3D"; +import Quest from "@/components/airdrop/Quest"; +import { AirdropQuests } from "@/lib/types"; + +import copyIcon from "@/assets/copy-gray.svg"; +import rightCaret from "@/assets/right-caret.svg"; +import rightCaretBlack from "@/assets/right-caret-black.svg"; +import leftArrow from "@/assets/left-arrow.svg"; +import questionMark from "@/assets/questionmark-border.svg"; +import pointHexagon from "@/assets/fuse-foundation-point-hexagon.svg"; +import fuseAirdropPhase from "@/assets/fuse-foundation.svg"; +import bridgeFuse from "@/assets/bridge-fuse.svg"; +import followX from "@/assets/twitter-x-green.svg"; +import verifyDiscord from "@/assets/verify-discord-green.svg"; +import joinTelegram from "@/assets/join-telegram-green.svg"; +import volt from "@/assets/volt-wallet-green.svg"; +import artrific from "@/assets/artrific-green.svg"; +import meridian from "@/assets/meridian-green.svg"; +import meridianYellow from "@/assets/meridian-yellow.svg"; +import voltageLiquidityYellow from "@/assets/voltage-liquidity-yellow.svg"; +import gooddollarYellow from "@/assets/gooddollar-yellow.svg"; + +const Home = () => { + const dispatch = useAppDispatch(); + const { user, twitterAuthUrl } = useAppSelector(selectAirdropSlice); + const router = useRouter(); + const searchParams = useSearchParams(); + const twitterConnected = searchParams.get('twitter-connected'); + + const [quests, setQuests] = useState([ + { + id: "followFuseOnTwitter", + title: "Follow @Fuse_network on X", + description: "Get 50 point for following an official Fuse Network X account", + point: "50 Points", + frequency: "One-time", + image: followX, + buttons: [ + { + text: "Go to X", + isFunction: true, + } + ] + }, + { + id: "telegramSubscription", + title: "Join Fuse Telegram", + description: "Get 50 point for joining an official Fuse Network Telegram channel \n**Verify the quest 1 hour after completing it on Layer3**", + point: "50 Points", + frequency: "One-time", + image: joinTelegram, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/join-fuse-telegram", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "joinFuseDiscord", + title: "Join Fuse Discord", + description: "Get 50 point for joining an official Fuse network Discord channel \n**Verify the quest 1 hour after completing it on Layer3**", + point: "50 Points", + frequency: "One-time", + image: verifyDiscord, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/join-fuse-discord", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "exploreVoltageDex", + title: "Explore Voltage Finance", + description: "Trade, invest, and earn with just a few clicks. \n**Verify the quest 1 hour after completing it on Layer3**", + point: "125 Points", + frequency: "One-time", + image: volt, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/voltage-on-fuse-network", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "liquidityVoltage", + title: "Provide Liquidity to Voltage", + point: "Up to 8 points per $1 in pool daily", + image: voltageLiquidityYellow, + buttons: [ + { + text: "Go to Voltage", + link: "https://voltage.finance/pool", + }, + ] + }, + { + id: "exploreVoltWallet", + title: "Install the Volt wallet", + description: "The Volt wallet is the best mobile solution for interacting with the Fuse network, as it is built and developed by the Fuse team. Explore its features and get 200 points. \n**Verify the quest 1 hour after completing it on Layer3**", + point: "200 Points", + frequency: "One-time", + image: volt, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/explore-volt-wallet", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "exploreMeridian", + title: "Explore Meridian Finance", + description: "The All-in-one DeFi Hub for EVM-Compatible Networks. \n**Verify the quest 1 hour after completing it on Layer3**\n", + point: "175 Points", + frequency: "One-time", + image: meridian, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/explore-meridian-finance", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "provideMeridianLiquidity", + title: "Lend on Meridian", + point: "Up to 8 points per $1 in pool daily", + image: meridianYellow, + buttons: [ + { + text: "Go to Meridian Lend", + link: "https://lend.meridianfinance.net/markets/", + }, + ] + }, + { + id: "borrowOnMeridian", + title: "Borrow on Meridian", + description: "Borrow any asset on Meridian to get 12 points per $1 borrowed every day. \n**Points will begin to accrue 24 hours after the borrow transaction.**", + point: "12 points per $1 borrowed daily", + image: meridianYellow, + buttons: [ + { + text: "Go to Meridian Borrow", + link: "https://lend.meridianfinance.net/borrow/", + }, + ] + }, + { + id: "exploreArtrificOnFuse", + title: "Create an NFT on Artrific", + description: "Create an NFT on the leading NFT marketplace on Fuse Network and get 300 points \n**Verify the quest 1 hour after completing it on Layer3**\n", + point: "300 Points", + frequency: "One-time", + image: artrific, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/quests/explore-artrific-nft-marketplace-on-fuse-network", + }, + { + text: "Verify Quest", + isFunction: true, + } + ] + }, + { + id: "g$Claim", + title: "Claim G$ on GoodDapp", + description: "To get 30 points daily, you need to take 6 steps: \n**Step 1:**\nGo to quest on the Layer3 platform \n**Step 2:**\nConnect to Layer3 a wallet participating in the airdrop \n**Step 3:**\nGo to GoodDapp \n**Step 4:**\nClaim G$ token on Fuse Network \n**Step 5:**\nVerify quest completion on the Layer3 \n**Step 6:**\nRepeat every day. After 5 claims, the quest will renew automatically and allow you to claim more and more. \n**Verify the quest 1 hour after completing it on Layer3**", + point: "30 Points per claim", + frequency: "Once a day", + image: gooddollarYellow, + buttons: [ + { + text: "Go to Quest", + link: "https://app.layer3.xyz/streaks/claim-dollarg", + }, + { + text: "Verify Quest", + isFunction: true, + endpoint: "gooddollar", + } + ] + }, + ]) + + function referralLink() { + const host = !IS_SERVER ? window?.location?.host : "" + return `${host}/airdrop?ref=${user.referralCode}` + } + + useEffect(() => { + setQuests((prevQuests) => { + const newQuests = [...prevQuests]; + newQuests.map((newQuest) => { + if (newQuest.frequency !== "One-time") { + return newQuest; + } + + user.completedQuests?.map((completedQuest) => { + let completedQuestId = completedQuest.type; + if (completedQuest.stakingType) { + completedQuestId = `${completedQuest.type}-${completedQuest.stakingType}`; + } + if (newQuest.id === completedQuestId) { + newQuest.completed = true; + } + }) + return newQuest; + }); + return newQuests; + }) + }, [user.completedQuests]) + + useEffect(() => { + if (twitterConnected === "true") { + if (localStorage.getItem("airdrop-isClaimTestnetFuse")) { + dispatch(setIsClaimTestnetFuseModalOpen(true)); + localStorage.removeItem("airdrop-isClaimTestnetFuse"); + } + } + }, [dispatch, router, twitterConnected]) + + useEffect(() => { + if (twitterAuthUrl) { + router.push(twitterAuthUrl); + } + }, [router, twitterAuthUrl]) + + return ( +
+ + back to Points +
+ Points +
+ +
+

+ Explore the Ecosystem +

+
+
+
+
+ +
+
+

+ My points +

+
+ point hexagon +

+ {isFloat(user.points) ? user.points.toFixed(2) : user.points} +

+
+ {user.pointsLastUpdatedAt ? ( +
+

+ Last update {convertTimestampToUTC(user.pointsLastUpdatedAt)} +

+
+ question mark +
+

+ Points calculation updated every 24 hours. Next update {convertTimestampToUTC(user.nextRewardDistributionTime)} +

+
+
+
+ ) :
} +
+
+
+

+ Your Rank +

+

+ {new Intl.NumberFormat().format(user.leaderboardPosition)} +

+ + View Leaderboard + right caret + +
+
+ Fuse Airdrop phase +
+

+ Fuse is migrating to a zkEvm L2 (Fuse Ember) and taking its robust comunity with it +

+ + Learn more + right caret + +
+
+
+
+

+ Start earning points +

+
+ + +
+
+ + Bridge FUSE + + + Get 4 points daily on every $1 you bridge to Fuse + +
+
+ + + +
+
+ + bridge Fuse + +
+
+ + +
+ + Invite friends + + + {"Get 20% of your friend's total points"} + +
+
+ + Invite link + +
+ + {referralLink()} + + + + +
+
+
+
+
+
+
+

+ {isSocialFollowed(user) ? "Join our Socials and explore the Ecosystem" : "Follow Fuse on X to unlock quests"} +

+
+ {quests.filter((quest) => quest.frequency === "One-time").map((quest) => ( + + ))} +
+
+
+

+ {isSocialFollowed(user) ? "Get multipliers for your points!" : "Follow Fuse on X to unlock multiplier quests"} +

+
+ {quests.filter((quest) => quest.frequency !== "One-time").map((quest) => ( + + ))} +
+
+
+ ) +} + +export default Home; diff --git a/app/points/ecosystem/layout.tsx b/app/points/ecosystem/layout.tsx new file mode 100644 index 00000000..ca3118a6 --- /dev/null +++ b/app/points/ecosystem/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Ecosystem - Fuse Console Points', + description: 'Complete quests and invite friends to earn XP', +} + +export default function AirdropEcosystemLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} diff --git a/app/points/ecosystem/page.tsx b/app/points/ecosystem/page.tsx new file mode 100644 index 00000000..3f397071 --- /dev/null +++ b/app/points/ecosystem/page.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; + +import { path } from "@/lib/helpers"; +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { setSelectedNavbar } from "@/store/navbarSlice"; +import Home from "./Home"; +import Footer from "@/components/Footer"; +import Topbar from "@/components/Topbar"; +import WaitlistModal from "@/components/airdrop/WaitlistModal"; +import { retrieveAirdropUser, selectAirdropSlice } from "@/store/airdropSlice"; +import QuestModal from "@/components/airdrop/QuestModal"; +import ClaimTestnetFuseModal from "@/components/airdrop/ClaimTestnetFuseModal"; + +const AirdropEcosystem = () => { + const dispatch = useAppDispatch(); + const airdropSlice = useAppSelector(selectAirdropSlice); + const router = useRouter(); + + useEffect(() => { + dispatch(setSelectedNavbar("points")); + dispatch(retrieveAirdropUser()); + }, [dispatch]) + + useEffect(() => { + if (airdropSlice.isHydrated && !airdropSlice.isUser) { + router.push(path.AIRDROP) + } + }, [airdropSlice.isHydrated, airdropSlice.isUser, router]); + + return ( +
+ + + + + +
+
+ ); +}; + +export default AirdropEcosystem; diff --git a/app/points/grant/Home.tsx b/app/points/grant/Home.tsx new file mode 100644 index 00000000..19a9c20a --- /dev/null +++ b/app/points/grant/Home.tsx @@ -0,0 +1,231 @@ +import Image from "next/image"; +import Link from "next/link"; + +import FAQ from "@/components/FAQ"; + +import prizePool from "@/assets/airdrop-grant-prize-background.svg"; +import wallet from "@/assets/wallet.svg"; +import paid from "@/assets/paid.svg"; +import agriculture from "@/assets/agriculture.svg"; +import esports from "@/assets/esports.svg"; +import build from "@/assets/build.svg"; +import mintmark from "@/assets/mintmark.svg"; +import currencyExchange from "@/assets/currency-exchange.svg"; +import group from "@/assets/group.svg"; +import smartToy from "@/assets/smart-toy.svg"; +import article from "@/assets/article.svg"; +import uploadFile from "@/assets/upload-file.svg"; + +const bounties = [ + { + title: "Payments", + description: "Debit cards supporting FUSE and USDC.", + icon: wallet, + }, + { + title: "Stablecoins", + description: "CDP stablecoins, yield-bearing stablecoins, RWA-backed stablecoins.", + icon: paid, + }, + { + title: "Yield", + description: "Fixed yield, yield aggregators, cross-chain yield tokenization.", + icon: agriculture, + }, + { + title: "Gaming", + description: "Prediction markets, single-click games, gamified NFT games.", + icon: esports, + }, + { + title: "Tooling", + description: "Vote incentive markets, liquid locker protocols.", + icon: build, + }, + { + title: "Lending", + description: "Simple lending markets, isolated lending markets.", + icon: mintmark, + }, + { + title: "Exchanges", + description: "Perpetual markets, options markets, AMMs, CLOB exchanges.", + icon: currencyExchange, + }, + { + title: "Community Movements", + description: "Brand ambassador campaigns, user-engagement campaigns.", + icon: group, + }, + { + title: "DePIN & AI", + description: "Wireless networks, energy grids, computation, storage.", + icon: smartToy, + }, +]; + +const joins = [ + { + title: "Explore the Developer Docs", + description: "Dive into our comprehensive documentation to understand the Ember platform and its capabilities.", + icon: article, + button: { + title: "Start building", + link: "#" + }, + }, + { + title: "Submit Your Application", + description: "Once your app is ready, apply for the bounty program to showcase your work and earn rewards.", + icon: uploadFile, + button: { + title: "Apply Now", + link: "https://docs.google.com/forms/d/e/1FAIpQLServsLcjBhksX0bGXsE9jwf8qixP4HlKq2jEiJmwEjFxPxX8w/viewform" + }, + }, +]; + +const questions = [ + "What is Fuse Ember?", + "How do I apply to Fuse Ember bounty program?", + "Who can participate in the Fuse Ember bounty program?", + "What types of projects can be submitted?", + "How are winners selected?", + "How much bounty will each winner get?", + "When will the Fuse Ember bounty be distributed?", + "What support is available for participants?", + "Can existing projects participate?", + "?" +] + +const answers = [ + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", + "Fuse Nodes are devices (computers or servers) that run the Fuse blockchain's protocol software and connect to its network. They participate in the Fuse Network by maintaining a copy of the ", +] + +const Hero = () => { + return ( +
+

+ Builder Grants +

+

+ A bounty program rewarding developers for building apps on Ember. +

+
+

+ Prize pool +

+

+ 3,900,000 FUSE +

+ +
+
+ ); +}; + +const Bounty = () => { + return ( +
+
+ {bounties.map((bounty) => ( +
+ +

{bounty.title}

+
+

{bounty.description}

+
+
+ ))} +
+
+

+ Bounty list +

+

+ The bounty program covers a wide range of categories to encourage diverse and innovative apps. Multiple winners can be selected in each category. To qualify, your app must fit into one of the following categories: +

+
+
+ ); +}; + +const Winner = () => { + return ( +
+
+
+

+ Be a Winner! +

+

+ At least 3 best projects will be selected and awarded. But if there are more amazing projects, everyone will get a bounty! +

+
+
+
+ ); +}; + +const Join = () => { + return ( +
+
+

+ Build and Apply +

+

+ Join us in building the next generation of Ember apps. Start building right now on Flash testnet +

+
+
+ {joins.map((join) => ( +
+ +

+ {join.title} +

+

+ {join.description} +

+ + {join.button.title} + +
+ ))} +
+
+ ); +}; + +const Home = () => { + return ( +
+ +
+ + + + +
+ ); +}; + +export default Home; diff --git a/app/points/grant/layout.tsx b/app/points/grant/layout.tsx new file mode 100644 index 00000000..6acf6e57 --- /dev/null +++ b/app/points/grant/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Builder Grants - Fuse Console Points', + description: 'A bounty program rewarding developers for building apps on Ember', +} + +export default function AirdropGrantLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} diff --git a/app/points/grant/page.tsx b/app/points/grant/page.tsx new file mode 100644 index 00000000..dc1e0777 --- /dev/null +++ b/app/points/grant/page.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; + +import { path } from "@/lib/helpers"; +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { setSelectedNavbar } from "@/store/navbarSlice"; +import Home from "./Home"; +import Footer from "@/components/Footer"; +import Topbar from "@/components/Topbar"; +import { retrieveAirdropUser, selectAirdropSlice } from "@/store/airdropSlice"; + +const AirdropGrant = () => { + const dispatch = useAppDispatch(); + const airdropSlice = useAppSelector(selectAirdropSlice); + const router = useRouter(); + + useEffect(() => { + dispatch(setSelectedNavbar("points")); + dispatch(retrieveAirdropUser()); + }, [dispatch]) + + useEffect(() => { + if (airdropSlice.isHydrated && !airdropSlice.isUser) { + router.push(path.AIRDROP) + } + }, [airdropSlice.isHydrated, airdropSlice.isUser, router]); + + return ( +
+
+ + +
+
+ ); +}; + +export default AirdropGrant; diff --git a/app/points/layout.tsx b/app/points/layout.tsx new file mode 100644 index 00000000..f0612cd1 --- /dev/null +++ b/app/points/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Points - Fuse Console', + description: 'Join the Fuse Points! Get into the Fuse, connect your wallet and earn Rewards with ease', +} + +export default function AirdropLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} diff --git a/app/points/leaderboard/Home.tsx b/app/points/leaderboard/Home.tsx new file mode 100644 index 00000000..a0a89aac --- /dev/null +++ b/app/points/leaderboard/Home.tsx @@ -0,0 +1,172 @@ +import Image from "next/image"; +import { motion } from "framer-motion"; + +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { fetchAirdropLeaderboardUsers, selectAirdropSlice } from "@/store/airdropSlice"; +import { eclipseAddress } from "@/lib/helpers"; +import Avatar from "@/components/ui/Avatar"; + +import star from "@/assets/star.svg"; +import starGold from "@/assets/star-gold.svg"; +import starSilver from "@/assets/star-silver.svg"; +import starBronze from "@/assets/star-bronze.svg"; + +type PositionStar = { + name: string; + icon: string; +} + +type PositionStars = { + [key: number]: PositionStar +} + +const PAGE_SIZE = "30"; + +const leaderboardVariants = { + hidden: { + opacity: 0, + y: 50, + transition: { ease: [0.78, 0.14, 0.15, 0.86] } + }, + show: { + opacity: 1, + y: 0, + transition: { ease: [0.78, 0.14, 0.15, 0.86] }, + } +}; + +const positionStars: PositionStars = { + 1: { + name: "Gold", + icon: starGold + }, + 2: { + name: "Silver", + icon: starSilver + }, + 3: { + name: "Bronze", + icon: starBronze + } +} + +const Home = () => { + const dispatch = useAppDispatch(); + const { isLeaderboardUsersLoading, leaderboardUsers, lastLeaderboardUserId, isLeaderboardUsersFinished, user } = useAppSelector(selectAirdropSlice); + + return ( +
+

+ Leaderboard +

+

+ Your Ranking +

+ +
+

+ {new Intl.NumberFormat().format(user.leaderboardPosition)} +

+
+
+ +
+
+

+ {eclipseAddress(user.walletAddress)} +

+

+ {user.walletAddress} +

+
+
+ star +

+ {user.points % 1 === 0 ? user.points : user.points.toFixed(2)} +

+
+
+

+ Top users of all-time +

+
+ {leaderboardUsers.map((leaderboardUser, index) => + +
+ {positionStars[index + 1] && + {positionStars[index + } +

+ {new Intl.NumberFormat().format(index + 1)} +

+
+
+ +
+
+

+ {leaderboardUser.walletAddress} +

+

+ {eclipseAddress(leaderboardUser.walletAddress)} +

+
+
+ star +

+ {leaderboardUser.points % 1 === 0 ? leaderboardUser.points : leaderboardUser.points.toFixed(2)} +

+
+
+ )} + {!isLeaderboardUsersFinished && + { + dispatch(fetchAirdropLeaderboardUsers({ + queryParams: { + pageSize: PAGE_SIZE, + userIdToStartAfter: lastLeaderboardUserId + } + })) + }} + > + {isLeaderboardUsersLoading && +
+ } +
+ } +
+
+ ) +} + +export default Home; diff --git a/app/points/leaderboard/layout.tsx b/app/points/leaderboard/layout.tsx new file mode 100644 index 00000000..34b20c38 --- /dev/null +++ b/app/points/leaderboard/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Leaderboard - Fuse Console Points', + description: 'View all participants ranks in the Fuse Points Leaderboard!', +} + +export default function AirdropLeaderboardLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} diff --git a/app/points/leaderboard/page.tsx b/app/points/leaderboard/page.tsx new file mode 100644 index 00000000..d7f5f0b6 --- /dev/null +++ b/app/points/leaderboard/page.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; + +import { path } from "@/lib/helpers"; +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { setSelectedNavbar } from "@/store/navbarSlice"; +import Home from "./Home"; +import Footer from "@/components/Footer"; +import Topbar from "@/components/Topbar"; +import { selectAirdropSlice } from "@/store/airdropSlice"; + +const AirdropLeaderboard = () => { + const dispatch = useAppDispatch(); + const airdropSlice = useAppSelector(selectAirdropSlice); + const router = useRouter(); + + useEffect(() => { + dispatch(setSelectedNavbar("points")); + }, [dispatch]) + + useEffect(() => { + if (airdropSlice.isHydrated && !airdropSlice.isUser) { + router.push(path.AIRDROP) + } + }, [airdropSlice.isHydrated, airdropSlice.isUser, router]); + + return ( +
+ + +
+
+ ); +}; + +export default AirdropLeaderboard; diff --git a/app/points/page.tsx b/app/points/page.tsx new file mode 100644 index 00000000..34922e72 --- /dev/null +++ b/app/points/page.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { useEffect } from "react"; + +import { useAppDispatch } from "@/store/store"; +import { setSelectedNavbar } from "@/store/navbarSlice"; +import Home from "./Home"; +import Topbar from "@/components/Topbar"; + +const Airdrop = () => { + const dispatch = useAppDispatch(); + + useEffect(() => { + dispatch(setSelectedNavbar("points")); + }, [dispatch]) + + return ( +
+ + +
+ ); +}; + +export default Airdrop; diff --git a/assets/RightArrow.tsx b/assets/RightArrow.tsx new file mode 100644 index 00000000..49005793 --- /dev/null +++ b/assets/RightArrow.tsx @@ -0,0 +1,5 @@ +export default function RightArrow() { + return ( + + ); +} diff --git a/assets/RightCaret.tsx b/assets/RightCaret.tsx new file mode 100644 index 00000000..25266fd7 --- /dev/null +++ b/assets/RightCaret.tsx @@ -0,0 +1,5 @@ +export default function RightCaret() { + return ( + + ) +} diff --git a/assets/agriculture.svg b/assets/agriculture.svg new file mode 100644 index 00000000..896b2c4c --- /dev/null +++ b/assets/agriculture.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/airdrop-grant-prize-background.svg b/assets/airdrop-grant-prize-background.svg new file mode 100644 index 00000000..bc969995 --- /dev/null +++ b/assets/airdrop-grant-prize-background.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/airdrop-right.svg b/assets/airdrop-right.svg new file mode 100644 index 00000000..1c44ee6a --- /dev/null +++ b/assets/airdrop-right.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/article.svg b/assets/article.svg new file mode 100644 index 00000000..a8b08b27 --- /dev/null +++ b/assets/article.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/artrific-green.svg b/assets/artrific-green.svg new file mode 100644 index 00000000..98082130 --- /dev/null +++ b/assets/artrific-green.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/artrific.svg b/assets/artrific.svg new file mode 100644 index 00000000..b51a39f6 --- /dev/null +++ b/assets/artrific.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/bridge-fuse.svg b/assets/bridge-fuse.svg new file mode 100644 index 00000000..65297f37 --- /dev/null +++ b/assets/bridge-fuse.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/build.svg b/assets/build.svg new file mode 100644 index 00000000..b60baa83 --- /dev/null +++ b/assets/build.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/check-background-black.svg b/assets/check-background-black.svg new file mode 100644 index 00000000..da12f20d --- /dev/null +++ b/assets/check-background-black.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/check-background.svg b/assets/check-background.svg new file mode 100644 index 00000000..61f21844 --- /dev/null +++ b/assets/check-background.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/checkmark-orange.svg b/assets/checkmark-orange.svg new file mode 100644 index 00000000..a6347ab3 --- /dev/null +++ b/assets/checkmark-orange.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/copy-gray.svg b/assets/copy-gray.svg new file mode 100644 index 00000000..020a04f1 --- /dev/null +++ b/assets/copy-gray.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/currency-exchange.svg b/assets/currency-exchange.svg new file mode 100644 index 00000000..d92e7a7e --- /dev/null +++ b/assets/currency-exchange.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/email-orange.svg b/assets/email-orange.svg new file mode 100644 index 00000000..bec4e037 --- /dev/null +++ b/assets/email-orange.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/ember-icon.svg b/assets/ember-icon.svg new file mode 100644 index 00000000..e3be1018 --- /dev/null +++ b/assets/ember-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/ember.svg b/assets/ember.svg new file mode 100644 index 00000000..6fd60f8d --- /dev/null +++ b/assets/ember.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/esports.svg b/assets/esports.svg new file mode 100644 index 00000000..f97da597 --- /dev/null +++ b/assets/esports.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/fire.svg b/assets/fire.svg new file mode 100644 index 00000000..3004f516 --- /dev/null +++ b/assets/fire.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/flash-faucet.svg b/assets/flash-faucet.svg new file mode 100644 index 00000000..b35be7bf --- /dev/null +++ b/assets/flash-faucet.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/friends.svg b/assets/friends.svg new file mode 100644 index 00000000..ba604ceb --- /dev/null +++ b/assets/friends.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/fuse-ember.svg b/assets/fuse-ember.svg new file mode 100644 index 00000000..eda21403 --- /dev/null +++ b/assets/fuse-ember.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/fuse-faucet.svg b/assets/fuse-faucet.svg new file mode 100644 index 00000000..21df3957 --- /dev/null +++ b/assets/fuse-faucet.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/fuse-flash.svg b/assets/fuse-flash.svg new file mode 100644 index 00000000..ca53541f --- /dev/null +++ b/assets/fuse-flash.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/fuse-foundation-point-hexagon.svg b/assets/fuse-foundation-point-hexagon.svg new file mode 100644 index 00000000..71cb034c --- /dev/null +++ b/assets/fuse-foundation-point-hexagon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/fuse-foundation.svg b/assets/fuse-foundation.svg new file mode 100644 index 00000000..d5df0150 --- /dev/null +++ b/assets/fuse-foundation.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/fuse-founders.png b/assets/fuse-founders.png new file mode 100644 index 00000000..647f7b33 Binary files /dev/null and b/assets/fuse-founders.png differ diff --git a/assets/gooddollar-green.svg b/assets/gooddollar-green.svg new file mode 100644 index 00000000..617063f0 --- /dev/null +++ b/assets/gooddollar-green.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/gooddollar-yellow.svg b/assets/gooddollar-yellow.svg new file mode 100644 index 00000000..1c2f9f37 --- /dev/null +++ b/assets/gooddollar-yellow.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/gooddollar.svg b/assets/gooddollar.svg new file mode 100644 index 00000000..f1b29e8e --- /dev/null +++ b/assets/gooddollar.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/group.svg b/assets/group.svg new file mode 100644 index 00000000..c2422246 --- /dev/null +++ b/assets/group.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/join-telegram-green.svg b/assets/join-telegram-green.svg new file mode 100644 index 00000000..b874d656 --- /dev/null +++ b/assets/join-telegram-green.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/join-telegram.svg b/assets/join-telegram.svg new file mode 100644 index 00000000..a2d7fcef --- /dev/null +++ b/assets/join-telegram.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/join-waitlist.svg b/assets/join-waitlist.svg new file mode 100644 index 00000000..4f322b63 --- /dev/null +++ b/assets/join-waitlist.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/meridian-green.svg b/assets/meridian-green.svg new file mode 100644 index 00000000..21966c7b --- /dev/null +++ b/assets/meridian-green.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/meridian-yellow.svg b/assets/meridian-yellow.svg new file mode 100644 index 00000000..ab7daf46 --- /dev/null +++ b/assets/meridian-yellow.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/meridian.svg b/assets/meridian.svg new file mode 100644 index 00000000..5dc5b1b3 --- /dev/null +++ b/assets/meridian.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/mintmark.svg b/assets/mintmark.svg new file mode 100644 index 00000000..1c3fcf67 --- /dev/null +++ b/assets/mintmark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/paid.svg b/assets/paid.svg new file mode 100644 index 00000000..80eb9e35 --- /dev/null +++ b/assets/paid.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/point-hexagon-yellow.svg b/assets/point-hexagon-yellow.svg new file mode 100644 index 00000000..fc5c031a --- /dev/null +++ b/assets/point-hexagon-yellow.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/points-phases.png b/assets/points-phases.png new file mode 100644 index 00000000..e049d9ff Binary files /dev/null and b/assets/points-phases.png differ diff --git a/assets/questionmark-border.svg b/assets/questionmark-border.svg new file mode 100644 index 00000000..e35ed6f9 --- /dev/null +++ b/assets/questionmark-border.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/right-caret-black.svg b/assets/right-caret-black.svg new file mode 100644 index 00000000..9bd6b191 --- /dev/null +++ b/assets/right-caret-black.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/right-caret.svg b/assets/right-caret.svg new file mode 100644 index 00000000..f1e3d726 --- /dev/null +++ b/assets/right-caret.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/roulette-game.svg b/assets/roulette-game.svg new file mode 100644 index 00000000..907a3a36 --- /dev/null +++ b/assets/roulette-game.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/shoebill-green.svg b/assets/shoebill-green.svg new file mode 100644 index 00000000..025b5103 --- /dev/null +++ b/assets/shoebill-green.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/shoebill.svg b/assets/shoebill.svg new file mode 100644 index 00000000..dd5808f7 --- /dev/null +++ b/assets/shoebill.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/smart-toy.svg b/assets/smart-toy.svg new file mode 100644 index 00000000..4f5001fe --- /dev/null +++ b/assets/smart-toy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/star-bronze.svg b/assets/star-bronze.svg new file mode 100644 index 00000000..197746ba --- /dev/null +++ b/assets/star-bronze.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/star-gold.svg b/assets/star-gold.svg new file mode 100644 index 00000000..823a3f53 --- /dev/null +++ b/assets/star-gold.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/star-silver.svg b/assets/star-silver.svg new file mode 100644 index 00000000..e0412f22 --- /dev/null +++ b/assets/star-silver.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/star.svg b/assets/star.svg new file mode 100644 index 00000000..a775aa84 --- /dev/null +++ b/assets/star.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/twitter-x-green.svg b/assets/twitter-x-green.svg new file mode 100644 index 00000000..7c3366a2 --- /dev/null +++ b/assets/twitter-x-green.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/twitter-x-logo.svg b/assets/twitter-x-logo.svg new file mode 100644 index 00000000..8005c0f9 --- /dev/null +++ b/assets/twitter-x-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/twitter-x.svg b/assets/twitter-x.svg new file mode 100644 index 00000000..5797df72 --- /dev/null +++ b/assets/twitter-x.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/upload-file.svg b/assets/upload-file.svg new file mode 100644 index 00000000..c8a3a1d7 --- /dev/null +++ b/assets/upload-file.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/verify-discord-green.svg b/assets/verify-discord-green.svg new file mode 100644 index 00000000..c7e74776 --- /dev/null +++ b/assets/verify-discord-green.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/verify-discord.svg b/assets/verify-discord.svg new file mode 100644 index 00000000..c562abfa --- /dev/null +++ b/assets/verify-discord.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/volt-wallet-green.svg b/assets/volt-wallet-green.svg new file mode 100644 index 00000000..47be292e --- /dev/null +++ b/assets/volt-wallet-green.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/volt-wallet-yellow.svg b/assets/volt-wallet-yellow.svg new file mode 100644 index 00000000..e4dfba4a --- /dev/null +++ b/assets/volt-wallet-yellow.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/volt-wallet.svg b/assets/volt-wallet.svg new file mode 100644 index 00000000..f7b49f81 --- /dev/null +++ b/assets/volt-wallet.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/voltage-liquidity-yellow.svg b/assets/voltage-liquidity-yellow.svg new file mode 100644 index 00000000..b4aa53fb --- /dev/null +++ b/assets/voltage-liquidity-yellow.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/voltage-liquidity.svg b/assets/voltage-liquidity.svg new file mode 100644 index 00000000..987c63d8 --- /dev/null +++ b/assets/voltage-liquidity.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/wallet.svg b/assets/wallet.svg new file mode 100644 index 00000000..f4d9d2c4 --- /dev/null +++ b/assets/wallet.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/components/FAQ.tsx b/components/FAQ.tsx index aa9ff58f..13f8ffd6 100644 --- a/components/FAQ.tsx +++ b/components/FAQ.tsx @@ -3,7 +3,7 @@ import FaqQuestion from "./FaqQuestion"; type FAQProps = { questions: string[]; - answers: JSX.Element[]; + answers: JSX.Element[] | string[]; className?: string; }; diff --git a/components/FaqQuestion.tsx b/components/FaqQuestion.tsx index 3ea59429..2d5a77b8 100644 --- a/components/FaqQuestion.tsx +++ b/components/FaqQuestion.tsx @@ -6,7 +6,7 @@ import Image from "next/image"; type FaqQuestionProps = { question: string; - answer: JSX.Element; + answer: JSX.Element | string; className?: string; }; diff --git a/components/NavMenu.tsx b/components/NavMenu.tsx index c7ab8320..19910fec 100644 --- a/components/NavMenu.tsx +++ b/components/NavMenu.tsx @@ -7,6 +7,10 @@ import { path, walletType } from "@/lib/helpers"; import { useAccount } from "wagmi"; import { selectOperatorSlice } from "@/store/operatorSlice"; import Link from "next/link"; +import { motion, Variants } from "framer-motion"; +import { useState } from "react"; +import Image from "next/image"; +import rightCaret from "@/assets/right-caret-black.svg"; type NavMenuProps = { menuItems?: MenuItems; @@ -26,17 +30,43 @@ const openMenuItemEvent: OpenMenuItemEvent = { "Bridge": "Go to Bridge" } +const menu: Variants = { + closed: (isCenter) => ({ + opacity: 0, + transition: { + delay: 0.15, + duration: 0.3, + }, + y: -10, + x: isCenter ? "-50%" : 0, + transitionEnd: { + display: "none", + }, + }), + open: (isCenter) => ({ + opacity: 1, + display: "block", + transition: { + type: "spring", + duration: 0.5, + }, + y: 0, + x: isCenter ? "-50%" : 0, + }), +}; + const NavMenu = ({ menuItems = [], isOpen = false, selected = "", isResponsive = false, className = `items-center justify-between w-auto order-1 absolute left-[50%] -translate-x-[50%] rounded-md ${isResponsive ? "md:w-full md:translate-y-8 md:top-1/2 md:bg-black" : ""}`, - liClassName = "w-20", + liClassName = "w-fit", }: NavMenuProps) => { const matches = useMediaQuery("(min-width: 768px)"); const { address, connector } = useAccount(); const { isAuthenticated } = useAppSelector(selectOperatorSlice); + const [isHover, setIsHover] = useState(-1); return ( <> @@ -44,26 +74,62 @@ const NavMenu = ({
    {menuItems.map((item, index) => ( - { - amplitude.track(openMenuItemEvent[item.title], { - walletType: connector ? walletType[connector.id] : undefined, - walletAddress: address - }); - }} + className="relative md:w-full" > -
    + { + amplitude.track(openMenuItemEvent[item.title], { + walletType: connector ? walletType[connector.id] : undefined, + walletAddress: address + }); + }} + onMouseEnter={() => setIsHover(index)} + onMouseLeave={() => setIsHover(-1)} + > {item.title} -
    - + {item.submenu && ( + right caret + )} + + {item.submenu && ( + setIsHover(index)} + onMouseLeave={() => setIsHover(-1)} + > +
    + {item.submenu.map((subItem, subIndex) => ( + + {subItem.title} + + ))} +
    +
    + )} +
))} diff --git a/components/Topbar.tsx b/components/Topbar.tsx index 3f9108dc..637a78b2 100644 --- a/components/Topbar.tsx +++ b/components/Topbar.tsx @@ -8,16 +8,33 @@ import { selectNavbarSlice } from "@/store/navbarSlice"; import { selectOperatorSlice } from "@/store/operatorSlice"; import { path } from "@/lib/helpers"; import Image from "next/image"; +import { selectAirdropSlice } from "@/store/airdropSlice"; + +const AirdropSubmenu = [ + { + title: "Leaderboard", + link: path.AIRDROP_LEADERBOARD, + }, + { + title: "Fuse Ecosystem", + link: path.AIRDROP_ECOSYSTEM, + }, +] const Topbar = () => { const [isOpen, setOpen] = useState(false); const { isTransfiModalOpen, selected } = useAppSelector(selectNavbarSlice); const { isAuthenticated } = useAppSelector(selectOperatorSlice); + const airdropSlice = useAppSelector(selectAirdropSlice); const [menuItems, setMenuItems] = useState([ { title: "Wallet", link: "/wallet", }, + { + title: "Points", + link: path.AIRDROP, + }, { title: "Build", link: "/build", @@ -34,16 +51,21 @@ const Topbar = () => { useEffect(() => { setMenuItems((oldMenuItems) => - oldMenuItems.map((item) => - item.link === path.BUILD && isAuthenticated ? - { ...item, link: "/dashboard" } : - item + oldMenuItems.map((item) => { + if (item.link === path.BUILD && isAuthenticated) { + return { ...item, link: path.DASHBOARD } + } + if (item.link === path.AIRDROP && airdropSlice.isUser) { + return { ...item, link: path.AIRDROP, submenu: AirdropSubmenu } + } + return item + } ) ); - }, [isAuthenticated]); + }, [isAuthenticated, airdropSlice.isUser]); return ( -