From a8756731897529598e15d2569e65b9fe9a38793c Mon Sep 17 00:00:00 2001 From: nabarun Date: Fri, 26 Jul 2024 08:33:51 +0000 Subject: [PATCH] Add terms and conditions page and update cosmos tx message (#2) Part of [Sumsub KYC integration in onboarding app](https://www.notion.so/Sumsub-KYC-integration-in-onboarding-app-607b598c9c1d4d12adc71725e2ab5e7e) - Add terms and conditions in home page and before signing cosmos message - Add `kycId` and `role` field in cosmos message Co-authored-by: IshaVenikar Co-authored-by: Shreerang Kale Reviewed-on: https://git.vdb.to/deep-stack/testnet-onboarding-app/pulls/2 --- src/App.tsx | 14 ++-- src/components/Header.tsx | 33 +++++++++ src/components/TermsAndConditionsCard.tsx | 81 +++++++++++++++++++++ src/components/TermsAndConditionsDialog.tsx | 34 +++++++++ src/constants.ts | 9 +++ src/layout/SignPageLayout.tsx | 22 +----- src/pages/ConnectWallet.tsx | 31 +++----- src/pages/OnboardingSuccess.tsx | 6 +- src/pages/SignWithCosmos.tsx | 31 +++++--- src/pages/SignWithNitroKey.tsx | 10 ++- src/pages/TermsAndConditions.tsx | 44 +++++++++++ src/pages/UserVerification.tsx | 10 +-- 12 files changed, 259 insertions(+), 66 deletions(-) create mode 100644 src/components/Header.tsx create mode 100644 src/components/TermsAndConditionsCard.tsx create mode 100644 src/components/TermsAndConditionsDialog.tsx create mode 100644 src/constants.ts create mode 100644 src/pages/TermsAndConditions.tsx diff --git a/src/App.tsx b/src/App.tsx index 82125ac..af3f1ed 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,28 +6,32 @@ import SignWithNitroKey from "./pages/SignWithNitroKey"; import SignWithCosmos from "./pages/SignWithCosmos"; import PageNotFound from "./pages/PageNotFound"; import OnboardingSuccess from "./pages/OnboardingSuccess"; -import UserVerification from "./pages/UserVerification"; import SignPageLayout from "./layout/SignPageLayout"; +import UserVerification from "./pages/UserVerification"; +import TermsAndConditions from "./pages/TermsAndConditions"; +import Header from "./components/Header"; import { WalletConnectProvider } from "./context/WalletConnectContext"; function App() { return ( +
- } /> + } /> } /> + } /> }> - } /> + } /> } /> } > diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 0000000..0b627a6 --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; + +import { AppBar, Toolbar, Avatar, Box, IconButton } from '@mui/material'; + +const Header: React.FC = () => { + const location = useLocation() + + return ( + + + + + + + Testnet Onboarding + + + + + + ); +}; + +export default Header; diff --git a/src/components/TermsAndConditionsCard.tsx b/src/components/TermsAndConditionsCard.tsx new file mode 100644 index 0000000..ec547e6 --- /dev/null +++ b/src/components/TermsAndConditionsCard.tsx @@ -0,0 +1,81 @@ +import React, { useState } from 'react'; + +import { Typography, Button, Box, Paper, Radio, RadioGroup, FormControlLabel, FormControl, FormLabel, Link, Checkbox } from '@mui/material'; +import { Role } from '@cerc-io/registry-sdk/dist/proto/cerc/onboarding/v1/onboarding'; + +import TermsAndConditionsDialog from './TermsAndConditionsDialog'; + +const VALIDATOR_OPTION = "validator"; +const PARTICIPANT_OPTION = "participant"; + +const TermsAndConditionsCard = ({ handleAccept, handleRoleChange }: { handleAccept: () => void, handleRoleChange: (role: Role) => void }) => { + const [selectedRole, setSelectedRole] = useState(PARTICIPANT_OPTION); + const [checked, setChecked] = useState(false); + const [isHidden, setIsHidden] = useState(false); + + const [isDialogOpen, setisDialogOpen] = useState(false) + + const handleCheckboxChange = (event: React.ChangeEvent) => { + setChecked(event.target.checked); + }; + + const handleContinue = () => { + handleAccept() + setIsHidden(true) + } + + const handleRadioChange = (event: React.ChangeEvent) => { + setSelectedRole((event.target as HTMLInputElement).value); + handleRoleChange((event.target as HTMLInputElement).value === VALIDATOR_OPTION ? Role.ROLE_VALIDATOR : Role.ROLE_PARTICIPANT); + }; + + return ( + + + Select your role + + } + label="Validator" + /> + } + label="Participant" + /> + + + + + + I accept the setisDialogOpen(true)} target="_blank" rel="noopener"> + terms and conditions + + + + + + + setisDialogOpen(false)}/> + + ); +}; + +export default TermsAndConditionsCard; diff --git a/src/components/TermsAndConditionsDialog.tsx b/src/components/TermsAndConditionsDialog.tsx new file mode 100644 index 0000000..a29bb63 --- /dev/null +++ b/src/components/TermsAndConditionsDialog.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button, Typography } from '@mui/material'; + +import { TNC_CONTENT } from '../constants'; + +interface TermsDialogProps { + isValidator: boolean; + open: boolean; + onClose: () => void; +} + +const TermsAndConditionsDialog: React.FC = ({ isValidator, open, onClose }) => { + return ( + + Terms and Conditions + + + Onboard as a {isValidator ? "validator" : "participant"} + + +
+ + + + + +
+ ); +}; + +export default TermsAndConditionsDialog; \ No newline at end of file diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..9910297 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,9 @@ +export const TNC_CONTENT = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`; diff --git a/src/layout/SignPageLayout.tsx b/src/layout/SignPageLayout.tsx index 3bb5e9e..c59f459 100644 --- a/src/layout/SignPageLayout.tsx +++ b/src/layout/SignPageLayout.tsx @@ -1,14 +1,12 @@ import React from "react"; -import { Outlet, useNavigate, Link } from "react-router-dom"; +import { Outlet, useNavigate } from "react-router-dom"; import { Toolbar, - IconButton, Avatar, Button, Typography, - Container, - Box, + Container } from "@mui/material"; import { useWalletConnectContext } from "../context/WalletConnectContext"; @@ -25,22 +23,6 @@ const SignPageLayout = () => { return ( <> - - - - - Testnet Onboarding - - - diff --git a/src/pages/OnboardingSuccess.tsx b/src/pages/OnboardingSuccess.tsx index 72b24e5..051a65b 100644 --- a/src/pages/OnboardingSuccess.tsx +++ b/src/pages/OnboardingSuccess.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { SnackbarProvider, enqueueSnackbar } from "notistack"; -import { useParams } from "react-router-dom"; +import { useLocation } from "react-router-dom"; import { Box, Typography } from "@mui/material"; import { Registry } from "@cerc-io/registry-sdk"; @@ -15,7 +15,9 @@ const registry = new Registry( ); const OnboardingSuccess = () => { - const { cosmosAddress } = useParams(); + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const cosmosAddress = queryParams.get('cosmosAddress'); const [participant, setParticipant] = useState(); diff --git a/src/pages/SignWithCosmos.tsx b/src/pages/SignWithCosmos.tsx index bb8f44b..b70941b 100644 --- a/src/pages/SignWithCosmos.tsx +++ b/src/pages/SignWithCosmos.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { useParams, useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { SnackbarProvider, enqueueSnackbar } from "notistack"; import { Box, Card, CardContent, Grid, Typography } from "@mui/material"; @@ -8,21 +8,28 @@ import { MsgOnboardParticipantEncodeObject, typeUrlMsgOnboardParticipant, } from "@cerc-io/registry-sdk"; +import { Role } from "@cerc-io/registry-sdk/dist/proto/cerc/onboarding/v1/onboarding"; import { StargateClient } from "@cosmjs/stargate"; import { useWalletConnectContext } from "../context/WalletConnectContext"; +import TermsAndConditionsCard from "../components/TermsAndConditionsCard"; const SignWithCosmos = () => { const { session, signClient } = useWalletConnectContext(); - const { cosmosAddress, ethSignature } = useParams(); + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const cosmosAddress = queryParams.get('cosmosAddress'); + const ethSignature = queryParams.get('ethSignature'); + const kycId = queryParams.get('kycId'); const [isLoading, setIsLoading] = useState(false); const [balance, setBalance] = useState(''); const [isRequesting, setIsRequesting] = useState(false); + const [isTncAccepted, setIsTncAccepted] = useState(false); + const [role, setRole] = useState(Role.ROLE_PARTICIPANT); const navigate = useNavigate(); - const location = useLocation(); const innerMessage = location.state; const ethAddress = innerMessage.address; @@ -35,12 +42,14 @@ const SignWithCosmos = () => { return { typeUrl: typeUrlMsgOnboardParticipant, value: { - participant: cosmosAddress, + participant: cosmosAddress!, ethPayload: innerMessage, - ethSignature, + ethSignature: ethSignature!, + kycId: kycId!, + role }, }; - }, [cosmosAddress, innerMessage, ethSignature]); + }, [cosmosAddress, innerMessage, ethSignature, kycId, role]); const handleTokenRequest = async () => { try { @@ -100,7 +109,7 @@ const SignWithCosmos = () => { if (responseFromWallet.code !== 0) { enqueueSnackbar("Transaction not sent", { variant: "error" }); } else { - navigate(`/onboarding-success/${cosmosAddress}`); + navigate(`/onboarding-success?cosmosAddress=${cosmosAddress}`); } } catch (error) { console.error(error); @@ -130,10 +139,12 @@ const SignWithCosmos = () => { sx={{ display: "flex", flexDirection: "column", - marginTop: "100px", + marginY: "100px", gap: "10px", }} > + Please accept terms and conditions to continue + setIsTncAccepted(true)} handleRoleChange={setRole}/> Send transaction to chain Cosmos Account: @@ -147,7 +158,7 @@ const SignWithCosmos = () => { Request tokens from Faucet @@ -178,7 +189,7 @@ const SignWithCosmos = () => { await sendTransaction(onboardParticipantMsg); }} loading={isLoading} - disabled={balance === '0'} + disabled={isTncAccepted ? (balance === '0') : !isTncAccepted} > Send transaction diff --git a/src/pages/SignWithNitroKey.tsx b/src/pages/SignWithNitroKey.tsx index 038fda2..cc97a26 100644 --- a/src/pages/SignWithNitroKey.tsx +++ b/src/pages/SignWithNitroKey.tsx @@ -1,5 +1,5 @@ import React, { useState, useMemo, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { SnackbarProvider, enqueueSnackbar } from "notistack"; import canonicalStringify from "canonical-json"; @@ -15,6 +15,10 @@ import { utf8ToHex } from "@walletconnect/encoding"; import { useWalletConnectContext } from "../context/WalletConnectContext"; const SignWithNitroKey = () => { + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const kycId = queryParams.get('kycId'); + const { session, signClient, checkPersistedState } = useWalletConnectContext(); @@ -55,7 +59,7 @@ const SignWithNitroKey = () => { }); setIsLoading(false) setEthSignature(ethSignature); - navigate(`/sign-with-cosmos/${cosmosAddress}/${receivedEthSig}`, { + navigate(`/sign-with-cosmos?cosmosAddress=${cosmosAddress}ðSignature=${receivedEthSig}&kycId=${kycId}`, { state: message, }); } catch (error) { @@ -129,7 +133,7 @@ const SignWithNitroKey = () => { style={{ marginTop: "20px" }} loading={isLoading} > - Sign using Nitro key + Sign using Nitro key diff --git a/src/pages/TermsAndConditions.tsx b/src/pages/TermsAndConditions.tsx new file mode 100644 index 0000000..3962d93 --- /dev/null +++ b/src/pages/TermsAndConditions.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { Container, Typography, Button, Box, Paper } from '@mui/material'; + +import { TNC_CONTENT } from '../constants'; + +const TermsAndConditions = () => { + const navigate = useNavigate(); + + const handleAccept = () => { + navigate('/user-verification'); + }; + + return ( + + + + Terms and Conditions + + + +
+ + + + + + + + + ); +}; + +export default TermsAndConditions; diff --git a/src/pages/UserVerification.tsx b/src/pages/UserVerification.tsx index 6e8a015..f0710c6 100644 --- a/src/pages/UserVerification.tsx +++ b/src/pages/UserVerification.tsx @@ -15,16 +15,16 @@ const options = { } const UserVerification = () => { - const [userId, setUserId] = useState(''); + const [kycId, setKycId] = useState(''); const [applicationSubmitted, setApplicationSubmitted] = useState(false); const navigate = useNavigate(); useEffect(()=>{ - if (applicationSubmitted && userId !== '') { - navigate(`/sign-with-nitro-key/${userId}`) + if (applicationSubmitted && kycId !== '') { + navigate(`/connect-wallet?kycId=${kycId}`) } - }, [applicationSubmitted, userId, navigate]); + }, [applicationSubmitted, kycId, navigate]); // TODO: Implement const accessTokenExpirationHandler = async () => { @@ -41,7 +41,7 @@ const UserVerification = () => { const messageHandler = (event: any, payload: any ) => { if (event === 'idCheck.onApplicantLoaded') { - setUserId(payload.applicantId); + setKycId(payload.applicantId); } if (event === 'idCheck.onApplicantSubmitted'){