forked from LaconicNetwork/icns-frontend
[WIP] Fix QA
This commit is contained in:
parent
bb58fb54ea
commit
bcf8827186
4
.pnp.cjs
generated
4
.pnp.cjs
generated
@ -38,6 +38,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/react", "npm:18.0.25"],\
|
||||
["@types/react-dom", "npm:18.0.9"],\
|
||||
["@types/react-modal", "npm:3.13.1"],\
|
||||
["@types/semver", "npm:7.3.13"],\
|
||||
["@types/styled-components", "npm:5.1.26"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
["@typescript-eslint/parser", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
@ -62,6 +63,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["react-is", "npm:18.2.0"],\
|
||||
["react-modal", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1"],\
|
||||
["react-typed", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:1.2.0"],\
|
||||
["semver", "npm:7.3.8"],\
|
||||
["styled-components", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.3.6"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.3#~builtin<compat/typescript>::version=4.9.3&hash=d73830"]\
|
||||
],\
|
||||
@ -3985,6 +3987,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/react", "npm:18.0.25"],\
|
||||
["@types/react-dom", "npm:18.0.9"],\
|
||||
["@types/react-modal", "npm:3.13.1"],\
|
||||
["@types/semver", "npm:7.3.13"],\
|
||||
["@types/styled-components", "npm:5.1.26"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
["@typescript-eslint/parser", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.45.0"],\
|
||||
@ -4009,6 +4012,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["react-is", "npm:18.2.0"],\
|
||||
["react-modal", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:3.16.1"],\
|
||||
["react-typed", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:1.2.0"],\
|
||||
["semver", "npm:7.3.8"],\
|
||||
["styled-components", "virtual:4b77e00d446246df1ed27001550885fbf1b51be18c660c1b5c357d3d763078ecef2a676194291a120f149b87573081e5af0621dc83cf1f83383639f39ac133c7#npm:5.3.6"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.3#~builtin<compat/typescript>::version=4.9.3&hash=d73830"]\
|
||||
],\
|
||||
|
61
components/back-button/index.tsx
Normal file
61
components/back-button/index.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import styled from "styled-components";
|
||||
import color from "../../styles/color";
|
||||
|
||||
import ArrowLeftIcon from "../../public/images/svg/arrow-left.svg";
|
||||
import Image from "next/image";
|
||||
|
||||
export const BackButton: FunctionComponent = () => {
|
||||
return (
|
||||
<Container
|
||||
onClick={() => {
|
||||
location.href = "/";
|
||||
}}
|
||||
>
|
||||
<ContentContainer>
|
||||
<IconContainer>
|
||||
<Image
|
||||
src={ArrowLeftIcon}
|
||||
fill={true}
|
||||
sizes="1rem"
|
||||
alt="arrow left icon"
|
||||
/>
|
||||
</IconContainer>
|
||||
<div>BACK</div>
|
||||
</ContentContainer>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
width: 100%;
|
||||
padding: 0.7rem 0.5rem;
|
||||
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
gap: 0.25rem;
|
||||
`;
|
||||
|
||||
const IconContainer = styled.div`
|
||||
position: relative;
|
||||
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
`;
|
@ -32,6 +32,7 @@ export const AllChainsItem: FunctionComponent<Props> = (props) => {
|
||||
<ChainItemContainer
|
||||
key={chainItem.prefix}
|
||||
isLoading={false}
|
||||
checked={allChecked}
|
||||
onClick={checkHandler}
|
||||
>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
@ -57,5 +58,5 @@ export const AllChainsItem: FunctionComponent<Props> = (props) => {
|
||||
const AllChainsContainer = styled.div`
|
||||
width: 100%;
|
||||
|
||||
background-color: ${color.grey["800"]};
|
||||
background-color: ${color.grey["900"]};
|
||||
`;
|
||||
|
@ -15,7 +15,7 @@ interface Props {
|
||||
|
||||
export const ChainItem: FunctionComponent<Props> = (props) => {
|
||||
const { chainItem, checkedItemHandler, checkedItems, disabled } = props;
|
||||
const [checked, setChecked] = useState(disabled);
|
||||
const [checked, setChecked] = useState(!!disabled);
|
||||
|
||||
const checkHandler = () => {
|
||||
if (!disabled) {
|
||||
@ -35,6 +35,7 @@ export const ChainItem: FunctionComponent<Props> = (props) => {
|
||||
key={chainItem.prefix}
|
||||
isLoading={false}
|
||||
disabled={disabled}
|
||||
checked={checked}
|
||||
onClick={checkHandler}
|
||||
>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
@ -71,10 +72,17 @@ export const ChainItemContainer = styled.div<{
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
opacity: ${(props) => (props.disabled ? "0.3" : "1")};
|
||||
opacity: ${(props) => (props.disabled ? "0.5" : "1")};
|
||||
|
||||
background-color: ${(props) =>
|
||||
props.disabled
|
||||
? color.black
|
||||
: props.checked
|
||||
? color.grey["800"]
|
||||
: color.grey["900"]};
|
||||
|
||||
&:hover {
|
||||
background: ${(props) => (props.isLoading ? null : color.grey["600"])};
|
||||
background: ${(props) => (props.isLoading ? null : color.grey["700"])};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -52,7 +52,7 @@ export const ChainList: FunctionComponent<Props> = (props) => {
|
||||
}, [checkedItems]);
|
||||
|
||||
return (
|
||||
<ChainContainer color={color.grey["800"]}>
|
||||
<ChainContainer color={color.grey["900"]}>
|
||||
{chainList.map((chainItem) => (
|
||||
<ChainItem
|
||||
key={chainItem.address}
|
||||
@ -78,8 +78,10 @@ export const ChainContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 33rem;
|
||||
//max-height: 33rem;
|
||||
overflow: scroll;
|
||||
|
||||
flex: 1;
|
||||
|
||||
background-color: ${(props) => props.color};
|
||||
`;
|
||||
|
@ -1,24 +1,34 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import ArrowRightIcon from "../../public/images/svg/arrow-right.svg";
|
||||
import color from "../../styles/color";
|
||||
import { Flex1 } from "../../styles/flex-1";
|
||||
import styled from "styled-components";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
MINIMUM_VERSION,
|
||||
SELECTED_WALLET_KEY,
|
||||
WALLET_INSTALL_URL,
|
||||
WalletType,
|
||||
} from "../../constants/wallet";
|
||||
import { getKeplrFromWindow, KeplrWallet } from "../../wallets";
|
||||
import { loginWithTwitter } from "../../queries";
|
||||
import {
|
||||
KEPLR_NOT_FOUND_ERROR,
|
||||
KEPLR_VERSION_ERROR,
|
||||
} from "../../constants/error-message";
|
||||
import semver from "semver/preload";
|
||||
|
||||
interface Props {
|
||||
wallet: WalletType;
|
||||
}
|
||||
|
||||
// Todo: Wallet 관련된 부분을 Context로 빼는 부분
|
||||
export const WalletItem: FunctionComponent<Props> = (props: Props) => {
|
||||
const { wallet } = props;
|
||||
const [isInstalled, setIsInstalled] = useState<boolean>();
|
||||
|
||||
useEffect(() => {
|
||||
setIsInstalled(!!window.keplr);
|
||||
}, []);
|
||||
|
||||
const onClickWalletItem = async () => {
|
||||
try {
|
||||
@ -38,6 +48,11 @@ export const WalletItem: FunctionComponent<Props> = (props: Props) => {
|
||||
|
||||
if (keplr === undefined) {
|
||||
window.location.href = WALLET_INSTALL_URL;
|
||||
throw new Error(KEPLR_NOT_FOUND_ERROR);
|
||||
}
|
||||
|
||||
if (semver.lt(keplr.version, MINIMUM_VERSION)) {
|
||||
throw new Error(KEPLR_VERSION_ERROR);
|
||||
}
|
||||
|
||||
if (keplr) {
|
||||
@ -62,7 +77,11 @@ export const WalletItem: FunctionComponent<Props> = (props: Props) => {
|
||||
</WalletIcon>
|
||||
<WalletContentContainer>
|
||||
<WalletName>{wallet.name}</WalletName>
|
||||
{wallet.isReady ? null : (
|
||||
{wallet.isReady ? (
|
||||
isInstalled ? null : (
|
||||
<WalletDescription>Go to install Keplr Extension</WalletDescription>
|
||||
)
|
||||
) : (
|
||||
<WalletDescription>Comming soon</WalletDescription>
|
||||
)}
|
||||
</WalletContentContainer>
|
||||
|
@ -31,10 +31,9 @@ export const LogoContainer = styled.div`
|
||||
justify-content: center;
|
||||
|
||||
position: absolute;
|
||||
|
||||
width: 10rem;
|
||||
height: 5rem;
|
||||
|
||||
margin-top: 80px;
|
||||
margin-left: 80px;
|
||||
margin-top: 5rem;
|
||||
margin-left: 5rem;
|
||||
`;
|
||||
|
@ -7,7 +7,6 @@ export const PrimaryButton = styled.button`
|
||||
|
||||
border: none;
|
||||
|
||||
background-color: ${color.orange["100"]};
|
||||
padding: 11px 30px;
|
||||
|
||||
font-family: "Inter", serif;
|
||||
@ -17,6 +16,7 @@ export const PrimaryButton = styled.button`
|
||||
line-height: 20px;
|
||||
|
||||
color: ${color.orange["50"]};
|
||||
background-color: ${color.orange["100"]};
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
@ -26,6 +26,8 @@ export const PrimaryButton = styled.button`
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: ${color.orange["200"]};
|
||||
opacity: 0.5;
|
||||
|
||||
background-color: ${color.orange["300"]};
|
||||
}
|
||||
`;
|
||||
|
@ -27,99 +27,105 @@ import {
|
||||
} from "../chain-list";
|
||||
|
||||
export const SkeletonChainList: FunctionComponent = () => (
|
||||
<ContentContainer>
|
||||
<ProfileContainer color={color.grey["700"]}>
|
||||
<SkeletonCircle width="5.5rem" height="5.5rem" />
|
||||
<SkeletonContainer>
|
||||
<ContentContainer>
|
||||
<ProfileContainer color={color.grey["700"]}>
|
||||
<SkeletonCircle width="5.5rem" height="5.5rem" />
|
||||
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
<SkeletonText width="5rem" height="1.5rem" />
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
<SkeletonText width="5rem" height="1rem" />
|
||||
</ProfileUserNameContainer>
|
||||
<ProfileContentContainer>
|
||||
<ProfileNameContainer>
|
||||
<SkeletonText width="5rem" height="1.5rem" />
|
||||
</ProfileNameContainer>
|
||||
<ProfileUserNameContainer>
|
||||
<SkeletonText width="5rem" height="1rem" />
|
||||
</ProfileUserNameContainer>
|
||||
|
||||
<ProfileFollowContainer>
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
</ProfileFollowContainer>
|
||||
<ProfileFollowContainer>
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
<SkeletonText width="8rem" height="1rem" />
|
||||
</ProfileFollowContainer>
|
||||
|
||||
<SkeletonText width="20rem" height="1rem" />
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
<SkeletonText width="20rem" height="1rem" />
|
||||
</ProfileContentContainer>
|
||||
</ProfileContainer>
|
||||
|
||||
<ChainListTitleContainer>
|
||||
<SkeletonTitle />
|
||||
</ChainListTitleContainer>
|
||||
<ChainListTitleContainer>
|
||||
<SkeletonTitle />
|
||||
</ChainListTitleContainer>
|
||||
|
||||
<ChainContainer color={color.grey["700"]}>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
<ChainContainer color={color.grey["700"]}>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
<SkeletonDivider />
|
||||
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
<ChainItemContainer isLoading={true}>
|
||||
<ChainImageContainer width="3rem" height="3rem">
|
||||
<SkeletonCircle width="3rem" height="3rem" />
|
||||
</ChainImageContainer>
|
||||
<ChainInfoContainer>
|
||||
<SkeletonText width="4rem" height="1rem" />
|
||||
<SkeletonText width="12rem" height="1rem" />
|
||||
</ChainInfoContainer>
|
||||
</ChainItemContainer>
|
||||
|
||||
<SkeletonDivider />
|
||||
</ChainContainer>
|
||||
<SkeletonDivider />
|
||||
</ChainContainer>
|
||||
|
||||
<ButtonContainer>
|
||||
<SkeletonButton />
|
||||
</ButtonContainer>
|
||||
</ContentContainer>
|
||||
<ButtonContainer>
|
||||
<SkeletonButton />
|
||||
</ButtonContainer>
|
||||
</ContentContainer>
|
||||
</SkeletonContainer>
|
||||
);
|
||||
|
||||
const SkeletonContainer = styled.div`
|
||||
padding: 2.4rem 0;
|
||||
`;
|
||||
|
||||
const SkeletonTitle = styled.div`
|
||||
width: 8rem;
|
||||
height: 1.5rem;
|
||||
|
@ -12,7 +12,7 @@ export const TwitterProfile: FunctionComponent<Props> = (props) => {
|
||||
const { twitterProfileInformation } = props;
|
||||
|
||||
return (
|
||||
<ProfileContainer color={color.grey["800"]}>
|
||||
<ProfileContainer color={color.grey["900"]}>
|
||||
<ProfileImageContainer>
|
||||
<Image
|
||||
src={twitterProfileInformation?.profile_image_url ?? ""}
|
||||
|
@ -2,3 +2,4 @@ export const TWITTER_LOGIN_ERROR = "Twitter login access denied";
|
||||
export const TWITTER_PROFILE_ERROR = "Twitter auth code is not valid";
|
||||
|
||||
export const KEPLR_NOT_FOUND_ERROR = "Can't fount window.keplr";
|
||||
export const KEPLR_VERSION_ERROR = "You should update keplr";
|
||||
|
@ -1,9 +1,13 @@
|
||||
export const MainChainId = "osmo-test-4";
|
||||
|
||||
export const REFERRAL_KEY = "icns-referral";
|
||||
|
||||
export const RPC_URL = "https://rpc.testnet.osmosis.zone";
|
||||
export const REST_URL = "https://lcd.testnet.osmosis.zone";
|
||||
|
||||
// TODO: .evn에 없으면 디폴트값 설정
|
||||
export const NAME_NFT_ADDRESS =
|
||||
"osmo1xahnjn872smah6xle8n3z5a5teqq390qr959l805mkuw0kcy8g5smtdagg";
|
||||
export const REGISTRAR_ADDRESS =
|
||||
"osmo1npn97g7hsgqlp70rw8nhd7c7vyvkukv9x0n25sn4fk5mgcjlz4gq9zlgf3";
|
||||
export const RESOLVER_ADDRESS =
|
||||
|
@ -7,3 +7,5 @@ export const twitterOAuthScopes = [
|
||||
];
|
||||
|
||||
export const twitterApiBaseUrl = "https://api.twitter.com/2";
|
||||
|
||||
export const SHARE_URL = "https://twitter.com/share";
|
||||
|
@ -7,6 +7,8 @@ export const WALLET_INSTALL_URL =
|
||||
"https://chrome.google.com/webstore/detail/keplr/dmkamcknogkgcdfhhbddcghachkejeap";
|
||||
export const SELECTED_WALLET_KEY = "SELECTED_WALLET_KEY";
|
||||
|
||||
export const MINIMUM_VERSION = "0.11.22";
|
||||
|
||||
export type WalletName = "Keplr" | "Cosmostation";
|
||||
export interface WalletType {
|
||||
name: WalletName;
|
||||
|
@ -7,6 +7,7 @@ export const makeClaimMessage = (
|
||||
senderAddress: string,
|
||||
twitterUserName: string,
|
||||
verificationList: any[],
|
||||
referral?: string,
|
||||
): CosmwasmExecuteMessageResult => {
|
||||
return makeCosmwasmExecMsg(
|
||||
senderAddress,
|
||||
@ -26,6 +27,7 @@ export const makeClaimMessage = (
|
||||
};
|
||||
}
|
||||
}),
|
||||
referral,
|
||||
},
|
||||
},
|
||||
[ContractFee],
|
||||
|
@ -24,6 +24,7 @@
|
||||
"react-is": "^18.2.0",
|
||||
"react-modal": "^3.16.1",
|
||||
"react-typed": "^1.2.0",
|
||||
"semver": "^7.3.8",
|
||||
"styled-components": "^5.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -33,6 +34,7 @@
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "18.0.9",
|
||||
"@types/react-modal": "^3",
|
||||
"@types/semver": "^7",
|
||||
"@types/styled-components": "^5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
|
@ -9,31 +9,56 @@ import color from "../../styles/color";
|
||||
import AlertCircleOutlineIcon from "../../public/images/svg/alert-circle-outline.svg";
|
||||
import TwitterIcon from "../../public/images/svg/twitter-icon.svg";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { TendermintTxTracer } from "@keplr-wallet/cosmos";
|
||||
import { queryAddressesFromTwitterName } from "../../queries";
|
||||
import { RegisteredAddresses } from "../../types";
|
||||
import { SHARE_URL } from "../../constants/twitter";
|
||||
|
||||
export default function CompletePage() {
|
||||
const router = useRouter();
|
||||
|
||||
const [registeredAddressed, setRegisteredAddressed] =
|
||||
useState<RegisteredAddresses[]>();
|
||||
|
||||
const [availableAddress, setAvailableAddress] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const { txHash } = router.query;
|
||||
const { txHash, twitterUsername } = router.query;
|
||||
|
||||
if (txHash) {
|
||||
traceTX(txHash as string);
|
||||
if (txHash && twitterUsername) {
|
||||
initialize(txHash as string, twitterUsername as string);
|
||||
}
|
||||
}, []);
|
||||
}, [router.query]);
|
||||
|
||||
const traceTX = async (txHash: string) => {
|
||||
const initialize = async (txHash: string, twitterUserName: string) => {
|
||||
const txTracer = new TendermintTxTracer(
|
||||
"https://rpc.testnet.osmosis.zone",
|
||||
"/websocket",
|
||||
);
|
||||
|
||||
const result = await txTracer.traceTx(Buffer.from(txHash, "hex"));
|
||||
const result: { code?: number } = await txTracer.traceTx(
|
||||
Buffer.from(txHash, "hex"),
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
if (result.code || result.code === 0) {
|
||||
const addresses = await queryAddressesFromTwitterName(twitterUserName);
|
||||
setRegisteredAddressed(addresses.data.addresses);
|
||||
}
|
||||
};
|
||||
|
||||
// Todo rsult => 확인 후에 확인
|
||||
const onClickShareButton = () => {
|
||||
const { twitterUsername } = router.query;
|
||||
|
||||
const width = 500;
|
||||
const height = 700;
|
||||
window.open(
|
||||
`${SHARE_URL}?url=https://www.icns.xyz/&text=${twitterUsername}`,
|
||||
"Share Twitter",
|
||||
`top=${(window.screen.height - height) / 2}, left=${
|
||||
(window.screen.width - width) / 2
|
||||
}, width=${width}, height=${height}, status=no, menubar=no, toolbar=no, resizable=no`,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -41,22 +66,31 @@ export default function CompletePage() {
|
||||
<Logo />
|
||||
|
||||
<MainContainer>
|
||||
<MainTitle>Your Name is Active Now!</MainTitle>
|
||||
<MainTitle>
|
||||
<div>Your Name is Active Now!</div>
|
||||
</MainTitle>
|
||||
<ContentContainer>
|
||||
<RecipentContainer>
|
||||
<RecipentTitle>Recipent</RecipentTitle>
|
||||
<AddressContainer>
|
||||
kingstarcookies.
|
||||
<Typed
|
||||
strings={["osmo", "cosmos"]}
|
||||
typeSpeed={150}
|
||||
backSpeed={150}
|
||||
backDelay={1000}
|
||||
loop
|
||||
smartBackspace
|
||||
/>
|
||||
{`${router.query.twitterUsername}.`}
|
||||
{registeredAddressed && (
|
||||
<Typed
|
||||
strings={registeredAddressed.map(
|
||||
(address) => address.bech32_prefix,
|
||||
)}
|
||||
typeSpeed={150}
|
||||
backSpeed={150}
|
||||
backDelay={1000}
|
||||
loop
|
||||
smartBackspace
|
||||
onStringTyped={(arrayPos: number) => {
|
||||
setAvailableAddress(registeredAddressed[arrayPos].address);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AddressContainer>
|
||||
<AvailableAddressText>available address</AvailableAddressText>
|
||||
<AvailableAddressText>{availableAddress}</AvailableAddressText>
|
||||
</RecipentContainer>
|
||||
</ContentContainer>
|
||||
|
||||
@ -70,7 +104,7 @@ export default function CompletePage() {
|
||||
</DescriptionText>
|
||||
</DescriptionContainer>
|
||||
|
||||
<ShareButtonContainer>
|
||||
<ShareButtonContainer onClick={onClickShareButton}>
|
||||
<ShareButtonText>SHARE MY NAME</ShareButtonText>
|
||||
<Image src={TwitterIcon} alt="twitter icon" />
|
||||
</ShareButtonContainer>
|
||||
@ -95,19 +129,22 @@ const MainContainer = styled.div`
|
||||
`;
|
||||
|
||||
const MainTitle = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
|
||||
padding: 1rem;
|
||||
height: 5rem;
|
||||
`;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
width: 30rem;
|
||||
|
||||
margin-top: 1rem;
|
||||
padding: 2rem 2rem;
|
||||
|
||||
background-color: ${color.grey["900"]};
|
||||
@ -152,19 +189,22 @@ const AvailableAddressText = styled.div`
|
||||
font-size: 0.75rem;
|
||||
line-height: 0.75rem;
|
||||
|
||||
min-height: 0.75rem;
|
||||
|
||||
color: ${color.blue};
|
||||
`;
|
||||
|
||||
const DescriptionContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
gap: 1rem;
|
||||
|
||||
width: 30rem;
|
||||
|
||||
margin-top: 1.5rem;
|
||||
padding: 1.5rem 2rem;
|
||||
padding: 1.25rem 2rem;
|
||||
|
||||
background-color: ${color.grey["900"]};
|
||||
`;
|
||||
@ -183,7 +223,7 @@ const DescriptionText = styled.div`
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
line-height: 140%;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
@ -16,6 +16,8 @@ import CheckIcon from "../public/images/svg/check-icon.svg";
|
||||
import { Logo } from "../components/logo";
|
||||
import { useEffect, useState } from "react";
|
||||
import { SELECTED_WALLET_KEY } from "../constants/wallet";
|
||||
import { replaceToInstallPage } from "../utils/url";
|
||||
import { REFERRAL_KEY } from "../constants/icns";
|
||||
|
||||
export default function Home() {
|
||||
const [isModalOpen, setModalOpen] = useState(false);
|
||||
@ -25,6 +27,17 @@ export default function Home() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.removeItem(REFERRAL_KEY);
|
||||
|
||||
if (window.location.search) {
|
||||
const [, referral] =
|
||||
window.location.search.match(/^(?=.*referral=([^&]+)|).+$/) || [];
|
||||
|
||||
if (referral) {
|
||||
localStorage.setItem(REFERRAL_KEY, referral);
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.removeItem(SELECTED_WALLET_KEY);
|
||||
}, []);
|
||||
|
||||
@ -62,7 +75,8 @@ export default function Home() {
|
||||
/>
|
||||
</CheckIconContainer>
|
||||
You are a <CheckBoldText> keplr </CheckBoldText> user.
|
||||
if not, you can install here
|
||||
if not, you can install
|
||||
<InstallLInk onClick={replaceToInstallPage}>HERE</InstallLInk>
|
||||
</CheckContainer>
|
||||
<CheckContainer>
|
||||
<CheckIconContainer>
|
||||
@ -182,7 +196,16 @@ const CheckContainer = styled.div`
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
color: ${color.grey["300"]};
|
||||
padding-left: 0.75rem;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
`;
|
||||
|
||||
const InstallLInk = styled.a`
|
||||
color: ${color.grey["400"]};
|
||||
text-decoration: underline;
|
||||
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const CheckBoldText = styled.span`
|
||||
|
@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
// Types
|
||||
import {
|
||||
ChainItemType,
|
||||
QueryError,
|
||||
RegisteredAddresses,
|
||||
TwitterProfileType,
|
||||
} from "../../types";
|
||||
@ -32,11 +33,17 @@ 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";
|
||||
import { SearchInput } from "../../components/search-input";
|
||||
import { MainChainId, RESOLVER_ADDRESS, REST_URL } from "../../constants/icns";
|
||||
import {
|
||||
MainChainId,
|
||||
REFERRAL_KEY,
|
||||
RESOLVER_ADDRESS,
|
||||
REST_URL,
|
||||
} from "../../constants/icns";
|
||||
|
||||
import {
|
||||
fetchTwitterInfo,
|
||||
queryAddressesFromTwitterName,
|
||||
queryOwnerOfTwitterName,
|
||||
queryRegisteredTwitterId,
|
||||
verifyTwitterAccount,
|
||||
} from "../../queries";
|
||||
@ -46,6 +53,8 @@ import {
|
||||
TWITTER_LOGIN_ERROR,
|
||||
} from "../../constants/error-message";
|
||||
import { makeClaimMessage, makeSetRecordMessage } from "../../messages";
|
||||
import Axios, { AxiosError } from "axios";
|
||||
import { BackButton } from "../../components/back-button";
|
||||
|
||||
export default function VerificationPage() {
|
||||
const router = useRouter();
|
||||
@ -69,6 +78,9 @@ export default function VerificationPage() {
|
||||
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
|
||||
const [isOwner, setIsOwner] = useState(false);
|
||||
const [isAgree, setIsAgree] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
if (window.location.search) {
|
||||
@ -78,7 +90,7 @@ export default function VerificationPage() {
|
||||
);
|
||||
|
||||
// Initialize Wallet
|
||||
await initWallet();
|
||||
const keplrWallet = await initWallet();
|
||||
|
||||
// Fetch Twitter Profile
|
||||
const twitterInfo = await fetchTwitterInfo(state, code);
|
||||
@ -94,10 +106,19 @@ export default function VerificationPage() {
|
||||
});
|
||||
|
||||
if ("data" in registeredQueryResponse) {
|
||||
const ownerOfQueryResponse = await queryOwnerOfTwitterName(
|
||||
registeredQueryResponse.data.name,
|
||||
);
|
||||
|
||||
const addressesQueryResponse = await queryAddressesFromTwitterName(
|
||||
registeredQueryResponse.data.name,
|
||||
);
|
||||
|
||||
if (keplrWallet) {
|
||||
const key = await keplrWallet.getKey(MainChainId);
|
||||
setIsOwner(ownerOfQueryResponse.data.owner === key.bech32Address);
|
||||
}
|
||||
|
||||
setRegisteredChainList(addressesQueryResponse.data.addresses);
|
||||
}
|
||||
} catch (error) {
|
||||
@ -153,6 +174,8 @@ export default function VerificationPage() {
|
||||
|
||||
await fetchChainList(keplrWallet);
|
||||
setWallet(keplrWallet);
|
||||
|
||||
return keplrWallet;
|
||||
} else {
|
||||
ErrorHandler(KEPLR_NOT_FOUND_ERROR);
|
||||
}
|
||||
@ -227,84 +250,99 @@ export default function VerificationPage() {
|
||||
};
|
||||
|
||||
const onClickRegistration = async () => {
|
||||
const { state, code } = checkTwitterAuthQueryParameter(
|
||||
window.location.search,
|
||||
);
|
||||
const twitterInfo = await fetchTwitterInfo(state, code);
|
||||
|
||||
const adr36Infos = await checkAdr36();
|
||||
|
||||
if (wallet && adr36Infos) {
|
||||
const key = await wallet.getKey(MainChainId);
|
||||
|
||||
const icnsVerificationList = await verifyTwitterAccount(
|
||||
key.bech32Address,
|
||||
twitterInfo.accessToken,
|
||||
try {
|
||||
const { state, code } = checkTwitterAuthQueryParameter(
|
||||
window.location.search,
|
||||
);
|
||||
const twitterInfo = await fetchTwitterInfo(state, code);
|
||||
|
||||
const registerMsg = makeClaimMessage(
|
||||
key.bech32Address,
|
||||
twitterInfo.username,
|
||||
icnsVerificationList,
|
||||
);
|
||||
const adr36Infos = await checkAdr36();
|
||||
|
||||
const addressMsgs = adr36Infos.map((adr36Info) => {
|
||||
return makeSetRecordMessage(
|
||||
if (wallet && adr36Infos) {
|
||||
const key = await wallet.getKey(MainChainId);
|
||||
|
||||
const icnsVerificationList = await verifyTwitterAccount(
|
||||
key.bech32Address,
|
||||
twitterInfo.accessToken,
|
||||
);
|
||||
|
||||
const registerMsg = makeClaimMessage(
|
||||
key.bech32Address,
|
||||
twitterInfo.username,
|
||||
adr36Info,
|
||||
icnsVerificationList,
|
||||
localStorage.getItem(REFERRAL_KEY) ?? undefined,
|
||||
);
|
||||
});
|
||||
|
||||
const aminoMsgs = twitterAuthInfo?.isRegistered
|
||||
? []
|
||||
: [registerMsg.amino];
|
||||
const protoMsgs = twitterAuthInfo?.isRegistered
|
||||
? []
|
||||
: [registerMsg.proto];
|
||||
const addressMsgs = adr36Infos.map((adr36Info) => {
|
||||
return makeSetRecordMessage(
|
||||
key.bech32Address,
|
||||
twitterInfo.username,
|
||||
adr36Info,
|
||||
);
|
||||
});
|
||||
|
||||
for (const addressMsg of addressMsgs) {
|
||||
aminoMsgs.push(addressMsg.amino);
|
||||
protoMsgs.push(addressMsg.proto);
|
||||
const aminoMsgs = twitterAuthInfo?.isRegistered
|
||||
? []
|
||||
: [registerMsg.amino];
|
||||
const protoMsgs = twitterAuthInfo?.isRegistered
|
||||
? []
|
||||
: [registerMsg.proto];
|
||||
|
||||
for (const addressMsg of addressMsgs) {
|
||||
aminoMsgs.push(addressMsg.amino);
|
||||
protoMsgs.push(addressMsg.proto);
|
||||
}
|
||||
|
||||
const chainInfo = {
|
||||
chainId: MainChainId,
|
||||
rest: REST_URL,
|
||||
};
|
||||
|
||||
const simulated = await simulateMsgs(
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
},
|
||||
);
|
||||
|
||||
const txHash = await sendMsgs(
|
||||
wallet,
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
amino: aminoMsgs,
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
gas: Math.floor(simulated.gasUsed * 1.5).toString(),
|
||||
},
|
||||
);
|
||||
|
||||
await router.push({
|
||||
pathname: "complete",
|
||||
query: {
|
||||
txHash: Buffer.from(txHash).toString("hex"),
|
||||
twitterUsername: twitterInfo.username,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
if (Axios.isAxiosError(error)) {
|
||||
console.error((error?.response?.data as QueryError).message);
|
||||
}
|
||||
|
||||
const chainInfo = {
|
||||
chainId: MainChainId,
|
||||
rest: REST_URL,
|
||||
};
|
||||
|
||||
const simulated = await simulateMsgs(
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
},
|
||||
);
|
||||
|
||||
const txHash = await sendMsgs(
|
||||
wallet,
|
||||
chainInfo,
|
||||
key.bech32Address,
|
||||
{
|
||||
amino: aminoMsgs,
|
||||
proto: protoMsgs,
|
||||
},
|
||||
{
|
||||
amount: [],
|
||||
gas: Math.floor(simulated.gasUsed * 1.5).toString(),
|
||||
},
|
||||
);
|
||||
|
||||
await router.push({
|
||||
pathname: "complete",
|
||||
query: { txHash: Buffer.from(txHash).toString("hex") },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isRegisterButtonDisable =
|
||||
checkedItems.size < 1 ||
|
||||
(!isOwner && registeredChainList.length > 0) ||
|
||||
!isAgree;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Logo />
|
||||
@ -314,6 +352,7 @@ export default function VerificationPage() {
|
||||
<SkeletonChainList />
|
||||
) : (
|
||||
<ContentContainer>
|
||||
<BackButton />
|
||||
<TwitterProfile twitterProfileInformation={twitterAuthInfo} />
|
||||
|
||||
<ChainListTitleContainer>
|
||||
@ -351,9 +390,21 @@ export default function VerificationPage() {
|
||||
setCheckedItems={setCheckedItems}
|
||||
/>
|
||||
|
||||
<ButtonContainer>
|
||||
<AgreeContainer>
|
||||
<AgreeCheckBox
|
||||
type="checkbox"
|
||||
checked={isAgree}
|
||||
onClick={() => {
|
||||
setIsAgree(!isAgree);
|
||||
}}
|
||||
readOnly
|
||||
/>
|
||||
I check that Osmo is required for this transaction
|
||||
</AgreeContainer>
|
||||
|
||||
<ButtonContainer disabled={isRegisterButtonDisable}>
|
||||
<PrimaryButton
|
||||
disabled={checkedItems.size < 1}
|
||||
disabled={isRegisterButtonDisable}
|
||||
onClick={onClickRegistration}
|
||||
>
|
||||
Register
|
||||
@ -375,6 +426,10 @@ const MainContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
height: 100vh;
|
||||
|
||||
padding: 2.7rem 0;
|
||||
|
||||
color: white;
|
||||
`;
|
||||
|
||||
@ -384,15 +439,14 @@ export const ContentContainer = styled.div`
|
||||
align-items: center;
|
||||
|
||||
width: 40rem;
|
||||
|
||||
margin-top: 5rem;
|
||||
`;
|
||||
|
||||
export const ButtonContainer = styled.div`
|
||||
export const ButtonContainer = styled.div<{ disabled?: boolean }>`
|
||||
width: 12rem;
|
||||
height: 4rem;
|
||||
|
||||
margin-top: 2rem;
|
||||
background-color: ${(props) =>
|
||||
props.disabled ? color.orange["300"] : color.orange["100"]};
|
||||
`;
|
||||
|
||||
export const ChainListTitleContainer = styled.div`
|
||||
@ -414,3 +468,26 @@ const ChainListTitle = styled.div`
|
||||
|
||||
color: ${color.white};
|
||||
`;
|
||||
|
||||
const AgreeContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
font-family: "Inter", serif;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
color: ${color.grey["400"]};
|
||||
|
||||
padding: 2rem 0;
|
||||
`;
|
||||
|
||||
const AgreeCheckBox = styled.input.attrs({ type: "checkbox" })`
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
`;
|
||||
|
3
public/images/svg/arrow-left.svg
Normal file
3
public/images/svg/arrow-left.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.57812 14.0625L3.51562 9L8.57812 3.9375M4.21875 9H14.4844" stroke="#5B5B5B" stroke-width="1.5" stroke-linecap="square"/>
|
||||
</svg>
|
After Width: | Height: | Size: 235 B |
@ -1,5 +1,6 @@
|
||||
import { request } from "../utils/url";
|
||||
import {
|
||||
NAME_NFT_ADDRESS,
|
||||
REGISTRAR_ADDRESS,
|
||||
RESOLVER_ADDRESS,
|
||||
REST_URL,
|
||||
@ -8,6 +9,7 @@ import { Buffer } from "buffer/";
|
||||
import {
|
||||
AddressesQueryResponse,
|
||||
NameByTwitterIdQueryResponse,
|
||||
OwnerOfQueryResponse,
|
||||
QueryError,
|
||||
} from "../types";
|
||||
|
||||
@ -20,11 +22,14 @@ export const queryRegisteredTwitterId = async (
|
||||
const msg = {
|
||||
name_by_twitter_id: { twitter_id: twitterId },
|
||||
};
|
||||
|
||||
return request<NameByTwitterIdQueryResponse>(
|
||||
getCosmwasmQueryUrl(
|
||||
REGISTRAR_ADDRESS,
|
||||
Buffer.from(JSON.stringify(msg)).toString("base64"),
|
||||
),
|
||||
{},
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
@ -42,3 +47,20 @@ export const queryAddressesFromTwitterName = async (
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
export const queryOwnerOfTwitterName = async (
|
||||
twitterUsername: string,
|
||||
): Promise<OwnerOfQueryResponse> => {
|
||||
const msg = {
|
||||
owner_of: { token_id: twitterUsername },
|
||||
};
|
||||
|
||||
return request<OwnerOfQueryResponse>(
|
||||
getCosmwasmQueryUrl(
|
||||
NAME_NFT_ADDRESS,
|
||||
Buffer.from(JSON.stringify(msg)).toString("base64"),
|
||||
),
|
||||
{},
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
@ -16,8 +16,8 @@ const grey = {
|
||||
400: "#5B5B5B",
|
||||
500: "#424242",
|
||||
600: "#333333",
|
||||
700: "#2B2B2B",
|
||||
800: "#242424",
|
||||
700: "#222222",
|
||||
800: "#1D1D1D",
|
||||
900: "#181818",
|
||||
};
|
||||
const black = "#121212";
|
||||
|
@ -59,3 +59,9 @@ export interface QueryError {
|
||||
code: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface OwnerOfQueryResponse {
|
||||
data: {
|
||||
owner: string;
|
||||
};
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { TwitterLoginSuccess } from "../types";
|
||||
import { TWITTER_LOGIN_ERROR } from "../constants/error-message";
|
||||
import { WALLET_INSTALL_URL } from "../constants/wallet";
|
||||
|
||||
export function request<TResponse>(
|
||||
url: string,
|
||||
config: RequestInit = {},
|
||||
isIgnore?: boolean,
|
||||
): Promise<TResponse> {
|
||||
return fetch(url, config)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
if (!response.ok && !isIgnore) {
|
||||
throw new Error(
|
||||
`This is an HTTP error: The status is ${response.status} ${response.statusText}`,
|
||||
);
|
||||
@ -44,3 +46,7 @@ export const checkTwitterAuthQueryParameter = (
|
||||
code,
|
||||
};
|
||||
};
|
||||
|
||||
export const replaceToInstallPage = () => {
|
||||
window.location.href = WALLET_INSTALL_URL;
|
||||
};
|
||||
|
@ -1109,7 +1109,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/semver@npm:^7.3.12":
|
||||
"@types/semver@npm:^7, @types/semver@npm:^7.3.12":
|
||||
version: 7.3.13
|
||||
resolution: "@types/semver@npm:7.3.13"
|
||||
checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0
|
||||
@ -3175,6 +3175,7 @@ __metadata:
|
||||
"@types/react": 18.0.25
|
||||
"@types/react-dom": 18.0.9
|
||||
"@types/react-modal": ^3
|
||||
"@types/semver": ^7
|
||||
"@types/styled-components": ^5
|
||||
"@typescript-eslint/eslint-plugin": ^5.45.0
|
||||
"@typescript-eslint/parser": ^5.45.0
|
||||
@ -3199,6 +3200,7 @@ __metadata:
|
||||
react-is: ^18.2.0
|
||||
react-modal: ^3.16.1
|
||||
react-typed: ^1.2.0
|
||||
semver: ^7.3.8
|
||||
styled-components: ^5.3.6
|
||||
typescript: 4.9.3
|
||||
languageName: unknown
|
||||
|
Loading…
Reference in New Issue
Block a user