Add all chains item, Fix checkbox logic
This commit is contained in:
parent
10e129baad
commit
1dd9e31911
65
components/chain-list/all-chains-item.tsx
Normal file
65
components/chain-list/all-chains-item.tsx
Normal file
@ -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<SetStateAction<boolean>>;
|
||||||
|
chainItem: ChainItemType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AllChainsItem: FunctionComponent<Props> = (props) => {
|
||||||
|
const { allChecked, setAllChecked, chainItem } = props;
|
||||||
|
|
||||||
|
const checkHandler = () => {
|
||||||
|
setAllChecked(!allChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AllChainsContainer>
|
||||||
|
<ChainItemContainer
|
||||||
|
key={chainItem.prefix}
|
||||||
|
isLoading={false}
|
||||||
|
onClick={checkHandler}
|
||||||
|
>
|
||||||
|
<ChainImageContainer width="3rem" height="3rem">
|
||||||
|
<ChainImage
|
||||||
|
src={chainItem.chainImageUrl}
|
||||||
|
fill={true}
|
||||||
|
alt={`${chainItem.prefix} chain image`}
|
||||||
|
/>
|
||||||
|
</ChainImageContainer>
|
||||||
|
<ChainInfoContainer>
|
||||||
|
<ChainName>{`.${chainItem.prefix}`}</ChainName>
|
||||||
|
<WalletAddress>{chainItem.address}</WalletAddress>
|
||||||
|
</ChainInfoContainer>
|
||||||
|
|
||||||
|
<Flex1 />
|
||||||
|
|
||||||
|
<ChainCheckBox checked={allChecked} />
|
||||||
|
</ChainItemContainer>
|
||||||
|
</AllChainsContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AllChainsContainer = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background-color: ${color.grey["800"]};
|
||||||
|
`;
|
@ -1,5 +1,12 @@
|
|||||||
import { ChainItemType } from "../../types";
|
import { ChainItemType } from "../../types";
|
||||||
import { ChangeEvent, FunctionComponent, useState } from "react";
|
import {
|
||||||
|
ChangeEvent,
|
||||||
|
Dispatch,
|
||||||
|
FunctionComponent,
|
||||||
|
SetStateAction,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
ChainImageContainer,
|
ChainImageContainer,
|
||||||
ChainInfoContainer,
|
ChainInfoContainer,
|
||||||
@ -14,18 +21,28 @@ import { ChainImage } from "./chain-image";
|
|||||||
interface Props {
|
interface Props {
|
||||||
chainItem: ChainItemType;
|
chainItem: ChainItemType;
|
||||||
checkedItemHandler: (chainItem: ChainItemType, isChecked: boolean) => void;
|
checkedItemHandler: (chainItem: ChainItemType, isChecked: boolean) => void;
|
||||||
|
checkedItems: Set<unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChainItem: FunctionComponent<Props> = (props) => {
|
export const ChainItem: FunctionComponent<Props> = (props) => {
|
||||||
const { chainItem, checkedItemHandler } = props;
|
const { chainItem, checkedItemHandler, checkedItems } = props;
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
|
|
||||||
const checkHandler = (event: ChangeEvent<HTMLInputElement>) => {
|
const checkHandler = () => {
|
||||||
setChecked(!checked);
|
setChecked(!checked);
|
||||||
checkedItemHandler(chainItem, event.target.checked);
|
checkedItemHandler(chainItem, !checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setChecked(checkedItems.has(chainItem));
|
||||||
|
}, [checkedItems]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChainItemContainer key={chainItem.prefix} isLoading={false}>
|
<ChainItemContainer
|
||||||
|
key={chainItem.prefix}
|
||||||
|
isLoading={false}
|
||||||
|
onClick={checkHandler}
|
||||||
|
>
|
||||||
<ChainImageContainer width="3rem" height="3rem">
|
<ChainImageContainer width="3rem" height="3rem">
|
||||||
<ChainImage
|
<ChainImage
|
||||||
src={chainItem.chainImageUrl}
|
src={chainItem.chainImageUrl}
|
||||||
@ -40,31 +57,36 @@ export const ChainItem: FunctionComponent<Props> = (props) => {
|
|||||||
|
|
||||||
<Flex1 />
|
<Flex1 />
|
||||||
|
|
||||||
<ChainCheckBox
|
<ChainCheckBox checked={checked} />
|
||||||
checked={checked}
|
|
||||||
onChange={(event) => checkHandler(event)}
|
|
||||||
/>
|
|
||||||
</ChainItemContainer>
|
</ChainItemContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChainName = styled.div`
|
export const ChainName = styled.div`
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
|
|
||||||
color: ${color.grey["100"]};
|
color: ${color.white};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const WalletAddress = styled.div`
|
export const WalletAddress = styled.div`
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1rem;
|
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"]};
|
color: ${color.grey["400"]};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ChainCheckBox = styled.input.attrs({ type: "checkbox" })`
|
export const ChainCheckBox = styled.input.attrs({ type: "checkbox" })`
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
`;
|
`;
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import { FunctionComponent } from "react";
|
import { Dispatch, FunctionComponent, SetStateAction, useEffect } from "react";
|
||||||
import { ChainItemType, WidthHeightProps } from "../../types";
|
import { ChainItemType, WidthHeightProps } from "../../types";
|
||||||
import color from "../../styles/color";
|
import color from "../../styles/color";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { ChainItem } from "./chain-item";
|
import { ChainItem } from "./chain-item";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
allChecked: boolean;
|
||||||
|
setAllChecked: Dispatch<SetStateAction<boolean>>;
|
||||||
chainList: ChainItemType[];
|
chainList: ChainItemType[];
|
||||||
checkedItems: any;
|
checkedItems: Set<unknown>;
|
||||||
setCheckedItems: any;
|
setCheckedItems: Dispatch<SetStateAction<Set<unknown>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChainList: FunctionComponent<Props> = (props) => {
|
export const ChainList: FunctionComponent<Props> = (props) => {
|
||||||
const { chainList, checkedItems, setCheckedItems } = props;
|
const {
|
||||||
|
allChecked,
|
||||||
|
setAllChecked,
|
||||||
|
chainList,
|
||||||
|
checkedItems,
|
||||||
|
setCheckedItems,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const checkedItemHandler = (chainItem: ChainItemType, isChecked: boolean) => {
|
const checkedItemHandler = (chainItem: ChainItemType, isChecked: boolean) => {
|
||||||
const tempSet = new Set(checkedItems);
|
const tempSet = new Set(checkedItems);
|
||||||
@ -25,6 +33,22 @@ export const ChainList: FunctionComponent<Props> = (props) => {
|
|||||||
setCheckedItems(tempSet);
|
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 (
|
return (
|
||||||
<ChainContainer color={color.grey["800"]}>
|
<ChainContainer color={color.grey["800"]}>
|
||||||
{chainList.map((chainItem) => (
|
{chainList.map((chainItem) => (
|
||||||
@ -32,6 +56,7 @@ export const ChainList: FunctionComponent<Props> = (props) => {
|
|||||||
key={chainItem.address}
|
key={chainItem.address}
|
||||||
chainItem={chainItem}
|
chainItem={chainItem}
|
||||||
checkedItemHandler={checkedItemHandler}
|
checkedItemHandler={checkedItemHandler}
|
||||||
|
checkedItems={checkedItems}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ChainContainer>
|
</ChainContainer>
|
||||||
|
@ -15,6 +15,10 @@ const nextConfig = {
|
|||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "raw.githubusercontent.com",
|
hostname: "raw.githubusercontent.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "abs.twimg.com",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -25,26 +25,33 @@ import { MainChainId } from "../../constants/wallet";
|
|||||||
import { getKeplrFromWindow, KeplrWallet } from "../../wallets";
|
import { getKeplrFromWindow, KeplrWallet } from "../../wallets";
|
||||||
import { ChainIdHelper } from "@keplr-wallet/cosmos";
|
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() {
|
export default function VerificationPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [twitterAuthInfo, setTwitterAuthInfo] =
|
const [twitterAuthInfo, setTwitterAuthInfo] =
|
||||||
useState<TwitterAuthInfoResponse | null>();
|
useState<TwitterAuthInfoResponse | null>();
|
||||||
|
|
||||||
const [chainList, setChainList] = useState<ChainItemType[]>([]);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
const [wallet, setWallet] = useState<KeplrWallet>();
|
||||||
|
const [allChains, setAllChains] = useState<ChainItemType>();
|
||||||
|
const [chainList, setChainList] = useState<ChainItemType[]>([]);
|
||||||
const [checkedItems, setCheckedItems] = useState(new Set());
|
const [checkedItems, setCheckedItems] = useState(new Set());
|
||||||
|
const [allChecked, setAllChecked] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleVerification = async () => {
|
const handleVerification = async () => {
|
||||||
if (window.location.search) {
|
if (window.location.search) {
|
||||||
if (window.location.search.match("error")) {
|
if (window.location.search.match("error")) {
|
||||||
await router.push("/");
|
await router.push("/");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchTwitterInfo();
|
await fetchTwitterInfo();
|
||||||
|
|
||||||
await fetchChainList();
|
await initWallet();
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@ -66,11 +73,39 @@ export default function VerificationPage() {
|
|||||||
setTwitterAuthInfo(newTwitterAuthInfo);
|
setTwitterAuthInfo(newTwitterAuthInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchChainList = async () => {
|
const initWallet = async () => {
|
||||||
const keplr = await getKeplrFromWindow();
|
const keplr = await getKeplrFromWindow();
|
||||||
|
|
||||||
if (keplr) {
|
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(
|
const chainIds = (await wallet.getChainInfosWithoutEndpoints()).map(
|
||||||
(c) => c.chainId,
|
(c) => c.chainId,
|
||||||
);
|
);
|
||||||
@ -81,6 +116,7 @@ export default function VerificationPage() {
|
|||||||
const chainInfos = (await wallet.getChainInfosWithoutEndpoints()).map(
|
const chainInfos = (await wallet.getChainInfosWithoutEndpoints()).map(
|
||||||
(chainInfo) => {
|
(chainInfo) => {
|
||||||
return {
|
return {
|
||||||
|
chainId: chainInfo.chainId,
|
||||||
prefix: chainInfo.bech32Config.bech32PrefixAccAddr,
|
prefix: chainInfo.bech32Config.bech32PrefixAccAddr,
|
||||||
chainImageUrl: `https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/${
|
chainImageUrl: `https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/${
|
||||||
ChainIdHelper.parse(chainInfo.chainId).identifier
|
ChainIdHelper.parse(chainInfo.chainId).identifier
|
||||||
@ -98,19 +134,16 @@ export default function VerificationPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove duplicated item
|
// remove duplicated item
|
||||||
// const filteredChainList = chainArray.filter((chain, index, self) => {
|
const filteredChainList = chainArray.filter((chain, index, self) => {
|
||||||
// return index === self.findIndex((t) => chain.prefix === t.prefix);
|
return index === self.findIndex((t) => chain.prefix === t.prefix);
|
||||||
// });
|
});
|
||||||
|
|
||||||
setChainList(chainArray);
|
setChainList(filteredChainList);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const verifyTwitterAccount = async () => {
|
const verifyTwitterAccount = async () => {
|
||||||
const keplr = await getKeplrFromWindow();
|
if (twitterAuthInfo && wallet) {
|
||||||
|
|
||||||
if (twitterAuthInfo && keplr) {
|
|
||||||
const wallet = new KeplrWallet(keplr);
|
|
||||||
const key = await wallet.getKey(MainChainId);
|
const key = await wallet.getKey(MainChainId);
|
||||||
|
|
||||||
const icnsVerificationList = (
|
const icnsVerificationList = (
|
||||||
@ -132,6 +165,8 @@ export default function VerificationPage() {
|
|||||||
|
|
||||||
const onClickRegistration = async () => {
|
const onClickRegistration = async () => {
|
||||||
await verifyTwitterAccount();
|
await verifyTwitterAccount();
|
||||||
|
|
||||||
|
await router.push("/complete");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -150,7 +185,17 @@ export default function VerificationPage() {
|
|||||||
<SearchContainer>Search</SearchContainer>
|
<SearchContainer>Search</SearchContainer>
|
||||||
</ChainListTitleContainer>
|
</ChainListTitleContainer>
|
||||||
|
|
||||||
|
{allChains ? (
|
||||||
|
<AllChainsItem
|
||||||
|
allChecked={allChecked}
|
||||||
|
setAllChecked={setAllChecked}
|
||||||
|
chainItem={allChains}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<ChainList
|
<ChainList
|
||||||
|
allChecked={allChecked}
|
||||||
|
setAllChecked={setAllChecked}
|
||||||
chainList={chainList}
|
chainList={chainList}
|
||||||
checkedItems={checkedItems}
|
checkedItems={checkedItems}
|
||||||
setCheckedItems={setCheckedItems}
|
setCheckedItems={setCheckedItems}
|
||||||
|
33
public/images/svg/all-chains-icon.svg
Normal file
33
public/images/svg/all-chains-icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 646 KiB |
@ -1,4 +1,5 @@
|
|||||||
export interface ChainItemType {
|
export interface ChainItemType {
|
||||||
|
chainId: string;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
chainImageUrl: string;
|
chainImageUrl: string;
|
||||||
address: string;
|
address: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user