diff --git a/components/chain-list/all-chains-item.tsx b/components/chain-list/all-chains-item.tsx new file mode 100644 index 0000000..22d959d --- /dev/null +++ b/components/chain-list/all-chains-item.tsx @@ -0,0 +1,65 @@ +import { ChainItemType } from "../../types"; +import { + ChangeEvent, + Dispatch, + FunctionComponent, + SetStateAction, + useEffect, + useState, +} from "react"; +import { + ChainImageContainer, + ChainInfoContainer, + ChainItemContainer, +} from "./chain-list"; +import { ChainImage } from "./chain-image"; +import { Flex1 } from "../../styles/flex-1"; +import { ChainCheckBox, ChainName, WalletAddress } from "./chain-item"; +import color from "../../styles/color"; +import styled from "styled-components"; + +interface Props { + allChecked: boolean; + setAllChecked: Dispatch>; + chainItem: ChainItemType; +} + +export const AllChainsItem: FunctionComponent = (props) => { + const { allChecked, setAllChecked, chainItem } = props; + + const checkHandler = () => { + setAllChecked(!allChecked); + }; + + return ( + + + + + + + {`.${chainItem.prefix}`} + {chainItem.address} + + + + + + + + ); +}; + +const AllChainsContainer = styled.div` + width: 100%; + + background-color: ${color.grey["800"]}; +`; diff --git a/components/chain-list/chain-item.tsx b/components/chain-list/chain-item.tsx index 4492420..b1e0cd1 100644 --- a/components/chain-list/chain-item.tsx +++ b/components/chain-list/chain-item.tsx @@ -1,5 +1,12 @@ import { ChainItemType } from "../../types"; -import { ChangeEvent, FunctionComponent, useState } from "react"; +import { + ChangeEvent, + Dispatch, + FunctionComponent, + SetStateAction, + useEffect, + useState, +} from "react"; import { ChainImageContainer, ChainInfoContainer, @@ -14,18 +21,28 @@ import { ChainImage } from "./chain-image"; interface Props { chainItem: ChainItemType; checkedItemHandler: (chainItem: ChainItemType, isChecked: boolean) => void; + checkedItems: Set; } export const ChainItem: FunctionComponent = (props) => { - const { chainItem, checkedItemHandler } = props; + const { chainItem, checkedItemHandler, checkedItems } = props; const [checked, setChecked] = useState(false); - const checkHandler = (event: ChangeEvent) => { + const checkHandler = () => { setChecked(!checked); - checkedItemHandler(chainItem, event.target.checked); + checkedItemHandler(chainItem, !checked); }; + + useEffect(() => { + setChecked(checkedItems.has(chainItem)); + }, [checkedItems]); + return ( - + = (props) => { - checkHandler(event)} - /> + ); }; -const ChainName = styled.div` +export const ChainName = styled.div` font-weight: 600; font-size: 0.8rem; line-height: 1rem; - color: ${color.grey["100"]}; + color: ${color.white}; `; -const WalletAddress = styled.div` +export const WalletAddress = styled.div` font-weight: 500; font-size: 0.8rem; line-height: 1rem; + max-height: 2rem; + max-width: 27rem; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + color: ${color.grey["400"]}; `; -const ChainCheckBox = styled.input.attrs({ type: "checkbox" })` +export const ChainCheckBox = styled.input.attrs({ type: "checkbox" })` width: 1.5rem; height: 1.5rem; `; diff --git a/components/chain-list/chain-list.tsx b/components/chain-list/chain-list.tsx index fbdb442..ef0f80e 100644 --- a/components/chain-list/chain-list.tsx +++ b/components/chain-list/chain-list.tsx @@ -1,17 +1,25 @@ -import { FunctionComponent } from "react"; +import { Dispatch, FunctionComponent, SetStateAction, useEffect } from "react"; import { ChainItemType, WidthHeightProps } from "../../types"; import color from "../../styles/color"; import styled from "styled-components"; import { ChainItem } from "./chain-item"; interface Props { + allChecked: boolean; + setAllChecked: Dispatch>; chainList: ChainItemType[]; - checkedItems: any; - setCheckedItems: any; + checkedItems: Set; + setCheckedItems: Dispatch>>; } export const ChainList: FunctionComponent = (props) => { - const { chainList, checkedItems, setCheckedItems } = props; + const { + allChecked, + setAllChecked, + chainList, + checkedItems, + setCheckedItems, + } = props; const checkedItemHandler = (chainItem: ChainItemType, isChecked: boolean) => { const tempSet = new Set(checkedItems); @@ -25,6 +33,22 @@ export const ChainList: FunctionComponent = (props) => { setCheckedItems(tempSet); }; + useEffect(() => { + if (allChecked) { + setCheckedItems(new Set(chainList)); + } else if (chainList.length === checkedItems.size) { + setCheckedItems(new Set()); + } + }, [allChecked]); + + useEffect(() => { + if (chainList.length === checkedItems.size && checkedItems.size !== 0) { + setAllChecked(true); + } else { + setAllChecked(false); + } + }, [checkedItems]); + return ( {chainList.map((chainItem) => ( @@ -32,6 +56,7 @@ export const ChainList: FunctionComponent = (props) => { key={chainItem.address} chainItem={chainItem} checkedItemHandler={checkedItemHandler} + checkedItems={checkedItems} /> ))} diff --git a/next.config.js b/next.config.js index d3197ea..94c9229 100644 --- a/next.config.js +++ b/next.config.js @@ -15,6 +15,10 @@ const nextConfig = { protocol: "https", hostname: "raw.githubusercontent.com", }, + { + protocol: "https", + hostname: "abs.twimg.com", + }, ], }, }; diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 431af3e..a5cc2b0 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -25,26 +25,33 @@ import { MainChainId } from "../../constants/wallet"; import { getKeplrFromWindow, KeplrWallet } from "../../wallets"; import { ChainIdHelper } from "@keplr-wallet/cosmos"; +import AllChainsIcon from "../../public/images/svg/all-chains-icon.svg"; +import { AllChainsItem } from "../../components/chain-list/all-chains-item"; + export default function VerificationPage() { const router = useRouter(); const [twitterAuthInfo, setTwitterAuthInfo] = useState(); - const [chainList, setChainList] = useState([]); const [isLoading, setIsLoading] = useState(true); + const [wallet, setWallet] = useState(); + const [allChains, setAllChains] = useState(); + const [chainList, setChainList] = useState([]); const [checkedItems, setCheckedItems] = useState(new Set()); + const [allChecked, setAllChecked] = useState(false); useEffect(() => { const handleVerification = async () => { if (window.location.search) { if (window.location.search.match("error")) { await router.push("/"); + return; } await fetchTwitterInfo(); - await fetchChainList(); + await initWallet(); setIsLoading(false); } @@ -66,11 +73,39 @@ export default function VerificationPage() { setTwitterAuthInfo(newTwitterAuthInfo); }; - const fetchChainList = async () => { + const initWallet = async () => { const keplr = await getKeplrFromWindow(); if (keplr) { - const wallet = new KeplrWallet(keplr); + const keplrWallet = new KeplrWallet(keplr); + setWallet(keplrWallet); + } + }; + + useEffect(() => { + if (wallet) { + fetchAllChains(); + fetchChainList(); + } + }, [wallet]); + + const fetchAllChains = async () => { + if (wallet) { + const chainNames = (await wallet.getChainInfosWithoutEndpoints()).map( + (chainInfo) => chainInfo.chainName, + ); + + setAllChains({ + chainId: "all chains", + prefix: `all chains(${chainNames.length})`, + address: chainNames.join(", "), + chainImageUrl: AllChainsIcon, + }); + } + }; + + const fetchChainList = async () => { + if (wallet) { const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map( (c) => c.chainId, ); @@ -81,6 +116,7 @@ export default function VerificationPage() { const chainInfos = (await wallet.getChainInfosWithoutEndpoints()).map( (chainInfo) => { return { + chainId: chainInfo.chainId, prefix: chainInfo.bech32Config.bech32PrefixAccAddr, chainImageUrl: `https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/${ ChainIdHelper.parse(chainInfo.chainId).identifier @@ -98,19 +134,16 @@ export default function VerificationPage() { } // remove duplicated item - // const filteredChainList = chainArray.filter((chain, index, self) => { - // return index === self.findIndex((t) => chain.prefix === t.prefix); - // }); + const filteredChainList = chainArray.filter((chain, index, self) => { + return index === self.findIndex((t) => chain.prefix === t.prefix); + }); - setChainList(chainArray); + setChainList(filteredChainList); } }; const verifyTwitterAccount = async () => { - const keplr = await getKeplrFromWindow(); - - if (twitterAuthInfo && keplr) { - const wallet = new KeplrWallet(keplr); + if (twitterAuthInfo && wallet) { const key = await wallet.getKey(MainChainId); const icnsVerificationList = ( @@ -132,6 +165,8 @@ export default function VerificationPage() { const onClickRegistration = async () => { await verifyTwitterAccount(); + + await router.push("/complete"); }; return ( @@ -150,7 +185,17 @@ export default function VerificationPage() { Search + {allChains ? ( + + ) : null} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/types/account-info.ts b/types/account-info.ts index 8c73a23..0e1d315 100644 --- a/types/account-info.ts +++ b/types/account-info.ts @@ -1,4 +1,5 @@ export interface ChainItemType { + chainId: string; prefix: string; chainImageUrl: string; address: string;