├── .prettierignore ├── .env.example ├── .eslintrc.json ├── .prettierrc ├── next.config.js ├── .husky └── pre-commit ├── public ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── social-banner.png ├── apple-touch-icon.png ├── mstile-150x150.png ├── android-chrome-192x192.png ├── android-chrome-384x384.png ├── browserconfig.xml ├── site.webmanifest └── safari-pinned-tab.svg ├── hooks ├── useDeveloperList.ts ├── useFetch.ts ├── useAvailableTokens.ts ├── useDeveloperMap.ts ├── useDeveloperAvailabilityList.ts ├── useWindowFocus.ts ├── useFilteredList.ts ├── useDeveloperSearch.ts └── useWallet.ts ├── .vscode └── launch.json ├── next-env.d.ts ├── components ├── Button.tsx ├── Logo.tsx ├── Footer.tsx ├── Layout.tsx ├── DeveloperList.tsx ├── ThemeToggleButton.tsx ├── NavBar.tsx ├── CommunityLinks.tsx ├── Header.tsx ├── DeveloperCard.tsx ├── Wallet.tsx ├── DeveloperSearch.tsx ├── DeveloperDetails.tsx └── DataTable.tsx ├── pages ├── api │ └── tokens │ │ ├── index.ts │ │ └── available.ts ├── _document.tsx ├── index.tsx └── _app.tsx ├── lib ├── getAvailableTokens.ts ├── getContract.ts └── getTokenHolders.ts ├── .gitignore ├── tsconfig.json ├── package.json ├── LICENSE ├── README.md └── contracts └── DevDao.json /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | INFURA_ENDPOINT= 2 | DEV_DAO_CONTRACT= 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "trailingComma": "all" 4 | } 5 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | }; 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/social-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/social-banner.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoliveira/developer-dao-frontend/HEAD/public/android-chrome-384x384.png -------------------------------------------------------------------------------- /hooks/useDeveloperList.ts: -------------------------------------------------------------------------------- 1 | import useFetch from "./useFetch"; 2 | 3 | export default function useDeveloperList() { 4 | return useFetch("/data/developers.json"); 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "attach", 7 | "name": "Attach to application", 8 | "skipFiles": ["/**"], 9 | "port": 9229 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | // NOTE: This file should not be edited 6 | // see https://nextjs.org/docs/basic-features/typescript for more information. 7 | -------------------------------------------------------------------------------- /components/Button.tsx: -------------------------------------------------------------------------------- 1 | export default function Button({ children, ...props }: any) { 2 | return ( 3 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /pages/api/tokens/index.ts: -------------------------------------------------------------------------------- 1 | import { NextApiResponse } from "next"; 2 | 3 | import getTokenHolders from "lib/getTokenHolders"; 4 | 5 | export default async function handler(req, res: NextApiResponse) { 6 | const tokens = await getTokenHolders(); 7 | res.status(200).json({ tokens }); 8 | } 9 | -------------------------------------------------------------------------------- /components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import { Heading } from "@chakra-ui/react"; 2 | 3 | export function Logo() { 4 | return ( 5 | 10 | devtokens.xyz 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /hooks/useFetch.ts: -------------------------------------------------------------------------------- 1 | import useSWR from "swr"; 2 | 3 | export default function useFetch(endpoint) { 4 | return useSWR(endpoint, fetcher); 5 | } 6 | 7 | async function fetcher(input: RequestInfo, init?: RequestInit) { 8 | const res = await fetch(input, init); 9 | return res.json(); 10 | } 11 | -------------------------------------------------------------------------------- /pages/api/tokens/available.ts: -------------------------------------------------------------------------------- 1 | import { NextApiResponse } from "next"; 2 | 3 | import getAvailableTokens from "lib/getAvailableTokens"; 4 | 5 | export default async function handler(req, res: NextApiResponse) { 6 | const available = await getAvailableTokens(); 7 | res.status(200).json({ available }); 8 | } 9 | -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #000000 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /hooks/useAvailableTokens.ts: -------------------------------------------------------------------------------- 1 | import useFetch from "./useFetch"; 2 | 3 | export default function useAvailableTokens() { 4 | const { data, ...args } = useFetch("/api/tokens/available"); 5 | 6 | if (Array.isArray(data?.available)) { 7 | return { 8 | data: new Set(data.available), 9 | ...args, 10 | }; 11 | } 12 | 13 | return { data, ...args }; 14 | } 15 | -------------------------------------------------------------------------------- /hooks/useDeveloperMap.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | 3 | export default function useDeveloperMap(developerList: any[]) { 4 | return useMemo(() => { 5 | const map = new Map(); 6 | 7 | developerList.forEach((developer) => { 8 | map.set(developer.id, developer); 9 | }); 10 | 11 | return map; 12 | }, [developerList]); 13 | } 14 | -------------------------------------------------------------------------------- /components/Footer.tsx: -------------------------------------------------------------------------------- 1 | export function Footer() { 2 | return ( 3 |
4 | Made with 🔥 by{" "} 5 | 9 | @tfmoliveira 10 | 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import { Container, VStack, useColorModeValue } from "@chakra-ui/react"; 2 | import { NavBar } from "./NavBar"; 3 | 4 | export function Layout({ children }) { 5 | const mainBg = useColorModeValue("gray.50", "gray.800"); 6 | 7 | return ( 8 | 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /lib/getAvailableTokens.ts: -------------------------------------------------------------------------------- 1 | import getTokenHolders from "./getTokenHolders"; 2 | 3 | const MIN_TOKEN = 1; 4 | const MAX_TOKEN = 7777; 5 | 6 | export default async function getAvailableTokens() { 7 | const tokens = await getTokenHolders(); 8 | const available: string[] = []; 9 | 10 | for (let i = MIN_TOKEN; i <= MAX_TOKEN; i++) { 11 | if (!tokens[i]) { 12 | available.push(i.toString()); 13 | } 14 | } 15 | 16 | return available; 17 | } 18 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Developer DAO", 3 | "short_name": "Developer DAO", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-384x384.png", 12 | "sizes": "384x384", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /components/DeveloperList.tsx: -------------------------------------------------------------------------------- 1 | import DataTable from "./DataTable"; 2 | 3 | type Props = { 4 | columns: string[]; 5 | data?: any[]; 6 | onClick?: (token: string) => void; 7 | }; 8 | 9 | export default function DevelopersList({ columns, data, onClick }: Props) { 10 | const handleClick = (item: any) => { 11 | onClick?.(item); 12 | }; 13 | 14 | return ( 15 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /lib/getContract.ts: -------------------------------------------------------------------------------- 1 | import Web3 from "web3"; 2 | import NftReference from "@0xcert/ethereum-erc721/build/erc721.json"; 3 | 4 | const INFURA_ENDPOINT = process.env.INFURA_ENDPOINT; 5 | const DEV_DAO_CONTRACT = process.env.DEV_DAO_CONTRACT; 6 | 7 | export default function getContract() { 8 | const provider = new Web3.providers.HttpProvider(INFURA_ENDPOINT); 9 | const client = new Web3(provider); 10 | const abi: any = NftReference.ERC721.abi; 11 | const contract = new client.eth.Contract(abi, DEV_DAO_CONTRACT); 12 | 13 | return contract; 14 | } 15 | -------------------------------------------------------------------------------- /lib/getTokenHolders.ts: -------------------------------------------------------------------------------- 1 | import getContract from "./getContract"; 2 | 3 | type DeveloperTokenList = Record; 4 | 5 | export default async function getTokenHolders(): Promise { 6 | const contract = getContract(); 7 | 8 | const tokens: DeveloperTokenList = {}; 9 | const events = await contract.getPastEvents("Transfer", { 10 | fromBlock: 0, 11 | toBlock: "latest", 12 | }); 13 | events.forEach((event) => { 14 | tokens[event.returnValues._tokenId] = event.returnValues._to; 15 | }); 16 | 17 | return tokens; 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "es5", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "strict": false, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve" 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /components/ThemeToggleButton.tsx: -------------------------------------------------------------------------------- 1 | import { DarkMode, IconButton, useColorMode } from "@chakra-ui/react"; 2 | import { MoonIcon, SunIcon } from "@chakra-ui/icons"; 3 | 4 | export function ThemeToggleButton() { 5 | const { colorMode, toggleColorMode } = useColorMode(); 6 | 7 | return ( 8 | 9 | : } 11 | aria-label={`Switch to ${ 12 | colorMode === "light" ? "dark theme" : "light theme" 13 | }`} 14 | onClick={toggleColorMode} 15 | /> 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { 2 | DocumentContext, 3 | Html, 4 | Head, 5 | Main, 6 | NextScript, 7 | } from "next/document"; 8 | 9 | class MyDocument extends Document { 10 | static async getInitialProps(ctx: DocumentContext) { 11 | const initialProps = await Document.getInitialProps(ctx); 12 | return { ...initialProps }; 13 | } 14 | 15 | render() { 16 | return ( 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | ); 25 | } 26 | } 27 | 28 | export default MyDocument; 29 | -------------------------------------------------------------------------------- /hooks/useDeveloperAvailabilityList.ts: -------------------------------------------------------------------------------- 1 | import useAvailableTokens from "./useAvailableTokens"; 2 | 3 | export default function useDeveloperAvailabilityList(developerList: any[]) { 4 | const availableTokens = useAvailableTokens(); 5 | 6 | if (!developerList) { 7 | return []; 8 | } 9 | 10 | if (!availableTokens.data) { 11 | return developerList; 12 | } 13 | 14 | return developerList.map((developer) => { 15 | const available = availableTokens.data.has(developer.id); 16 | 17 | return { 18 | ...developer, 19 | available, 20 | availableText: available ? "Available" : "Claimed", // searchable words 21 | }; 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /components/NavBar.tsx: -------------------------------------------------------------------------------- 1 | import RouterLink from "next/link"; 2 | import { Flex, HStack, useColorModeValue } from "@chakra-ui/react"; 3 | 4 | import { ThemeToggleButton } from "./ThemeToggleButton"; 5 | import { Logo } from "./Logo"; 6 | 7 | export function NavBar() { 8 | const bg = useColorModeValue("gray.700", "gray.900"); 9 | 10 | return ( 11 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /components/CommunityLinks.tsx: -------------------------------------------------------------------------------- 1 | const linkList = [ 2 | [ 3 | "Etherscan", 4 | "https://etherscan.io/token/0x25ed58c027921e14d86380ea2646e3a1b5c55a8b", 5 | ], 6 | ["Twitter", "https://twitter.com/developer_dao"], 7 | [ 8 | "How to mint", 9 | "https://twitter.com/developer_dao/status/1433960989033119749", 10 | ], 11 | ]; 12 | 13 | export default function CommunityLinks() { 14 | return ( 15 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /hooks/useWindowFocus.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | const hasFocus = () => typeof document !== "undefined" && document.hasFocus(); 4 | 5 | // source: https://github.com/jpalumickas/use-window-focus/blob/master/src/index.ts 6 | // license: MIT 7 | const useWindowFocus = () => { 8 | const [focused, setFocused] = useState(hasFocus); // Focus for first render 9 | 10 | useEffect(() => { 11 | setFocused(hasFocus()); // Focus for additional renders 12 | 13 | const onFocus = () => setFocused(true); 14 | const onBlur = () => setFocused(false); 15 | 16 | window.addEventListener("focus", onFocus); 17 | window.addEventListener("blur", onBlur); 18 | 19 | return () => { 20 | window.removeEventListener("focus", onFocus); 21 | window.removeEventListener("blur", onBlur); 22 | }; 23 | }, []); 24 | 25 | return focused; 26 | }; 27 | 28 | export default useWindowFocus; 29 | -------------------------------------------------------------------------------- /components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { Container, Text, HStack, VStack, Link } from "@chakra-ui/layout"; 2 | 3 | export function Header() { 4 | return ( 5 | 6 | 7 | 8 | Find your next Developer DAO token with your favourite attributes and 9 | available to claim! 10 | 11 | 12 | With a token you will get access to special channels on the Developer 13 | DAO community, where you can connect with other builders and create 14 | amazing things together. 15 | 16 | 17 | Official Developer DAO website: 18 | 19 | 20 | www.developerdao.com 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /hooks/useFilteredList.ts: -------------------------------------------------------------------------------- 1 | type Filter = { 2 | search: string; 3 | onlyAvailable: boolean; 4 | }; 5 | 6 | export default function useFilteredList(data: any[] = [], filter: Filter) { 7 | const loadedAvailability = typeof data[0]?.available === "boolean"; 8 | const keywordList = getKeywordList(filter, loadedAvailability); 9 | 10 | return data.filter((row) => { 11 | const cellList: string[] = Object.values(row); 12 | 13 | // a row must contain all keywords to be matched 14 | return keywordList.every((keyword) => { 15 | return cellList.some((cell) => 16 | String(cell).toLowerCase().includes(keyword), 17 | ); 18 | }); 19 | }); 20 | } 21 | 22 | function getKeywordList(filter: Filter, loadedAvailability: boolean): string[] { 23 | const keywords = filter.search.toLowerCase().split(/[ ,;]/).filter(Boolean); 24 | 25 | if (loadedAvailability && filter.onlyAvailable) { 26 | keywords.push("available"); 27 | } 28 | 29 | return keywords; 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "developer-dao-frontend", 3 | "description": "Frontend interface for Developer DAO - Devs for Revolution.", 4 | "version": "0.1.0", 5 | "private": true, 6 | "scripts": { 7 | "prepare": "husky install", 8 | "dev": "NODE_OPTIONS='--inspect' next dev", 9 | "build": "next build", 10 | "start": "next start", 11 | "lint": "next lint" 12 | }, 13 | "lint-staged": { 14 | "*.{js,ts,tsx,html,css,json,md}": "prettier --write" 15 | }, 16 | "dependencies": { 17 | "@0xcert/ethereum-erc721": "^2.4.0", 18 | "@chakra-ui/icons": "^1.0.16", 19 | "@chakra-ui/react": "^1.6.10", 20 | "@emotion/react": "^11.5.0", 21 | "@emotion/styled": "^11.3.0", 22 | "ethers": "^5.4.6", 23 | "framer-motion": "^4.1.17", 24 | "next": "11.1.2", 25 | "react": "17.0.2", 26 | "react-dom": "17.0.2", 27 | "swr": "^1.0.0", 28 | "web3": "^1.5.2" 29 | }, 30 | "devDependencies": { 31 | "@types/react": "^17.0.20", 32 | "eslint": "7.32.0", 33 | "eslint-config-next": "11.1.2", 34 | "husky": "^7.0.2", 35 | "lint-staged": "^11.1.2", 36 | "prettier": "^2.3.2", 37 | "typescript": "^4.4.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Filipe Oliveira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hooks/useDeveloperSearch.ts: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | import useDeveloperAvailabilityList from "./useDeveloperAvailabilityList"; 4 | import useDeveloperList from "./useDeveloperList"; 5 | import useDeveloperMap from "./useDeveloperMap"; 6 | import useFilteredList from "./useFilteredList"; 7 | 8 | export const DEVELOPER_COLUMNS = [ 9 | "id", 10 | "os", 11 | "textEditor", 12 | "clothing", 13 | "language", 14 | "industry", 15 | "location", 16 | "mind", 17 | "vibe", 18 | "available", 19 | ]; 20 | 21 | export default function useDeveloperSearch() { 22 | const [filter, setFilter] = useState({ search: "", onlyAvailable: false }); 23 | 24 | const developerQuery = useDeveloperList(); 25 | const developerList = developerQuery.data ?? []; 26 | 27 | const developerMap = useDeveloperMap(developerList); 28 | const developerAvailabilityList = useDeveloperAvailabilityList(developerList); 29 | const filteredList = useFilteredList(developerAvailabilityList, filter); 30 | const cappedList = useCappedList(filteredList, 100); 31 | 32 | return { 33 | filter, 34 | setFilter, 35 | developerMap, 36 | resultList: cappedList, 37 | resultCount: filteredList.length, 38 | visibleCount: cappedList.length, 39 | }; 40 | } 41 | 42 | function useCappedList(data: any[] = [], capacity: number) { 43 | return data.slice(0, capacity); 44 | } 45 | -------------------------------------------------------------------------------- /public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 19 | 21 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /components/DeveloperCard.tsx: -------------------------------------------------------------------------------- 1 | const attributeClassName = "font-serif text-base"; 2 | 3 | interface Props { 4 | os: string; 5 | textEditor: string; 6 | clothing: string; 7 | language: string; 8 | industry: string; 9 | location: string; 10 | mind: string; 11 | vibe: string; 12 | } 13 | 14 | export default function DeveloperCard({ 15 | os, 16 | textEditor, 17 | clothing, 18 | language, 19 | industry, 20 | location, 21 | mind, 22 | vibe, 23 | }: Props) { 24 | return ( 25 | 31 | 32 | 33 | {os} 34 | 35 | 36 | {textEditor} 37 | 38 | 39 | {clothing} 40 | 41 | 42 | {language} 43 | 44 | 45 | {industry} 46 | 47 | 48 | {location} 49 | 50 | 51 | {mind} 52 | 53 | 54 | {vibe} 55 | 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /components/Wallet.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Link } from "@chakra-ui/react"; 2 | import { ExternalLinkIcon } from "@chakra-ui/icons"; 3 | 4 | const classNames = (...args: string[]) => args.join(" "); 5 | 6 | type Props = { 7 | walletInstalled: boolean; 8 | walletConnected: boolean; 9 | networkName: string; 10 | isMainNet: boolean; 11 | loading: boolean; 12 | connectWallet: () => void; 13 | }; 14 | 15 | export default function Wallet({ 16 | walletInstalled, 17 | walletConnected, 18 | networkName, 19 | isMainNet, 20 | loading, 21 | connectWallet, 22 | }: Props) { 23 | if (loading) { 24 | return
; 25 | } 26 | 27 | return ( 28 |
29 | {!walletInstalled && ( 30 | 34 | Install MetaMask 35 | 36 | 37 | )} 38 | {walletInstalled && !walletConnected && ( 39 | 42 | )} 43 | {walletConnected && ( 44 |
45 |
46 | 47 | Wallet Connected 48 |
49 |
55 | Network: {networkName} 56 |
57 | {!isMainNet && ( 58 |
59 | Please switch to Mainnet 60 |
61 | )} 62 |
63 | )} 64 |
65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { VStack } from "@chakra-ui/react"; 3 | 4 | import DeveloperDetails from "components/DeveloperDetails"; 5 | import DeveloperList from "components/DeveloperList"; 6 | import DeveloperSearch from "components/DeveloperSearch"; 7 | import Wallet from "components/Wallet"; 8 | import { Footer } from "components/Footer"; 9 | import { Header } from "components/Header"; 10 | import { Layout } from "components/Layout"; 11 | 12 | import useDeveloperSearch, { 13 | DEVELOPER_COLUMNS, 14 | } from "hooks/useDeveloperSearch"; 15 | import useWallet from "hooks/useWallet"; 16 | 17 | export default function Home() { 18 | const { 19 | walletInstalled, 20 | walletConnected, 21 | networkName, 22 | isMainNet, 23 | loading, 24 | connectWallet, 25 | claimToken, 26 | } = useWallet(); 27 | 28 | const { setFilter, resultList, resultCount, visibleCount } = 29 | useDeveloperSearch(); 30 | const [token, selectToken] = useState(null); 31 | 32 | return ( 33 | 34 | 35 |
36 | 44 | 49 | selectToken("")} 54 | /> 55 | 60 |