Skip to content

Commit

Permalink
feat: add route authentication.
Browse files Browse the repository at this point in the history
feat: create footer.
  • Loading branch information
albertocruzluis committed Mar 1, 2022
1 parent def22fe commit 781104e
Show file tree
Hide file tree
Showing 15 changed files with 662 additions and 46 deletions.
4 changes: 2 additions & 2 deletions components/BannerAnalytics/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { v4 as uuidv4 } from 'uuid';

export const BannerAnalytics = () => {
const analytics = [
{name: "Total proposals", icon: <BiPencil />, value: "2"},
{name: "Members", icon: <BiUser />, value: "2"},
{name: "Total proposals", icon: <BiPencil />, value: "4"},
{name: "Members", icon: <BiUser />, value: "3"},
]

return (
Expand Down
17 changes: 17 additions & 0 deletions components/Footer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import CustomLink from 'components/CustomLink';
import { BsTwitter } from 'react-icons/bs'

export const Footer = () => {
const currentYear = new Date().getFullYear();

return (
<div className="flex flex-col gap-2">
<div className='flex justify-center'>
<CustomLink href="https://twitter.com/intent/user?screen_name=albertocruzdev">
<BsTwitter color='white' />
</CustomLink>
</div>
<span className="text-white">©{currentYear} Alberto Cruz Luis | Made with NextJS</span>
</div>
)
}
12 changes: 11 additions & 1 deletion components/Proposal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useDataOfBlock } from "hooks/useDataOfBlock"
import { useEffect, useState } from "react"
import toast from "react-hot-toast"
import { middleStringTruncate } from "utils/middleStringTruncate"
import { BiLoaderAlt } from 'react-icons/bi'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import localizedFormat from 'dayjs/plugin/localizedFormat'
Expand Down Expand Up @@ -125,7 +126,16 @@ export const Proposal = ({proposalId, description, state, proposer, votes, execu
)
})}
<button disabled={isVoting || hasVoted} onClick={onSubmitVote} className="bg-black rounded-md hover:bg-gray-900">
<span className="text-white">{ isVoting ? "Voting..." : hasVoted ? "You Already Voted" : "Vote"}</span>
{ isVoting ? (
<div className="flex gap-2 justify-center items-center">
<BiLoaderAlt className="animate-spin" color="white" />
<span className="text-white">Voting...</span>
</div>
) : hasVoted ? (
<span className="text-white">You Already Voted</span>
) : (
<span className="text-white">Vote</span>
)}
</button>
</div>
</div>
Expand Down
18 changes: 14 additions & 4 deletions components/Proposals/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import 'react-loading-skeleton/dist/skeleton.css'
import { filer } from "utils/filter"

const proposalOptions = [
{ label: "All", value: '' },
{ label: "All", value: 'all' },
{ label: "Active", value: 1 },
{ label: "Defeated", value: 3 },
{ label: 'Succeeded', value: 4 },
{ label: 'Executed', value: 7 }
]

export const Proposals = ({tokenModule, memberAddresses}) => {
Expand All @@ -31,8 +33,10 @@ export const Proposals = ({tokenModule, memberAddresses}) => {
const proposalsFiltered = filer(proposals, options, option)
if (proposalsFiltered.length) {
setProposalsFilter(proposalsFiltered)
} else {
} else if (option === 'all') {
setProposalsFilter(proposals)
} else {
setProposalsFilter([])
}
}

Expand All @@ -57,14 +61,20 @@ export const Proposals = ({tokenModule, memberAddresses}) => {
tokenModule={tokenModule} />
)
)}
{!proposalsFilter.length &&
{!proposals.length &&
<div className="bg-white rounded-md p-2">
<Skeleton highlightColor="#C2CBD7" width={100} />
<Skeleton highlightColor="#C2CBD7" />
<Skeleton highlightColor="#C2CBD7" height={30} count={3} />
<Skeleton highlightColor="#C2CBD7" />
</div>
}
}
{ proposals.length ? !proposalsFilter.length ? (
<div className="border border-solid border-gray-400 p-4 rounded-md">
<span className="text-white">{"Oops, we can't find any results"}</span>
</div>
) : "" : ""
}
</div>
</div>
)
Expand Down
7 changes: 7 additions & 0 deletions features/GlobalStore/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import create from 'zustand'
import { devtools } from 'zustand/middleware'

export const useGlobalStore = create(devtools(set => ({
hasClaimedNFT: false,
setHasClaimedNFT: (value) => set(_ => ({ hasClaimedNFT: value}))
})))
10 changes: 9 additions & 1 deletion features/NewProposal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Select } from "components/Select";
import { ethers } from "ethers";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { BiLoaderAlt } from 'react-icons/bi'

const ACTIONS = [
{ label: "mint", value: "mint" },
Expand Down Expand Up @@ -112,7 +113,14 @@ export const NewProposal = ({tokenModule, voteModule, memberAddresses}) => {
</div>
</div>
<button className="bg-black p-2 rounded-md" onClick={createProposal}>
<span className="text-white">{isCreating ? 'Creating...' : 'Create Proposal'}</span>
{ isCreating ? (
<div className="flex gap-2 justify-center items-center">
<BiLoaderAlt className="animate-spin" color="white" />
<span className="text-white">Creating...</span>
</div>
) : (
<span className="text-white">Create Proposal</span>
)}
</button>
</div>
</div>
Expand Down
31 changes: 31 additions & 0 deletions hooks/useAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useWeb3 } from "@3rdweb/hooks"
import { useRouter } from "next/router"
import { useEffect } from "react"
import toast from "react-hot-toast"
import { useClaimNFT } from "./useClaimNFT"

export const useAuth = (privateRoutes) => {
const { address } = useWeb3()
const { hasClaimedNFT } = useClaimNFT()
const router = useRouter()

const isPrivateRoute = () => {
const currentRoute = router.asPath
return privateRoutes[currentRoute]
}

const isLandingPage = () => {
const currentRoute = router.asPath
return (currentRoute === '/')
}

useEffect(() => {
if (!hasClaimedNFT && isPrivateRoute() && !isLandingPage()) {
router.push('/')
toast('This route only can be access who have the SpanishDAO NFT', {
icon: '🔒'
})
}

}, [hasClaimedNFT, router, address])
}
42 changes: 27 additions & 15 deletions hooks/useClaimNFT.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,57 @@
import { useWeb3 } from "@3rdweb/hooks";
import { BUNDLE_DROP_MODULE } from "config";
import { sdk } from "lib/sdk";
import { useEffect, useState } from "react";
import { useWeb3 } from "@3rdweb/hooks"
import { BUNDLE_DROP_MODULE } from "config"
import { useGlobalStore } from "features/GlobalStore"
import { sdk } from "lib/sdk"
import { useEffect, useState } from "react"
import toast from "react-hot-toast"
import { useSessionStorage } from 'react-use'

// We can grab a reference to our ERC-1155 contract.
const bundleDropModule = sdk.getBundleDropModule(
BUNDLE_DROP_MODULE,
);
)

export const useClaimNFT = () => {
const { address, provider } = useWeb3();
const [hasClaimedNFT, setHasClaimedNFT] = useState(false);
const [isClaiming, setIsClaiming] = useState(false);
const signer = provider ? provider.getSigner() : undefined;
const { address, provider } = useWeb3()
//const [hasNFT, setHasNFT] = useSessionStorage('HAS_NFT', "not_set")
const hasClaimedNFT = useGlobalStore(state => state.hasClaimedNFT)
const setHasClaimedNFT = useGlobalStore(state => state.setHasClaimedNFT)
const [isClaiming, setIsClaiming] = useState(false)
const signer = provider ? provider.getSigner() : undefined

useEffect(() => {
// We pass the signer to the sdk, which enables us to interact with
// our deployed contract!
sdk.setProviderOrSigner(signer);
}, [signer]);
sdk.setProviderOrSigner(signer)
}, [signer])

useEffect(async () => {
// If they don't have an connected wallet, exit!
if (!address) {
return;
return
}

/*if (hasNFT === "yes") {
setHasClaimedNFT(true)
return
}*/

// Check if the user has the NFT by using bundleDropModule.balanceOf
const balance = await bundleDropModule.balanceOf(address, "0");

try {
// If balance is greater than 0, they have our NFT!
if(balance.gt(0)) {
setHasClaimedNFT(true);
setHasClaimedNFT(true)
//setHasNFT("yes")
console.log("🌟 this user has a membership NFT!");
} else {
setHasClaimedNFT(false);
setHasClaimedNFT(false)
//setHasNFT("no")
console.log("😭 this user doesn't have a membership NFT.")
}
} catch (error) {
setHasClaimedNFT(false);
setHasClaimedNFT(false)
console.error("failed to nft balance", error);
}
}, [address]);
Expand Down
9 changes: 1 addition & 8 deletions hooks/useProposals.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { useClaimNFT } from "./useClaimNFT";
import { sdk } from "lib/sdk";
import { VOTE_MODULE } from "config";

Expand All @@ -8,22 +7,16 @@ const voteModule = sdk.getVoteModule(
);

export const useProposals = () => {
const { hasClaimedNFT } = useClaimNFT()
const [proposals, setProposals] = useState([]);

// Retrieve all our existing proposals from the contract.
useEffect(async () => {
if (!hasClaimedNFT) {
return;
}
// A simple call to voteModule.getAll() to grab the proposals.
try {
const proposals = await voteModule.getAll();
setProposals(proposals);
} catch (error) {
console.log("failed to get proposals", error);
}
}, [hasClaimedNFT]);
}, []);

return { proposals, setProposals }
}
1 change: 0 additions & 1 deletion layouts/DashboardLayout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { useEffect, useMemo, useState } from "react";
import { middleStringTruncate } from "utils/middleStringTruncate";
import { BUNDLE_DROP_MODULE, TOKEN_MODULE } from "config";
import { sdk } from "lib/sdk";
import { Component } from "react/cjs/react.production.min";

// We can grab a reference to our ERC-1155 contract.
const bundleDropModule = sdk.getBundleDropModule(BUNDLE_DROP_MODULE);
Expand Down
12 changes: 11 additions & 1 deletion layouts/PageLayout/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import CustomLink from "components/CustomLink"
import { Footer } from "components/Footer"
import { Logo } from "components/Logo"
import { Navbar } from "components/Navbar"
import { Wallet } from "components/Wallet"
import { useAuth } from "hooks/useAuth"

export const PageLayout = ({ children }) => {
const routes = [
{name: "Token", url: "https://rinkeby.etherscan.io/token/0x52f376C173C780EadBF347E7b1467b0311E5D484"},
{name: "OpenSea", url: "https://testnets.opensea.io/collection/unidentified-contract-uoqhbcayts"},
{name: "Dashboard", url: "/dashboard"}
]
const privateRoutes = {
'/dashboard' : true,
'/dashboard/create-proposal' : true
}

const auth = useAuth(privateRoutes)

return (
<div className="bg-indigo-900">
<div className="flex flex-col min-h-screen xl:container xl:mx-auto">
Expand All @@ -26,7 +35,8 @@ export const PageLayout = ({ children }) => {
<main className="grow xl:px-8 p-4">
{children}
</main>
<footer className="flex justify-center p-4">
<footer className="flex justify-center p-4 bg-black bg-opacity-30 rounded-t-md">
<Footer />
</footer>
</div>
</div>
Expand Down
Loading

1 comment on commit 781104e

@vercel
Copy link

@vercel vercel bot commented on 781104e Mar 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.