mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
fix linking email and wallet to existing account
This commit is contained in:
@@ -226,18 +226,21 @@ export const RESOURCES = {
|
||||
auth_send_otp: {
|
||||
path: '/api/account/v2/send_otp',
|
||||
},
|
||||
|
||||
auth_confirm_otp: {
|
||||
path: '/api/account/v2/confirm_otp',
|
||||
},
|
||||
|
||||
auth_siwe_message: {
|
||||
path: '/api/account/v2/siwe_message',
|
||||
},
|
||||
|
||||
auth_siwe_verify: {
|
||||
path: '/api/account/v2/authenticate_via_wallet',
|
||||
},
|
||||
auth_link_email: {
|
||||
path: '/api/account/v2/email/link',
|
||||
},
|
||||
auth_link_address: {
|
||||
path: '/api/account/v2/address/link',
|
||||
},
|
||||
|
||||
// STATS MICROSERVICE API
|
||||
stats_counters: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';
|
||||
@@ -6,6 +7,7 @@ import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';
|
||||
import type { Screen, ScreenSuccess } from './types';
|
||||
|
||||
import config from 'configs/app';
|
||||
import { getResourceKey } from 'lib/api/useApiQuery';
|
||||
import useGetCsrfToken from 'lib/hooks/useGetCsrfToken';
|
||||
import * as mixpanel from 'lib/mixpanel';
|
||||
import IconSvg from 'ui/shared/IconSvg';
|
||||
@@ -16,7 +18,6 @@ import AuthModalScreenOtpCode from './screens/AuthModalScreenOtpCode';
|
||||
import AuthModalScreenSelectMethod from './screens/AuthModalScreenSelectMethod';
|
||||
import AuthModalScreenSuccessEmail from './screens/AuthModalScreenSuccessEmail';
|
||||
import AuthModalScreenSuccessWallet from './screens/AuthModalScreenSuccessWallet';
|
||||
import useProfileQuery from './useProfileQuery';
|
||||
|
||||
const feature = config.features.account;
|
||||
|
||||
@@ -38,8 +39,8 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig }: Props) => {
|
||||
const [ isSuccess, setIsSuccess ] = React.useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const profileQuery = useProfileQuery();
|
||||
const csrfQuery = useGetCsrfToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
React.useEffect(() => {
|
||||
if ('isAuth' in initialScreen && initialScreen.isAuth) {
|
||||
@@ -84,13 +85,10 @@ const AuthModal = ({ initialScreen, onClose, mixpanelConfig }: Props) => {
|
||||
});
|
||||
}
|
||||
|
||||
const { data } = await profileQuery.refetch();
|
||||
queryClient.setQueryData(getResourceKey('user_info'), () => screen.profile);
|
||||
await csrfQuery.refetch();
|
||||
if (data) {
|
||||
onNextStep({ ...screen, profile: data });
|
||||
}
|
||||
// TODO @tom2drum handle error case
|
||||
}, [ initialScreen, mixpanelConfig?.account_link_info.source, onNextStep, profileQuery, csrfQuery ]);
|
||||
onNextStep(screen);
|
||||
}, [ initialScreen, mixpanelConfig?.account_link_info.source, onNextStep, csrfQuery, queryClient ]);
|
||||
|
||||
const onModalClose = React.useCallback(() => {
|
||||
onClose(isSuccess);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Center, Spinner } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
import type { ScreenSuccess } from '../types';
|
||||
import type { UserInfo } from 'types/api/account';
|
||||
|
||||
import type * as mixpanel from 'lib/mixpanel';
|
||||
|
||||
@@ -17,15 +18,15 @@ interface Props {
|
||||
const AuthModalScreenConnectWallet = ({ onSuccess, onError, isAuth, source }: Props) => {
|
||||
const isStartedRef = React.useRef(false);
|
||||
|
||||
const handleSignInSuccess = React.useCallback(({ address }: { address: string }) => {
|
||||
onSuccess({ type: 'success_wallet', address, isAuth });
|
||||
const handleSignInSuccess = React.useCallback(({ address, profile }: { address: string; profile: UserInfo }) => {
|
||||
onSuccess({ type: 'success_wallet', address, isAuth, profile });
|
||||
}, [ onSuccess, isAuth ]);
|
||||
|
||||
const handleSignInError = React.useCallback(() => {
|
||||
onError(isAuth);
|
||||
}, [ onError, isAuth ]);
|
||||
|
||||
const { start } = useSignInWithWallet({ onSuccess: handleSignInSuccess, onError: handleSignInError, source });
|
||||
const { start } = useSignInWithWallet({ onSuccess: handleSignInSuccess, onError: handleSignInError, source, isAuth });
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isStartedRef.current) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { EmailFormFields, Screen } from '../types';
|
||||
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import getErrorMessage from 'lib/errors/getErrorMessage';
|
||||
import getErrorObjPayload from 'lib/errors/getErrorObjPayload';
|
||||
import useToast from 'lib/hooks/useToast';
|
||||
import * as mixpanel from 'lib/mixpanel';
|
||||
|
||||
@@ -65,7 +66,7 @@ const AuthModalScreenEmail = ({ onSubmit, isAuth, mixpanelConfig }: Props) => {
|
||||
toast({
|
||||
status: 'error',
|
||||
title: 'Error',
|
||||
description: getErrorMessage(error) || 'Something went wrong',
|
||||
description: getErrorObjPayload<{ message: string }>(error)?.message || getErrorMessage(error) || 'Something went wrong',
|
||||
});
|
||||
}
|
||||
}, [ executeRecaptcha, apiFetch, isAuth, onSubmit, mixpanelConfig?.account_link_info.source, toast ]);
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { SubmitHandler } from 'react-hook-form';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
import type { OtpCodeFormFields, ScreenSuccess } from '../types';
|
||||
import type { UserInfo } from 'types/api/account';
|
||||
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import getErrorMessage from 'lib/errors/getErrorMessage';
|
||||
@@ -35,7 +36,8 @@ const AuthModalScreenOtpCode = ({ email, onSuccess, isAuth }: Props) => {
|
||||
});
|
||||
|
||||
const onFormSubmit: SubmitHandler<OtpCodeFormFields> = React.useCallback((formData) => {
|
||||
return apiFetch('auth_confirm_otp', {
|
||||
const resource = isAuth ? 'auth_link_email' : 'auth_confirm_otp';
|
||||
return apiFetch<typeof resource, UserInfo, unknown>(resource, {
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
body: {
|
||||
@@ -44,8 +46,11 @@ const AuthModalScreenOtpCode = ({ email, onSuccess, isAuth }: Props) => {
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
onSuccess({ type: 'success_email', email, isAuth });
|
||||
.then((response) => {
|
||||
if (!('name' in response)) {
|
||||
throw Error('Something went wrong');
|
||||
}
|
||||
onSuccess({ type: 'success_email', email, isAuth, profile: response });
|
||||
})
|
||||
.catch((error) => {
|
||||
const apiError = getErrorObjPayload<{ message: string }>(error);
|
||||
|
||||
@@ -3,12 +3,12 @@ import type { UserInfo } from 'types/api/account';
|
||||
export type ScreenSuccess = {
|
||||
type: 'success_email';
|
||||
email: string;
|
||||
profile?: UserInfo;
|
||||
profile: UserInfo;
|
||||
isAuth?: boolean;
|
||||
} | {
|
||||
type: 'success_wallet';
|
||||
address: string;
|
||||
profile?: UserInfo;
|
||||
profile: UserInfo;
|
||||
isAuth?: boolean;
|
||||
}
|
||||
export type Screen = {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useWeb3Modal } from '@web3modal/wagmi/react';
|
||||
import React from 'react';
|
||||
import { useSignMessage } from 'wagmi';
|
||||
|
||||
import type { UserInfo } from 'types/api/account';
|
||||
|
||||
import config from 'configs/app';
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import getErrorMessage from 'lib/errors/getErrorMessage';
|
||||
@@ -11,12 +13,13 @@ import * as mixpanel from 'lib/mixpanel';
|
||||
import useAccount from 'lib/web3/useAccount';
|
||||
|
||||
interface Props {
|
||||
onSuccess?: ({ address }: { address: string }) => void;
|
||||
onSuccess?: ({ address, profile }: { address: string; profile: UserInfo }) => void;
|
||||
onError?: () => void;
|
||||
source?: mixpanel.EventPayload<mixpanel.EventTypes.WALLET_CONNECT>['Source'];
|
||||
isAuth?: boolean;
|
||||
}
|
||||
|
||||
function useSignInWithWallet({ onSuccess, onError, source = 'Login' }: Props) {
|
||||
function useSignInWithWallet({ onSuccess, onError, source = 'Login', isAuth }: Props) {
|
||||
const [ isPending, setIsPending ] = React.useState(false);
|
||||
const isConnectingWalletRef = React.useRef(false);
|
||||
|
||||
@@ -30,13 +33,17 @@ function useSignInWithWallet({ onSuccess, onError, source = 'Login' }: Props) {
|
||||
try {
|
||||
const siweMessage = await apiFetch('auth_siwe_message', { queryParams: { address } }) as { siwe_message: string };
|
||||
const signature = await signMessageAsync({ message: siweMessage.siwe_message });
|
||||
await apiFetch('auth_siwe_verify', {
|
||||
const resource = isAuth ? 'auth_link_address' : 'auth_siwe_verify';
|
||||
const response = await apiFetch<typeof resource, UserInfo, unknown>(resource, {
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
body: { message: siweMessage.siwe_message, signature },
|
||||
},
|
||||
});
|
||||
onSuccess?.({ address });
|
||||
if (!('name' in response)) {
|
||||
throw Error('Something went wrong');
|
||||
}
|
||||
onSuccess?.({ address, profile: response });
|
||||
} catch (error) {
|
||||
const errorObj = getErrorObj(error);
|
||||
const shortMessage = errorObj && 'shortMessage' in errorObj && typeof errorObj.shortMessage === 'string' ? errorObj.shortMessage : undefined;
|
||||
@@ -49,7 +56,7 @@ function useSignInWithWallet({ onSuccess, onError, source = 'Login' }: Props) {
|
||||
} finally {
|
||||
setIsPending(false);
|
||||
}
|
||||
}, [ apiFetch, onError, onSuccess, signMessageAsync, toast ]);
|
||||
}, [ apiFetch, isAuth, onError, onSuccess, signMessageAsync, toast ]);
|
||||
|
||||
const start = React.useCallback(() => {
|
||||
setIsPending(true);
|
||||
|
||||
@@ -52,6 +52,7 @@ const UserProfileContentWallet = ({ onClose, className }: Props) => {
|
||||
onClick={ handleOpenWalletClick }
|
||||
isLoading={ web3Wallet.isOpen }
|
||||
flexShrink={ 0 }
|
||||
ml="auto"
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -40,6 +40,7 @@ const UserProfileDesktop = ({ buttonSize, buttonVariant = 'header' }: Props) =>
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO @tom2drum use auth modal instead
|
||||
if (router.pathname === '/apps/[id]') {
|
||||
signInWithWallet.start();
|
||||
return;
|
||||
|
||||
@@ -34,6 +34,7 @@ const UserProfileMobile = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO @tom2drum use auth modal instead
|
||||
if (router.pathname === '/apps/[id]') {
|
||||
signInWithWallet.start();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user