From 2a24985930c3033ea554c555842c4647e1f96ed4 Mon Sep 17 00:00:00 2001 From: nabarun Date: Tue, 30 Jul 2024 08:22:09 +0000 Subject: [PATCH] Integrate sumsub KYC with terms & conditions (#6) Part of [Sumsub KYC integration in onboarding app](https://www.notion.so/Sumsub-KYC-integration-in-onboarding-app-607b598c9c1d4d12adc71725e2ab5e7e) Reviewed-on: https://git.vdb.to/cerc-io/testnet-onboarding-app/pulls/6 --- .env.example | 1 + package.json | 18 +-- src/App.tsx | 15 ++- src/components/Header.tsx | 33 ++++++ src/components/TermsAndConditionsCard.tsx | 83 ++++++++++++++ src/components/TermsAndConditionsDialog.tsx | 34 ++++++ src/constants.ts | 29 +++++ src/layout/SignPageLayout.tsx | 22 +--- src/pages/ConnectWallet.tsx | 26 +---- src/pages/OnboardingSuccess.tsx | 21 ++-- src/pages/SignWithCosmos.tsx | 45 +++++--- src/pages/SignWithNitroKey.tsx | 14 ++- src/pages/TermsAndConditions.tsx | 48 ++++++++ src/pages/UserVerification.tsx | 116 ++++++++++++++++++++ src/utils/sumsub.ts | 16 +++ yarn.lock | 20 +++- 16 files changed, 459 insertions(+), 82 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 create mode 100644 src/pages/UserVerification.tsx create mode 100644 src/utils/sumsub.ts diff --git a/.env.example b/.env.example index 2c5252b..0557672 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,4 @@ REACT_APP_LACONICD_RPC_ENDPOINT=http://localhost:26657 REACT_APP_LACONICD_DENOM=photon REACT_APP_FAUCET_ENDPOINT=http://localhost:4000 REACT_APP_WALLET_META_URL=http://localhost:3000 +REACT_APP_SUMSUB_API_ENDPOINT= diff --git a/package.json b/package.json index fbee887..2354ac0 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,15 @@ "version": "0.1.0", "private": true, "dependencies": { - "@cerc-io/registry-sdk": "^0.2.2", + "@cerc-io/registry-sdk": "^0.2.4", "@cosmjs/stargate": "^0.32.4", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.15.14", "@mui/lab": "^5.0.0-alpha.169", "@mui/material": "^5.15.14", + "@sumsub/websdk": "^2.3.1", + "@sumsub/websdk-react": "^2.3.1", "@walletconnect/encoding": "^1.0.2", "@walletconnect/modal": "^2.6.2", "@walletconnect/sign-client": "^2.11.3", @@ -51,8 +53,9 @@ ] }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -60,11 +63,8 @@ "@types/node": "^16.18.90", "@types/react": "^18.2.67", "@types/react-dom": "^18.2.22", - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "eslint-plugin-react": "^7.33.2", - "husky": "^9.0.11", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", "babel-jest": "^27.4.2", "babel-loader": "^8.2.3", "babel-plugin-named-asset-import": "^0.3.8", @@ -78,10 +78,12 @@ "dotenv-expand": "^5.1.0", "eslint": "^8.3.0", "eslint-config-react-app": "^7.0.1", + "eslint-plugin-react": "^7.33.2", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.0", "html-webpack-plugin": "^5.5.0", + "husky": "^9.0.11", "identity-obj-proxy": "^3.0.0", "jest": "^27.4.3", "jest-resolve": "^27.4.2", diff --git a/src/App.tsx b/src/App.tsx index 50c6eac..596a474 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,22 +7,31 @@ import SignWithCosmos from "./pages/SignWithCosmos"; import PageNotFound from "./pages/PageNotFound"; import OnboardingSuccess from "./pages/OnboardingSuccess"; 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..413390d --- /dev/null +++ b/src/components/TermsAndConditionsCard.tsx @@ -0,0 +1,83 @@ +import React, { useState } from 'react'; + +import { Typography, Button, Box, Paper, Radio, RadioGroup, FormControlLabel, FormControl, FormLabel, Link, Checkbox } from '@mui/material'; + +import TermsAndConditionsDialog from './TermsAndConditionsDialog'; + +export enum Role { + Validator = 'validator', + Participant = 'participant' +} + +const TermsAndConditionsCard = ({ handleAccept, handleRoleChange }: { handleAccept: () => void, handleRoleChange: (role: Role) => void }) => { + const [selectedRole, setSelectedRole] = useState(Role.Participant); + 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.value as Role); + handleRoleChange((event.target as HTMLInputElement).value === Role.Validator ? Role.Validator : Role.Participant); + setChecked(false); + }; + + 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..4ad3c6f --- /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_PARTICIPANT_CONTENT, TNC_VALIDATOR_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..99003b8 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,29 @@ +export const TNC_GENERIC_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.`; + +export const TNC_VALIDATOR_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.`; + +export const TNC_PARTICIPANT_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..2a839f8 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"; @@ -8,6 +8,8 @@ import { Registry } from "@cerc-io/registry-sdk"; interface Participant { cosmosAddress: string; nitroAddress: string; + role: string; + kycId: string; } const registry = new Registry( @@ -15,18 +17,21 @@ const registry = new Registry( ); const OnboardingSuccess = () => { - const { cosmosAddress } = useParams(); + const location = useLocation(); + const { cosmosAddress } = location.state as { + cosmosAddress?: string + } const [participant, setParticipant] = useState(); useEffect(() => { const fetchParticipants = async () => { try { - const allParticipants: Participant[] = await registry.getParticipants(); - const participant = allParticipants.find( - (participant) => participant.cosmosAddress === cosmosAddress - ); - + if (!cosmosAddress) { + enqueueSnackbar("Cosmos address is not provided", { variant: "error" }); + return; + } + const participant: Participant = await registry.getParticipantByAddress(cosmosAddress); if (!participant) { enqueueSnackbar("Participant not found", { variant: "error" }); return; @@ -66,6 +71,8 @@ const OnboardingSuccess = () => {
Cosmos Address: {participant.cosmosAddress}
Nitro Address: {participant.nitroAddress}
+ Role: {participant.role}
+ KYC ID: {participant.kycId}

)} diff --git a/src/pages/SignWithCosmos.tsx b/src/pages/SignWithCosmos.tsx index bb8f44b..1107b0e 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"; @@ -11,20 +11,31 @@ import { import { StargateClient } from "@cosmjs/stargate"; import { useWalletConnectContext } from "../context/WalletConnectContext"; +import TermsAndConditionsCard, {Role} from "../components/TermsAndConditionsCard"; const SignWithCosmos = () => { const { session, signClient } = useWalletConnectContext(); - const { cosmosAddress, ethSignature } = useParams(); - + const location = useLocation(); const [isLoading, setIsLoading] = useState(false); const [balance, setBalance] = useState(''); const [isRequesting, setIsRequesting] = useState(false); + const [isTncAccepted, setIsTncAccepted] = useState(false); + const [role, setRole] = useState(Role.Participant); const navigate = useNavigate(); - const location = useLocation(); - const innerMessage = location.state; - const ethAddress = innerMessage.address; + + const {message: innerMessage, cosmosAddress, receivedEthSig: ethSignature, kycId} = location.state as { + message?: { + msg: string; + address: string; + }; + cosmosAddress?: string; + receivedEthSig?: string; + kycId?: string; + }; + + const ethAddress = innerMessage!.address; const createCosmosClient = useCallback(async (endpoint: string) => { return await StargateClient.connect(endpoint); @@ -35,12 +46,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 +113,11 @@ const SignWithCosmos = () => { if (responseFromWallet.code !== 0) { enqueueSnackbar("Transaction not sent", { variant: "error" }); } else { - navigate(`/onboarding-success/${cosmosAddress}`); + navigate("/onboarding-success", { + state: { + cosmosAddress + } + }); } } catch (error) { console.error(error); @@ -130,10 +147,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 +166,7 @@ const SignWithCosmos = () => { Request tokens from Faucet @@ -178,7 +197,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..d754c6a 100644 --- a/src/pages/SignWithNitroKey.tsx +++ b/src/pages/SignWithNitroKey.tsx @@ -15,6 +15,7 @@ import { utf8ToHex } from "@walletconnect/encoding"; import { useWalletConnectContext } from "../context/WalletConnectContext"; const SignWithNitroKey = () => { + const { session, signClient, checkPersistedState } = useWalletConnectContext(); @@ -34,7 +35,7 @@ const SignWithNitroKey = () => { const message = useMemo(() => { return { - msg: "Register my account as a validator on the Laconic network", + msg: "Register my account as a participant on the Laconic network", address: ethAddress, }; }, [ethAddress]); @@ -55,8 +56,12 @@ const SignWithNitroKey = () => { }); setIsLoading(false) setEthSignature(ethSignature); - navigate(`/sign-with-cosmos/${cosmosAddress}/${receivedEthSig}`, { - state: message, + navigate("/user-verification", { + state: { + message, + cosmosAddress, + receivedEthSig, + }, }); } catch (error) { console.log("err in signing ", error); @@ -66,7 +71,6 @@ const SignWithNitroKey = () => { } }; - return (
{session ? ( @@ -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..b84bfe9 --- /dev/null +++ b/src/pages/TermsAndConditions.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { Container, Typography, Button, Box, Paper } from '@mui/material'; + +import { TNC_GENERIC_CONTENT } from '../constants'; + +const TermsAndConditions = () => { + const navigate = useNavigate(); + + const handleAccept = () => { + navigate('/connect-wallet'); + }; + + return ( + + + + Terms and Conditions + + + +
+ + + + + + + + + ); +}; + +export default TermsAndConditions; diff --git a/src/pages/UserVerification.tsx b/src/pages/UserVerification.tsx new file mode 100644 index 0000000..3efa720 --- /dev/null +++ b/src/pages/UserVerification.tsx @@ -0,0 +1,116 @@ +import React, { useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; + +import { Box, Typography } from '@mui/material'; +import SumsubWebSdk from '@sumsub/websdk-react'; +import { MessageHandler } from '@sumsub/websdk'; +import { EventPayload } from '@sumsub/websdk/types/types'; + +import { fetchAccessToken } from '../utils/sumsub'; + +const config = { + lang: "en", // language of WebSDK texts and comments (ISO 639-1 format) + theme: "light", +}; + +const options = { + addViewportTag: false, + adaptIframeHeight: true, +}; + +const UserVerification = () => { + const [kycId, setKycId] = useState('unknown'); + const [applicationSubmitted, setApplicationSubmitted] = useState(false); + const [token, setToken] = useState(''); + const [loading, setLoading] = useState(true); + + const location = useLocation(); + const navigate = useNavigate(); + + const {message, cosmosAddress, receivedEthSig} = location.state as { + message?: string; + cosmosAddress?: string; + receivedEthSig?: string; + }; + + const userId = cosmosAddress; + + useEffect(() => { + const getToken = async (userId: string) => { + console.log(userId); + const newToken = await fetchAccessToken(userId); + + setToken(newToken); + setLoading(false); + }; + + if (userId) { + getToken(userId).catch(error => { + console.error(error); + alert("Failed to fetch token"); + }); + } + }, [userId]); + + useEffect(() => { + if (applicationSubmitted && kycId !== '') { + navigate("/sign-with-cosmos", { + state: { + message, + cosmosAddress, + receivedEthSig, + kycId, + }}) + } + }, [applicationSubmitted, kycId, navigate, cosmosAddress, message, receivedEthSig]); + + const accessTokenExpirationHandler = async () => { + alert("Please renew token"); + return "Token expired"; + }; + + const messageHandler: MessageHandler = (event, payload) => { + console.log('sumsubEvent:', event); + + if (event === 'idCheck.onApplicantLoaded') { + setKycId((payload as EventPayload<'idCheck.onApplicantLoaded'>).applicantId); + } + + if (event === 'idCheck.onApplicantSubmitted') { + setApplicationSubmitted(true); + } + + if (event === 'idCheck.onApplicantStatusChanged') { + if ((payload as EventPayload<'idCheck.onApplicantStatusChanged'>).reviewStatus === 'pending') { + setApplicationSubmitted(true); + } + } + }; + + return ( + <> + + User verification +
+
+ {!loading && token && ( + + )} + + ); +}; + +export default UserVerification; diff --git a/src/utils/sumsub.ts b/src/utils/sumsub.ts new file mode 100644 index 0000000..62a48c2 --- /dev/null +++ b/src/utils/sumsub.ts @@ -0,0 +1,16 @@ +export const fetchAccessToken = async (userId: string): Promise => { + const response = await fetch(`${process.env.REACT_APP_SUMSUB_API_ENDPOINT}/generate-token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ userId }) + }); + + if (!response.ok) { + throw new Error('Network response was not ok'); + } + + const data = await response.json(); + return data.token; +}; diff --git a/yarn.lock b/yarn.lock index ba8809e..f77e06e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1183,10 +1183,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cerc-io/registry-sdk@^0.2.2": - version "0.2.2" - resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fregistry-sdk/-/0.2.2/registry-sdk-0.2.2.tgz#2e8a533f069b4bb9f4cd4798e783f52e29167d0d" - integrity sha512-ocRMbWtdewOg02ORfK1U+qbTqB46anHP4ApXokGkY4d+mFSApR3sdUEi2geHcs8oh+SG8YAp7LUJ9AAJneNY8g== +"@cerc-io/registry-sdk@^0.2.4": + version "0.2.4" + resolved "https://git.vdb.to/api/packages/cerc-io/npm/%40cerc-io%2Fregistry-sdk/-/0.2.4/registry-sdk-0.2.4.tgz#60e4e75b1e6a957cf2b97490af4fda4af07b105f" + integrity sha512-hRZJP+s+uBvfrqtmQ38pmf74SyfFDC65AVwvWigJGxc6uKJG4jyuMyhsoD1P4XkjwAQSnFO89TuDC5JGkdXyrA== dependencies: "@cosmjs/amino" "^0.28.1" "@cosmjs/crypto" "^0.28.1" @@ -3015,6 +3015,16 @@ "@stablelib/random" "^1.0.2" "@stablelib/wipe" "^1.0.1" +"@sumsub/websdk-react@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@sumsub/websdk-react/-/websdk-react-2.3.1.tgz#43345cbe8bfe08f38da172b8a8d282dcbca9cb17" + integrity sha512-v6ZKsz3DRBNRzB36hx4pPGlMJH7Biwso3YWVtApgb0pJlhWkONUnuokhd58qnA4qwAPQAamI5JOkjFL8qsFhmw== + +"@sumsub/websdk@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@sumsub/websdk/-/websdk-2.3.1.tgz#20177e08dee8b15527c8a10722fa72d713e94b7f" + integrity sha512-pIxjLZybN+7eqVC7Hpl24Jf2Vk0ahsRuCO+wuNA8h4dna9AdnyjOxpxS4Akw7knNi8AHs4fQFHaDa9WfUPgTBQ== + "@surma/rollup-plugin-off-main-thread@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" @@ -12199,8 +12209,6 @@ tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== - dependencies: - punycode "^2.1.0" tr46@^2.1.0: version "2.1.0"