diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 8724a17..842724a 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -52,6 +52,12 @@ export interface IUpdatedContactsResult extends IDataResult { data: IUserContacts; } +export interface IUpdatedEmailResult extends IDataResult { + data: { + expired_seconds: number; + }; +} + export interface IUserResult extends IDataResult { data: Omit; } diff --git a/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx b/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx index 2f9a78a..222c545 100644 --- a/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx +++ b/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx @@ -1,9 +1,24 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { PinInput, PinInputField } from '@chakra-ui/react'; import { Button } from '@chakra-ui/button'; import { Box, Flex, Heading, HStack, Text } from '@chakra-ui/layout'; +import { ConfirmEmailContainerDataType } from 'types'; + +const ConfirmEmailContainer: React.FC<{ data: ConfirmEmailContainerDataType }> = ({ data }) => { + const [expired, setExpired] = useState(data.expired_seconds); + + useEffect(() => { + const interval = window.setInterval(() => { + if (expired <= 0) { + window.clearInterval(interval); + return; + } + setExpired(v => (v = v - 1)); + }, 1000); + + return () => window.clearInterval(interval); + }); -const ConfirmEmailContainer: React.FC<{ newEmail: string }> = ({ newEmail }) => { return ( = ({ newEmail }) => Confirmation - Enter the 4-digit code we send to {newEmail} + Enter the 4-digit code we send to {data.newEmail} @@ -44,12 +59,15 @@ const ConfirmEmailContainer: React.FC<{ newEmail: string }> = ({ newEmail }) => Verify - - Expires in 1:59 - - {/* */} + {expired > 0 ? ( + + Expires in {expired} seconds. + + ) : ( + + )} diff --git a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx b/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx index 2aaaf13..fbd50ca 100644 --- a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx +++ b/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx @@ -2,10 +2,12 @@ import { Button } from '@chakra-ui/button'; import { FormControl, FormHelperText, FormLabel } from '@chakra-ui/form-control'; import { Input } from '@chakra-ui/input'; import { Box, Stack } from '@chakra-ui/layout'; +import { useToast } from '@chakra-ui/toast'; import { yupResolver } from '@hookform/resolvers/yup'; import { ProfilePageViewContext } from 'contexts'; import { useRootStore } from 'hooks/useRootStore'; import React, { useContext } from 'react'; +import { useErrorHandler } from 'react-error-boundary'; import { SubmitHandler, useForm } from 'react-hook-form'; import UpdateEmailSchema from './UpdateEmailForm.validator'; @@ -18,9 +20,7 @@ type UpdateEmailInputType = { */ const UpdateEmailForm: React.FC = () => { const { setStatusPageView } = useContext(ProfilePageViewContext); - const { - userStore: { me }, - } = useRootStore(); + const { userStore } = useRootStore(); const { handleSubmit, register, @@ -28,10 +28,25 @@ const UpdateEmailForm: React.FC = () => { } = useForm({ resolver: yupResolver(UpdateEmailSchema), }); + const toast = useToast(); + const handleError = useErrorHandler(); - const onSubmit: SubmitHandler = async data => { - console.log(data); - setStatusPageView({ status: 'confirm-email', data: { confirmEmailData: { newEmail: data.email } } }); + const onSubmit: SubmitHandler = async ({ email }) => { + userStore + .updateUserEmail(email) + .then(({ data }) => { + setStatusPageView({ + status: 'confirm-email', + data: { confirmEmailData: { newEmail: email, expired_seconds: data.expired_seconds } }, + }); + }) + .catch(error => { + if (error.response) { + toast({ title: `${error.message}`, status: 'error' }); + } else { + handleError(error); + } + }); }; return ( @@ -40,7 +55,7 @@ const UpdateEmailForm: React.FC = () => { Current email - + New email diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index 40b46d6..a2e8765 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -124,7 +124,7 @@ const ProfilePage: React.FC = () => { {statusPageView.status === 'update-password' && } {statusPageView.status === 'update-email' && } {statusPageView.status === 'confirm-email' && statusPageView.data?.confirmEmailData && ( - + )} ); diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 25445fd..47d3df4 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -1,5 +1,5 @@ import { AxiosInstance } from 'axios'; -import { IDataResult, IUpdatedContactsResult, IUserContacts, IUserResult } from 'interfaces'; +import { IDataResult, IUpdatedContactsResult, IUpdatedEmailResult, IUserContacts, IUserResult } from 'interfaces'; import * as helpers from 'helpers'; export default class UserService { @@ -44,4 +44,17 @@ export default class UserService { }); return result.data; } + + public async updateEmail(email: string): Promise { + const result = await this.api.patch('v1/me/email', { email }); + return result.data; + } + + public async updateEmailConfirm(email: string, confirmationCode: number): Promise { + const result = await this.api.post('v1/me/email/change/confirm', { + email, + confirmationCode, + }); + return result.data; + } } diff --git a/src/stores/UserStore.ts b/src/stores/UserStore.ts index e53d666..551f120 100644 --- a/src/stores/UserStore.ts +++ b/src/stores/UserStore.ts @@ -1,6 +1,13 @@ import { AxiosInstance } from 'axios'; import { makeAutoObservable, runInAction } from 'mobx'; -import { IUserResult, IUser, IUserContacts, IUpdatedContactsResult, IDataResult } from 'interfaces'; +import { + IUserResult, + IUser, + IUserContacts, + IUpdatedContactsResult, + IDataResult, + IUpdatedEmailResult, +} from 'interfaces'; /** * Services @@ -77,6 +84,15 @@ export default class UserStore { } } + public async updateUserEmail(email: string): Promise { + try { + const result = await this.userService.updateEmail(email); + return result; + } catch (error) { + throw error; + } + } + public reset(): void { runInAction(() => { this.me = null; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 9a7881d..a326da0 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -7,15 +7,18 @@ export type LinkType = { icon: IconType; }; +export type ConfirmEmailContainerDataType = { + newEmail: string; + expired_seconds: number; +}; + export type ProfilePageStatusType = { status: 'update-password' | 'update-email' | 'confirm-email' | 'default'; data?: { /** * The field that is set when trying to change the mail address through form */ - confirmEmailData?: { - newEmail: string; - }; + confirmEmailData?: ConfirmEmailContainerDataType; }; }; export type ProfilePageViewStatusContextType = {