diff --git a/.env.development b/.env.development index e5a9551..650a34f 100644 --- a/.env.development +++ b/.env.development @@ -1,7 +1,5 @@ GENERATE_SOURCEMAP=false NEXT_PUBLIC_GOOGLE_ANALYTICS_ID= NEXT_PUBLIC_YANDEX_METRICA_ID= -NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= -NEXT_PUBLIC_WEB3AUTH_CLIENT_ID= -NEXT_PUBLIC_COIN_GECKO_API_KEY= +NEXT_PUBLIC_GOOGLE_FORM_ID= NEXT_PUBLIC_ENVIRONMENT= diff --git a/.env.production b/.env.production index e5a9551..650a34f 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,5 @@ GENERATE_SOURCEMAP=false NEXT_PUBLIC_GOOGLE_ANALYTICS_ID= NEXT_PUBLIC_YANDEX_METRICA_ID= -NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID= -NEXT_PUBLIC_WEB3AUTH_CLIENT_ID= -NEXT_PUBLIC_COIN_GECKO_API_KEY= +NEXT_PUBLIC_GOOGLE_FORM_ID= NEXT_PUBLIC_ENVIRONMENT= diff --git a/app/Providers.tsx b/app/Providers.tsx index e2acf5d..6140ae8 100644 --- a/app/Providers.tsx +++ b/app/Providers.tsx @@ -1,25 +1,17 @@ 'use client' -import { ReactNode, useRef, useState } from 'react' +import { ReactNode, useRef } from 'react' import { Provider } from 'react-redux' import { AppStore, makeStore } from '@/store/store' import { NEXT_PUBLIC_GOOGLE_ANALYTICS_ID, NEXT_PUBLIC_YANDEX_METRICA_ID } from '@/lib/config' import ReactGA from "react-ga4"; -import { type State, WagmiProvider } from 'wagmi' -import { getConfig } from '@/lib/web3Auth' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import WalletModal from '@/components/WalletModal' -import SwitchChainModal from '@/components/SwitchChainModal' import { YMInitializer } from 'react-yandex-metrika' type Props = { children: ReactNode, - initialState: State | undefined, } -export default function Providers({ children, initialState }: Props) { +export default function Providers({ children }: Props) { const storeRef = useRef() - const queryClient = new QueryClient() - const [config] = useState(() => getConfig()) if (!storeRef.current) { // Create the store instance the first time this renders @@ -29,22 +21,16 @@ export default function Providers({ children, initialState }: Props) { return ( - - - - - - {children} - - + + {children} ) } diff --git a/app/actions.ts b/app/actions.ts new file mode 100644 index 0000000..ffb1e2d --- /dev/null +++ b/app/actions.ts @@ -0,0 +1,27 @@ +'use server' + +import { NEXT_PUBLIC_GOOGLE_FORM_ID } from "@/lib/config" + +export async function joinWaitlist(prevState: any, formData: FormData) { + const email = formData.get('email') + const data = new URLSearchParams() + + if(email) { + data.append('entry.797678204', email.toString()) + } + + try { + await fetch(`https://docs.google.com/forms/d/e/${NEXT_PUBLIC_GOOGLE_FORM_ID}/formResponse`, { + method: 'POST', + body: data, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }) + prevState.type = 'success'; + } catch (error) { + prevState.type = 'error'; + } + + return prevState; +} diff --git a/app/globals.css b/app/globals.css index 7acff0d..b5c61c9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,15 +1,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -/* Chrome, Safari, Edge, Opera */ -.public-sale-amount::-webkit-outer-spin-button, -.public-sale-amount::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -/* Firefox */ -.public-sale-amount[type=number] { - -moz-appearance: textfield; -} diff --git a/app/layout.tsx b/app/layout.tsx index 472a29a..605d27f 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,9 +2,6 @@ import type { Metadata } from "next"; import localFont from 'next/font/local' import "./globals.css"; import Providers from "./Providers"; -import { cookieToInitialState } from "wagmi"; -import { headers } from "next/headers"; -import { getConfig } from "@/lib/web3Auth"; const monaSans = localFont({ src: './MonaSans.woff2', @@ -22,15 +19,10 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const initialState = cookieToInitialState( - getConfig(), - headers().get('cookie') - ) - return ( - + {children} diff --git a/app/page.tsx b/app/page.tsx index f21c461..eb282fc 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,87 +1,113 @@ "use client"; -import PublicSaleForm from "@/components/PublicSaleForm"; -import Topbar from "@/components/Topbar"; + import Image from "next/image"; import Link from "next/link"; -import ember from "@/assets/ember.svg"; -import checkmarkBg from "@/assets/checkmark-bg.svg"; + +import Topbar from "@/components/Topbar"; +import { useFormState } from 'react-dom' +import { joinWaitlist } from '@/app/actions' + import Footer from "@/components/Footer"; import List from "@/components/List"; import FAQ from "@/components/FAQ"; -import { useAppDispatch, useAppSelector } from "@/lib/hooks"; -import { tokenBought, retrieveCurrentTierDetail, retrieveTierDetails, retrieveTotalSupply, selectUserSlice, setIsClient } from "@/store/userSlice"; -import { useEffect } from "react"; -import { useAccount } from "wagmi"; +import JoinWaitlistButton from "@/components/JoinWaitlistButton"; -const whys = [ - "A step in the evolution of Fuse Network towards the new Fuse Ember layer-2 mainnet", - "A transition from a 5-year old L1 decentralized ecosystem to a modular, open source L2", - "An upgrade to a deflationary token model and more stable economy" -] +import ember from "@/assets/ember.svg"; +import checkmarkBg from "@/assets/checkmark-bg.svg"; -const advantages = [ - "Node Rewards - 20% of token supply Rewards is distributed over the frst 24 months after mainnet launch", - "Node owners get access to the Data Availability Committee", - "Participate in governance", - "Node ownership ofers potential additional airdrops" +const why = [ + { + description: "Imagine being part of a network where you can earn just by holding a node. Here's what's in it for you:" + }, + { + description: "15 000 000 FUSE tokens reward reserved exclusively for node operators like you.", + isCheckmark: true + }, + { + description: "40% Revenue Share: Every time a transaction happens on the network, you'll get a slice of the revenue—40% of it, to be exact!", + isCheckmark: true + }, + { + description: "External revenue: Node operators help govern the network and get extra yield. Every user that stakes any RWA or LST asset for yield. Node operators get a slice!", + isCheckmark: true + }, + { + description: "With 50,000 nodes available in 20 different tiers, the sooner you get in, the better the deal. Prices will go up as each tier fills, so don't wait too long to make your move!" + } ] const conditions = [ { - title: "Early birds get the best price", - points: [ - "5 tiers", - "Star price - 120,00 FUSE" - ] + title: "Join whitelist to get early access at the best price" }, { - title: "Nodes for sale at 500—exclusive to licensed operators." + title: "Get 10% discount when paying with FUSE token" }, { - title: "FUSE tokens from sale will be burned" + title: "Earn Node Sale bootstrap reward monthly for 3 years" } ] const questions = [ - "What are Fuse Nodes?", - "What are Fuse Nodes?", - "What are Fuse Nodes?", - "What are Fuse Nodes?", - "What are Fuse Nodes?", - "What are Fuse Nodes?", - "What are Fuse Nodes?", + "How to purchase a Node License?", + "What is whitelist?", + "How to get whitelisted?", + "Does entering the whitelist guarantee that I can definitely purchase a node?", + "How many nodes will be available in total?", + "What is the reward for node operator?", + "Can I buy multiple nodes?", + "How will the node licenses be distributed?", + "How to run a node?" ] 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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", - "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 blockchain ledger, validating transactions, and supporting consensus.", + () => ( +
+ The process will consist of 3 stages: +
    +
  1. + Whitelist application: users can register for whitelist to get priority access. Whitelisting will start in November 2024. Leave your email to be notified. +
  2. +
  3. + Whitelist Sale: only whitelisted users can participate in the sale. Nodes are sold on first come, first served basis. +
  4. +
  5. + Public Sale: the sale is open to all users. +
  6. +
+
+ ), + "This is a list of wallets that have expressed their desire to buy a node before the sale starts. These participants will receive priority access to buy the node before the public sale starts.", + "A whitelisting form will be published on this page in November 2024. Leave your email to be notified.", + "No. The priority sale of nodes to whitelisted participants will be on a first come, first served basis.If all nodes allocated to whitelisted users are sold out, you will be able to participate in the public sale. Leave your email to be notified.", + "A total of 50,000 nodes will be available for purchase in the Fuse Ember network.", + () => ( +
+ Active node operators will receive several types of rewards: +
    +
  1. + Fuse Foundation node sale bootstrap reward distributed monthly for 3 years +
  2. +
  3. + Share of the Fuse Foundation revenue from sequencer fees, new staking DApp, etc. +
  4. +
  5. + Delegation fees from node delegators +
  6. +
  7. + Node ownership offers potential additional airdrops +
  8. +
+
+ ), + "Yes, each participant can buy any number of nodes.", + "The node license is an NFT. NFTs will be sent to the buyer's wallet immediately after the license is paid.", + "Running and managing nodes on the Fuse Ember network will be done through the NodeOps console." ] export default function Home() { - const dispatch = useAppDispatch(); - const { isClient, isTotalSupplyLoading, totalSupply, isCurrentTierDetailLoading, currentTierDetail, isTierDetailsLoading, tierDetails, isBoughtLoading, bought, isMinted } = useAppSelector(selectUserSlice); - const { isConnected, address } = useAccount(); - - useEffect(() => { - dispatch(setIsClient(true)); - }, [dispatch]) - - useEffect(() => { - dispatch(retrieveTotalSupply()); - dispatch(retrieveCurrentTierDetail()); - dispatch(retrieveTierDetails()); - }, [isMinted, dispatch]) - - useEffect(() => { - if (address) { - dispatch(tokenBought({ address })); - } - }, [address, isMinted, dispatch]) + const initialState = { type: 'idle' } + const [state, formAction] = useFormState(joinWaitlist, initialState) return (
@@ -90,64 +116,42 @@ export default function Home() {
-

- Fuse L2 Node Sale +

+ Join the Fuse Ember Node Sale

-

- Buy a Fuse Network Node License NFT and Earn FUSE +

+ {"Your ticket to earning rewards and being part of a cutting-edge decentralized payment network that's set to change the game."}

- - Buy Node - -
+
-
+ +
-
-
-

- Sale in Progress -

-
-
-

- Sold licenses -

- {!isMinted && (!isClient || isTotalSupplyLoading) ? - : -

- {totalSupply} -

- } -
-
-

- Current license price -

- {!isMinted && (!isClient || isCurrentTierDetailLoading) ? - : -

- {new Intl.NumberFormat().format(currentTierDetail.price)} FUSE -

- } -
-
-
-
- ember -
+
+

+ See if you qualify to be a Node Operator +

+ {state.type === 'success' ? ( +

Thanks for joining the waitlist!

+ ) : ( +
+ + + + )}
-
@@ -165,106 +169,12 @@ export default function Home() {

{condition.title}

-
    - {condition.points?.map((point, i) => ( -
  • - {point} -
  • - ))} -
))}
- -
-
-
-

- Become a Fuse Network Node Operator -

-
-
-

- Tiers -

-
- {!isMinted && (!isClient || isTierDetailsLoading) ? - new Array(5).fill(0).map((_, i) => ( - - )) : - tierDetails.map((tierDetail) => ( -
-
-
-

- Tier {tierDetail.tier} -

-

- {tierDetail.tier === currentTierDetail.tier ? - "Selling" : - tierDetail.tier > currentTierDetail.tier ? - "Not started" : - "Sold out"} -

-
-
-

- Price per license -

-

- {new Intl.NumberFormat().format(tierDetail.price)} FUSE -

-
-
- {tierDetail.tier <= currentTierDetail.tier && ( -
-
-
-
-

- - {tierDetail.maxSupply - tierDetail.availableSupply} - - /{tierDetail.maxSupply} -

-
- )} -
- ))} -
-
- -
-
-

- My licenses -

- {!isMinted && (!isClient || isBoughtLoading) ? - : -

- {isConnected ? - bought ? - `Congratulations! You have ${bought} ${bought > 1 ? "licenses" : "license"}, and can launch ${bought} Data Availability ${bought > 1 ? "nodes" : "node"} when Ember L2 goes live. Stay tuned!` : - "You have not purchased a license." : - "Connect Wallet to view your purchased licenses." - } -

- } -
-
-
-