feat: exipred seconds interval

This commit is contained in:
Sergey Yarkov 2021-09-06 23:25:40 +03:00
parent cf81c3f5da
commit da4335ce7f
7 changed files with 93 additions and 22 deletions

View File

@ -52,6 +52,12 @@ export interface IUpdatedContactsResult extends IDataResult {
data: IUserContacts; data: IUserContacts;
} }
export interface IUpdatedEmailResult extends IDataResult {
data: {
expired_seconds: number;
};
}
export interface IUserResult extends IDataResult { export interface IUserResult extends IDataResult {
data: Omit<IUser, 'fullname'>; data: Omit<IUser, 'fullname'>;
} }

View File

@ -1,9 +1,24 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { PinInput, PinInputField } from '@chakra-ui/react'; import { PinInput, PinInputField } from '@chakra-ui/react';
import { Button } from '@chakra-ui/button'; import { Button } from '@chakra-ui/button';
import { Box, Flex, Heading, HStack, Text } from '@chakra-ui/layout'; 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 ( return (
<Box <Box
maxW='500px' maxW='500px'
@ -17,7 +32,7 @@ const ConfirmEmailContainer: React.FC<{ newEmail: string }> = ({ newEmail }) =>
<Heading as='h1'>Confirmation</Heading> <Heading as='h1'>Confirmation</Heading>
<Box mt='3'> <Box mt='3'>
<Text> <Text>
Enter the 4-digit code we send to <Text as='b'>{newEmail}</Text> Enter the 4-digit code we send to <Text as='b'>{data.newEmail}</Text>
</Text> </Text>
</Box> </Box>
<Flex alignItems='center' mt='10'> <Flex alignItems='center' mt='10'>
@ -44,12 +59,15 @@ const ConfirmEmailContainer: React.FC<{ newEmail: string }> = ({ newEmail }) =>
Verify Verify
</Button> </Button>
<Box mt='1.5'> <Box mt='1.5'>
<Text as='small' color='red'> {expired > 0 ? (
Expires in 1:59 <Text as='small' color='red'>
</Text> Expires in {expired} seconds.
{/* <Button variant='link' size='sm' colorScheme='black' mt='3' textDecoration='underline'> </Text>
Resend code ) : (
</Button> */} <Button variant='link' size='sm' colorScheme='black' mt='3' textDecoration='underline'>
Resend code
</Button>
)}
</Box> </Box>
</Box> </Box>
</Flex> </Flex>

View File

@ -2,10 +2,12 @@ import { Button } from '@chakra-ui/button';
import { FormControl, FormHelperText, FormLabel } from '@chakra-ui/form-control'; import { FormControl, FormHelperText, FormLabel } from '@chakra-ui/form-control';
import { Input } from '@chakra-ui/input'; import { Input } from '@chakra-ui/input';
import { Box, Stack } from '@chakra-ui/layout'; import { Box, Stack } from '@chakra-ui/layout';
import { useToast } from '@chakra-ui/toast';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
import { ProfilePageViewContext } from 'contexts'; import { ProfilePageViewContext } from 'contexts';
import { useRootStore } from 'hooks/useRootStore'; import { useRootStore } from 'hooks/useRootStore';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useErrorHandler } from 'react-error-boundary';
import { SubmitHandler, useForm } from 'react-hook-form'; import { SubmitHandler, useForm } from 'react-hook-form';
import UpdateEmailSchema from './UpdateEmailForm.validator'; import UpdateEmailSchema from './UpdateEmailForm.validator';
@ -18,9 +20,7 @@ type UpdateEmailInputType = {
*/ */
const UpdateEmailForm: React.FC = () => { const UpdateEmailForm: React.FC = () => {
const { setStatusPageView } = useContext(ProfilePageViewContext); const { setStatusPageView } = useContext(ProfilePageViewContext);
const { const { userStore } = useRootStore();
userStore: { me },
} = useRootStore();
const { const {
handleSubmit, handleSubmit,
register, register,
@ -28,10 +28,25 @@ const UpdateEmailForm: React.FC = () => {
} = useForm<UpdateEmailInputType>({ } = useForm<UpdateEmailInputType>({
resolver: yupResolver(UpdateEmailSchema), resolver: yupResolver(UpdateEmailSchema),
}); });
const toast = useToast();
const handleError = useErrorHandler();
const onSubmit: SubmitHandler<UpdateEmailInputType> = async data => { const onSubmit: SubmitHandler<UpdateEmailInputType> = async ({ email }) => {
console.log(data); userStore
setStatusPageView({ status: 'confirm-email', data: { confirmEmailData: { newEmail: data.email } } }); .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 ( return (
@ -40,7 +55,7 @@ const UpdateEmailForm: React.FC = () => {
<Stack spacing='15px' mt='10'> <Stack spacing='15px' mt='10'>
<FormControl id='email'> <FormControl id='email'>
<FormLabel>Current email</FormLabel> <FormLabel>Current email</FormLabel>
<Input type='email' size='md' variant='filled' disabled value={me?.email} /> <Input type='email' size='md' variant='filled' disabled value={userStore.me?.email} />
</FormControl> </FormControl>
<FormControl id='new_email' isRequired> <FormControl id='new_email' isRequired>
<FormLabel>New email</FormLabel> <FormLabel>New email</FormLabel>

View File

@ -124,7 +124,7 @@ const ProfilePage: React.FC<IPageProps> = () => {
{statusPageView.status === 'update-password' && <UpdatePasswordContainer />} {statusPageView.status === 'update-password' && <UpdatePasswordContainer />}
{statusPageView.status === 'update-email' && <UpdateEmailContainer />} {statusPageView.status === 'update-email' && <UpdateEmailContainer />}
{statusPageView.status === 'confirm-email' && statusPageView.data?.confirmEmailData && ( {statusPageView.status === 'confirm-email' && statusPageView.data?.confirmEmailData && (
<ConfirmEmailContainer newEmail={statusPageView.data.confirmEmailData.newEmail} /> <ConfirmEmailContainer data={statusPageView.data.confirmEmailData} />
)} )}
</ProfilePageViewContext.Provider> </ProfilePageViewContext.Provider>
); );

View File

@ -1,5 +1,5 @@
import { AxiosInstance } from 'axios'; import { AxiosInstance } from 'axios';
import { IDataResult, IUpdatedContactsResult, IUserContacts, IUserResult } from 'interfaces'; import { IDataResult, IUpdatedContactsResult, IUpdatedEmailResult, IUserContacts, IUserResult } from 'interfaces';
import * as helpers from 'helpers'; import * as helpers from 'helpers';
export default class UserService { export default class UserService {
@ -44,4 +44,17 @@ export default class UserService {
}); });
return result.data; return result.data;
} }
public async updateEmail(email: string): Promise<IUpdatedEmailResult> {
const result = await this.api.patch('v1/me/email', { email });
return result.data;
}
public async updateEmailConfirm(email: string, confirmationCode: number): Promise<IDataResult> {
const result = await this.api.post('v1/me/email/change/confirm', {
email,
confirmationCode,
});
return result.data;
}
} }

View File

@ -1,6 +1,13 @@
import { AxiosInstance } from 'axios'; import { AxiosInstance } from 'axios';
import { makeAutoObservable, runInAction } from 'mobx'; import { makeAutoObservable, runInAction } from 'mobx';
import { IUserResult, IUser, IUserContacts, IUpdatedContactsResult, IDataResult } from 'interfaces'; import {
IUserResult,
IUser,
IUserContacts,
IUpdatedContactsResult,
IDataResult,
IUpdatedEmailResult,
} from 'interfaces';
/** /**
* Services * Services
@ -77,6 +84,15 @@ export default class UserStore {
} }
} }
public async updateUserEmail(email: string): Promise<IUpdatedEmailResult> {
try {
const result = await this.userService.updateEmail(email);
return result;
} catch (error) {
throw error;
}
}
public reset(): void { public reset(): void {
runInAction(() => { runInAction(() => {
this.me = null; this.me = null;

View File

@ -7,15 +7,18 @@ export type LinkType = {
icon: IconType; icon: IconType;
}; };
export type ConfirmEmailContainerDataType = {
newEmail: string;
expired_seconds: number;
};
export type ProfilePageStatusType = { export type ProfilePageStatusType = {
status: 'update-password' | 'update-email' | 'confirm-email' | 'default'; status: 'update-password' | 'update-email' | 'confirm-email' | 'default';
data?: { data?: {
/** /**
* The field that is set when trying to change the mail address through form * The field that is set when trying to change the mail address through form
*/ */
confirmEmailData?: { confirmEmailData?: ConfirmEmailContainerDataType;
newEmail: string;
};
}; };
}; };
export type ProfilePageViewStatusContextType = { export type ProfilePageViewStatusContextType = {