Add all chains item, Fix checkbox logic

This commit is contained in:
HeesungB 2022-12-13 21:21:16 +09:00
parent 10e129baad
commit 1dd9e31911
7 changed files with 224 additions and 29 deletions

View 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"]};
`;

View File

@ -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<unknown>;
}
export const ChainItem: FunctionComponent<Props> = (props) => {
const { chainItem, checkedItemHandler } = props;
const { chainItem, checkedItemHandler, checkedItems } = props;
const [checked, setChecked] = useState(false);
const checkHandler = (event: ChangeEvent<HTMLInputElement>) => {
const checkHandler = () => {
setChecked(!checked);
checkedItemHandler(chainItem, event.target.checked);
checkedItemHandler(chainItem, !checked);
};
useEffect(() => {
setChecked(checkedItems.has(chainItem));
}, [checkedItems]);
return (
<ChainItemContainer key={chainItem.prefix} isLoading={false}>
<ChainItemContainer
key={chainItem.prefix}
isLoading={false}
onClick={checkHandler}
>
<ChainImageContainer width="3rem" height="3rem">
<ChainImage
src={chainItem.chainImageUrl}
@ -40,31 +57,36 @@ export const ChainItem: FunctionComponent<Props> = (props) => {
<Flex1 />
<ChainCheckBox
checked={checked}
onChange={(event) => checkHandler(event)}
/>
<ChainCheckBox checked={checked} />
</ChainItemContainer>
);
};
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;
`;

View File

@ -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<SetStateAction<boolean>>;
chainList: ChainItemType[];
checkedItems: any;
setCheckedItems: any;
checkedItems: Set<unknown>;
setCheckedItems: Dispatch<SetStateAction<Set<unknown>>>;
}
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 tempSet = new Set(checkedItems);
@ -25,6 +33,22 @@ export const ChainList: FunctionComponent<Props> = (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 (
<ChainContainer color={color.grey["800"]}>
{chainList.map((chainItem) => (
@ -32,6 +56,7 @@ export const ChainList: FunctionComponent<Props> = (props) => {
key={chainItem.address}
chainItem={chainItem}
checkedItemHandler={checkedItemHandler}
checkedItems={checkedItems}
/>
))}
</ChainContainer>

View File

@ -15,6 +15,10 @@ const nextConfig = {
protocol: "https",
hostname: "raw.githubusercontent.com",
},
{
protocol: "https",
hostname: "abs.twimg.com",
},
],
},
};

View File

@ -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<TwitterAuthInfoResponse | null>();
const [chainList, setChainList] = useState<ChainItemType[]>([]);
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 [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() {
<SearchContainer>Search</SearchContainer>
</ChainListTitleContainer>
{allChains ? (
<AllChainsItem
allChecked={allChecked}
setAllChecked={setAllChecked}
chainItem={allChains}
/>
) : null}
<ChainList
allChecked={allChecked}
setAllChecked={setAllChecked}
chainList={chainList}
checkedItems={checkedItems}
setCheckedItems={setCheckedItems}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 646 KiB

View File

@ -1,4 +1,5 @@
export interface ChainItemType {
chainId: string;
prefix: string;
chainImageUrl: string;
address: string;