From 8db10ea8c8c4253f5b498f9834d1c4e3dcd59f28 Mon Sep 17 00:00:00 2001 From: Sergey Kambalin Date: Wed, 31 Jul 2024 20:23:58 +0600 Subject: [PATCH] feature: OTP email configuration (#209) --- .env.dev | 1 + .env.prod | 3 ++- .env.prod-legacy | 5 +++++ .env.simulation-cyan | 1 + .env.simulation-mainnet | 1 + .env.simulation-testnet | 1 + .env.stage | 1 + .env.test | 1 + CHANGELOG.md | 2 +- packages/embed-wallet/src/types.ts | 1 + src/api/auth-api.service.ts | 17 ++++++++++++++--- src/components/Login/OtpPage.tsx | 18 ++++++++++++++---- src/constants.ts | 1 + src/routes/Authorize/Authorize.tsx | 2 +- src/stores/AppContextStore/AppContextStore.tsx | 11 ++++++++++- .../AuthorizePopupStore/AuthorizePopupStore.ts | 10 +++++++--- 16 files changed, 62 insertions(+), 14 deletions(-) diff --git a/.env.dev b/.env.dev index ff0ad1ff..aa0e9364 100644 --- a/.env.dev +++ b/.env.dev @@ -43,3 +43,4 @@ REACT_APP_RAMP_API_KEY=e5vj99sfvuxcyt99y6u9bahbcxex4feo4y6eaqjx # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true diff --git a/.env.prod b/.env.prod index 836b6162..3e02ea18 100644 --- a/.env.prod +++ b/.env.prod @@ -42,4 +42,5 @@ REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sen # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true -REACT_APP_ASSETS_MANAGEMENT_FEATURE=true \ No newline at end of file +REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true \ No newline at end of file diff --git a/.env.prod-legacy b/.env.prod-legacy index 3c79a81d..24ffcbb5 100644 --- a/.env.prod-legacy +++ b/.env.prod-legacy @@ -39,3 +39,8 @@ REACT_APP_GMT_ID=GTM-WQ33L7GG # Reporting REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sentry.io/4505266227052544 + +# Feature flags +REACT_APP_TRANSFER_ASSETS_FEATURE=true +REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true \ No newline at end of file diff --git a/.env.simulation-cyan b/.env.simulation-cyan index 9fbfc096..de0272e3 100644 --- a/.env.simulation-cyan +++ b/.env.simulation-cyan @@ -46,3 +46,4 @@ REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sen # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true diff --git a/.env.simulation-mainnet b/.env.simulation-mainnet index 967398d3..19ae9175 100644 --- a/.env.simulation-mainnet +++ b/.env.simulation-mainnet @@ -46,3 +46,4 @@ REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sen # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true diff --git a/.env.simulation-testnet b/.env.simulation-testnet index ec98058b..865ae99d 100644 --- a/.env.simulation-testnet +++ b/.env.simulation-testnet @@ -46,3 +46,4 @@ REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sen # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true diff --git a/.env.stage b/.env.stage index e0d33c86..45516296 100644 --- a/.env.stage +++ b/.env.stage @@ -43,3 +43,4 @@ REACT_APP_SENTRY_DNS=https://9d65aed043f04fd4bc14406a85c2a76d@o318183.ingest.sen # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=false diff --git a/.env.test b/.env.test index 2ecc5ef7..12127cd2 100644 --- a/.env.test +++ b/.env.test @@ -43,3 +43,4 @@ REACT_APP_GMT_ID=GTM-WQ33L7GG # Feature flags REACT_APP_TRANSFER_ASSETS_FEATURE=true REACT_APP_ASSETS_MANAGEMENT_FEATURE=true +REACT_APP_ENABLE_OTP_LINK=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 02a16c2c..9cb72119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### vNext -- +- Send OTP email with context specific values ### v1.40.0 diff --git a/packages/embed-wallet/src/types.ts b/packages/embed-wallet/src/types.ts index 96b7d1f6..b5c0f187 100644 --- a/packages/embed-wallet/src/types.ts +++ b/packages/embed-wallet/src/types.ts @@ -22,6 +22,7 @@ export type ContextApp = { appId?: string; name?: string; logoUrl?: string; + supportEmail?: string; }; export type ContextWhiteLabel = Record; // TODO: Use proper white label types diff --git a/src/api/auth-api.service.ts b/src/api/auth-api.service.ts index 94d12398..f2dbc909 100644 --- a/src/api/auth-api.service.ts +++ b/src/api/auth-api.service.ts @@ -1,7 +1,7 @@ import axios, { AxiosError, AxiosResponse } from 'axios'; import { reportError } from '~/reporting'; -import { WALLET_API } from '~/constants'; +import { FEATURE_FLAGS, WALLET_API } from '~/constants'; import { ApiResponse } from '~/api/interfaces'; export type TokenData = { @@ -12,16 +12,27 @@ export type TokenByLinkData = TokenData & { code: string; }; +export type SendOtpOptions = { + appTitle?: string; + supportEmail?: string; + authLink?: boolean; + popupId?: string; +}; + const api = axios.create({ baseURL: WALLET_API, }); export class AuthApiService { - public static async sendOtp(email: string): Promise { + public static async sendOtp(email: string, options: SendOtpOptions = {}): Promise { let result: AxiosResponse> | null = null; try { - result = await api.post('/auth/otp/send', { email }); + result = await api.post('/auth/otp/send', { + ...options, + email, + authLink: options.authLink ?? FEATURE_FLAGS.otpLink, + }); } catch (err: any) { reportError(err); } diff --git a/src/components/Login/OtpPage.tsx b/src/components/Login/OtpPage.tsx index 61bd4fdd..2cc99db0 100644 --- a/src/components/Login/OtpPage.tsx +++ b/src/components/Login/OtpPage.tsx @@ -41,11 +41,12 @@ export const OtpPage = ({ email, onRequestLogin, busy = false, code }: OtpProps) const location = useLocation(); const navigate = useNavigate(); const [spamNotice, setSpamNotice] = useState(false); + const [otpAccepted, setOtpAccepted] = useState(false); const [timeLeft, setTimeLeft] = useState(TIME_LEFT); const { isGame } = useTheme(); - const store = useAppContextStore(); + const appStore = useAppContextStore(); - const verifyScreenSettings = store?.whiteLabel?.verifyScreenSettings; + const verifyScreenSettings = appStore?.whiteLabel?.verifyScreenSettings; const { control, @@ -76,6 +77,8 @@ export const OtpPage = ({ email, onRequestLogin, busy = false, code }: OtpProps) return setError('code', { message: 'The code is wrong, please try again' }); } + setOtpAccepted(true); + try { await onRequestLogin(token); } catch (error) { @@ -89,7 +92,14 @@ export const OtpPage = ({ email, onRequestLogin, busy = false, code }: OtpProps) const handleResend = async () => { setTimeLeft(TIME_LEFT); - await AuthApiService.sendOtp(email!); + + /** + * TODO: Use AuthorizePopupStore method to send OTP + */ + await AuthApiService.sendOtp(email!, { + appTitle: appStore.app?.name, + supportEmail: appStore.app?.supportEmail, + }); }; useEffect(() => { @@ -203,7 +213,7 @@ export const OtpPage = ({ email, onRequestLogin, busy = false, code }: OtpProps) )} - {spamNotice && ( + {spamNotice && !otpAccepted && ( If you didn’t get the verification email please check your Spam folder. diff --git a/src/constants.ts b/src/constants.ts index 9e429397..59ef2d4d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -27,6 +27,7 @@ export const ANALYTICS = { export const FEATURE_FLAGS = { transferAssets: process.env.REACT_APP_TRANSFER_ASSETS_FEATURE === 'true', assetsManagement: process.env.REACT_APP_ASSETS_MANAGEMENT_FEATURE === 'true', + otpLink: process.env.REACT_APP_ENABLE_OTP_LINK === 'true', }; /** diff --git a/src/routes/Authorize/Authorize.tsx b/src/routes/Authorize/Authorize.tsx index f4c5c9af..ec634f76 100644 --- a/src/routes/Authorize/Authorize.tsx +++ b/src/routes/Authorize/Authorize.tsx @@ -24,7 +24,7 @@ const Authorize = () => { sessionNamespace, loginHint, email, - appId: wallet.appContextStore.app?.appId, + app: wallet.appContextStore.app, }), [wallet], ); diff --git a/src/stores/AppContextStore/AppContextStore.tsx b/src/stores/AppContextStore/AppContextStore.tsx index 9f69c193..c6d44d00 100644 --- a/src/stores/AppContextStore/AppContextStore.tsx +++ b/src/stores/AppContextStore/AppContextStore.tsx @@ -71,7 +71,16 @@ export class AppContextStore { const name = this.context.app.name || new URL(this.context.app.url).hostname; - return { ...this.context.app, name }; + let supportEmail = this.context.app.supportEmail; + + /** + * TODO: Remove this condition after Developer Console provide email via SDK + */ + if (!supportEmail && this.context.app.appId === 'developer-console') { + supportEmail = 'team@cere.network'; + } + + return { ...this.context.app, name, supportEmail }; } async disconnect() { diff --git a/src/stores/AuthorizePopupStore/AuthorizePopupStore.ts b/src/stores/AuthorizePopupStore/AuthorizePopupStore.ts index 0060919c..eddd9cd5 100644 --- a/src/stores/AuthorizePopupStore/AuthorizePopupStore.ts +++ b/src/stores/AuthorizePopupStore/AuthorizePopupStore.ts @@ -6,6 +6,7 @@ import { reportError } from '~/reporting'; import { OpenLoginStore } from '../OpenLoginStore'; import { SessionStore } from '../SessionStore'; import { Web3AuthStore } from '../Web3AuthStore'; +import { type App } from '../AppContextStore'; import { createSharedPopupState } from '../sharedState'; import { createRedirectUrl } from './createRedirectUrl'; import { Wallet } from '../types'; @@ -23,7 +24,7 @@ export type AuthorizePopupStoreOptions = { redirectUrl?: string; forceMfa?: boolean; sessionNamespace?: string; - appId?: string; + app?: App; loginHint?: string; email?: string; }; @@ -130,7 +131,7 @@ export class AuthorizePopupStore { const { userInfo, permissions } = await this.web3AuthStore.login({ idToken, - appId: this.options.appId, + appId: this.options.app?.appId, checkMfa: isMfa === undefined, }); @@ -190,7 +191,10 @@ export class AuthorizePopupStore { throw new Error('Email is required to send OTP'); } - const authLinkCode = await AuthApiService.sendOtp(toEmail); + const authLinkCode = await AuthApiService.sendOtp(toEmail, { + appTitle: this.options.app?.name, + supportEmail: this.options.app?.supportEmail, + }); if (authLinkCode) { this.authLinkResource?.dispose();