diff --git a/components/error-modal/index.tsx b/components/error-modal/index.tsx new file mode 100644 index 0000000..de154a8 --- /dev/null +++ b/components/error-modal/index.tsx @@ -0,0 +1,151 @@ +import color from "../../styles/color"; +import { FunctionComponent } from "react"; +import ReactModal from "react-modal"; +import { ErrorMessage } from "../../types"; +import styled from "styled-components"; + +import Image from "next/image"; +interface Props { + isModalOpen: boolean; + onCloseModal: () => void; + errorMessage?: ErrorMessage; +} + +import ErrorIcon from "../../public/images/svg/error-icon.svg"; +import ArrowLeftIcon from "../../public/images/svg/arrow-left.svg"; +import { useRouter } from "next/router"; + +export const ErrorModal: FunctionComponent = (props) => { + const router = useRouter(); + const { isModalOpen, onCloseModal, errorMessage } = props; + + const onClose = async () => { + if (errorMessage?.path) { + await router.push(errorMessage.path); + } + + onCloseModal(); + }; + + return ( + + + + + error icon + + Error + + + {errorMessage?.message} + + {errorMessage?.path ? ( + + + back button icon + + GO BACK TO HOME + + ) : null} + + + ); +}; + +const ModalContainer = styled.div` + display: flex; + flex-direction: column; + + width: 32rem; + + padding: 2.5rem 2.25rem; +`; + +const ErrorTitleContainer = styled.div` + display: flex; + flex-direction: row; + gap: 1rem; + + align-items: center; + + font-family: "Inter", serif; + font-style: normal; + font-weight: 600; + font-size: 2rem; + line-height: 2.5rem; + + color: ${color.white}; +`; + +const ErrorImageContainer = styled.div` + width: 2.5rem; + height: 2.5rem; + + position: relative; +`; + +const ErrorDescription = styled.div` + margin-top: 1rem; + + font-family: "Inter", serif; + font-style: normal; + font-weight: 400; + font-size: 1rem; + line-height: 1.25rem; + + color: ${color.grey["300"]}; +`; + +const ErrorBackButton = styled.div` + display: flex; + flex-direction: row; + align-items: center; + gap: 0.3rem; + + margin-top: 2.5rem; + + font-family: "Inter", serif; + font-style: normal; + font-weight: 600; + font-size: 1.125rem; + line-height: 1.125rem; + + color: ${color.grey["100"]}; + + cursor: pointer; +`; + +const ErrorBackIconContainer = styled.div` + width: 1.5rem; + height: 1.5rem; + + position: relative; +`; diff --git a/pages/verification/index.tsx b/pages/verification/index.tsx index 6975071..b2f6048 100644 --- a/pages/verification/index.tsx +++ b/pages/verification/index.tsx @@ -7,6 +7,7 @@ import { useEffect, useState } from "react"; import { ChainItemType, DisabledChainItemType, + ErrorMessage, QueryError, RegisteredAddresses, TwitterProfileType, @@ -58,6 +59,7 @@ import { makeClaimMessage, makeSetRecordMessage } from "../../messages"; import Axios from "axios"; import { BackButton } from "../../components/back-button"; import { FinalCheckModal } from "../../components/final-check-modal"; +import { ErrorModal } from "../../components/error-modal"; export default function VerificationPage() { const router = useRouter(); @@ -93,6 +95,8 @@ export default function VerificationPage() { const [isOwner, setIsOwner] = useState(false); const [isModalOpen, setModalOpen] = useState(false); + const [isErrorModalOpen, setErrorModalOpen] = useState(false); + const [errorMessage, setErrorMessage] = useState(); useEffect(() => { init(); @@ -203,8 +207,11 @@ export default function VerificationPage() { setRegisteredChainList(addressesQueryResponse.data.addresses); } } catch (error) { - if (error instanceof Error && error.message === TWITTER_LOGIN_ERROR) { - await router.push("/"); + if (error instanceof Error) { + if (error.message === TWITTER_LOGIN_ERROR) { + setErrorMessage({ message: TWITTER_LOGIN_ERROR, path: "/" }); + setErrorModalOpen(true); + } } console.error(error); @@ -227,7 +234,8 @@ export default function VerificationPage() { return keplrWallet; } else { - ErrorHandler(KEPLR_NOT_FOUND_ERROR); + setErrorMessage({ message: KEPLR_NOT_FOUND_ERROR, path: "/" }); + setErrorModalOpen(true); } }; @@ -399,7 +407,17 @@ export default function VerificationPage() { } } catch (error) { if (Axios.isAxiosError(error)) { - console.error((error?.response?.data as QueryError).message); + setErrorMessage({ + message: (error?.response?.data as QueryError).message, + }); + setErrorModalOpen(true); + return; + } + + if (error instanceof Error) { + console.log(error.message); + setErrorMessage({ message: error.message }); + setErrorModalOpen(true); } } finally { setIsLoadingRegistration(false); @@ -490,6 +508,12 @@ export default function VerificationPage() { onClickRegisterButton={handleRegistration} isLoadingRegistration={isLoadingRegistration} /> + + setErrorModalOpen(false)} + errorMessage={errorMessage} + /> ); } diff --git a/public/images/svg/error-icon.svg b/public/images/svg/error-icon.svg new file mode 100644 index 0000000..3ab520f --- /dev/null +++ b/public/images/svg/error-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/types/error-message.ts b/types/error-message.ts new file mode 100644 index 0000000..07e207c --- /dev/null +++ b/types/error-message.ts @@ -0,0 +1,4 @@ +export interface ErrorMessage { + message: string; + path?: string; +} diff --git a/types/index.ts b/types/index.ts index a14cb5f..7a6f5e9 100644 --- a/types/index.ts +++ b/types/index.ts @@ -4,3 +4,4 @@ export * from "./chain-item-type"; export * from "./msg"; export * from "./twitter"; export * from "./icns"; +export * from "./error-message";