mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
refactor: refactor profile page
This commit is contained in:
parent
1ceb083282
commit
27e1cdbfa5
@ -23,6 +23,8 @@ import PublicRoute from '@educt/components/PublicRoute';
|
||||
import AuthPage from '@educt/pages/auth/auth';
|
||||
import NotFoundPage from '@educt/pages/404/404';
|
||||
import CreateCoursePage from '@educt/pages/courses/create/create';
|
||||
import ChangePasswordPage from '@educt/pages/profile/change-password/change-password';
|
||||
import ChangeEmailPage from '@educt/pages/profile/change-email/change-email';
|
||||
const CoursesPage = React.lazy(() => import('@educt/pages/courses/courses'));
|
||||
const MainPage = React.lazy(() => import('@educt/pages/main/main'));
|
||||
const MessagesPage = React.lazy(() => import('@educt/pages/messages/messages'));
|
||||
@ -46,7 +48,9 @@ const App = () => {
|
||||
roles={[UserRoleEnum.ADMIN, UserRoleEnum.TEACHER]}
|
||||
/>
|
||||
<PrivateRoute path='/messages' component={MessagesPage} title='Messages' />
|
||||
<PrivateRoute path='/profile' component={ProfilePage} title='Profile' />
|
||||
<PrivateRoute exact path='/profile' component={ProfilePage} title='Profile' />
|
||||
<PrivateRoute path='/profile/change-password' component={ChangePasswordPage} title='Change Password' />
|
||||
<PrivateRoute path='/profile/change-email' component={ChangeEmailPage} title='Change Email' />
|
||||
<PrivateRoute
|
||||
path='/users'
|
||||
component={UsersPage}
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
import config from '@educt/config';
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { Flex, Box, Heading, useColorMode } from '@chakra-ui/react';
|
||||
import UserInfo from './UserInfo';
|
||||
import UserNotifications from './UserNotifications';
|
||||
import { MdSchool } from 'react-icons/md';
|
||||
import config from '@educt/config';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import NavMobile from '@educt/components/Nav/Mobile';
|
||||
import ColorModeSwitcher from '@educt/components/ColorModeSwitcher';
|
||||
import { MdSchool } from 'react-icons/md';
|
||||
import UserInfo from './UserInfo';
|
||||
import UserNotifications from './UserNotifications';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useMediaQuery } from '@chakra-ui/media-query';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const {
|
||||
uiStore: { isDesktop },
|
||||
} = useRootStore();
|
||||
const [isDesktop] = useMediaQuery('(min-width: 992px)');
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
return (
|
||||
@ -22,7 +28,9 @@ const Header: React.FC = () => {
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
borderBottomWidth={1}
|
||||
// borderBottomWidth={1}
|
||||
// h='43px'
|
||||
boxShadow='md'
|
||||
backgroundColor={colorMode === 'dark' ? 'gray.800' : 'white'}
|
||||
zIndex={4}
|
||||
>
|
||||
|
||||
@ -44,24 +44,7 @@ const Layout: React.FC<LayoutPropsType> = ({ children, roles }) => {
|
||||
<Header />
|
||||
<NavDesktop />
|
||||
<Flex minH='100vh' justifyContent='center'>
|
||||
<Box
|
||||
as='main'
|
||||
flex='1 0'
|
||||
maxW='85rem'
|
||||
ml='20rem'
|
||||
mt='7rem'
|
||||
mb='1rem'
|
||||
pr='2rem'
|
||||
pl='2rem'
|
||||
sx={{
|
||||
'@media (max-width: 1400px)': {
|
||||
ml: '20rem',
|
||||
},
|
||||
'@media (max-width: 991px)': {
|
||||
ml: '0',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box as='main' flex='1 0' maxW='85rem' ml={{ base: '0', lg: '20rem' }} mt='7rem' mb='1rem' pr='2rem' pl='2rem'>
|
||||
<Suspense fallback={<LoadingPage />}>
|
||||
{(() => {
|
||||
/**
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Flex, Box, useColorMode } from '@chakra-ui/react';
|
||||
import { Flex, Box, Text, Link, IconButton } from '@chakra-ui/react';
|
||||
import config from '@educt/config';
|
||||
|
||||
/**
|
||||
@ -11,7 +11,8 @@ import NavList from '../NavList';
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { useColorMode, useMediaQuery } from '@chakra-ui/react';
|
||||
import { FaGithub } from 'react-icons/fa';
|
||||
|
||||
/**
|
||||
*
|
||||
@ -19,14 +20,13 @@ import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
* Component for navigating the application.
|
||||
*/
|
||||
const Nav: React.FC = () => {
|
||||
const {
|
||||
uiStore: { isDesktop },
|
||||
} = useRootStore();
|
||||
const { colorMode } = useColorMode();
|
||||
const [isDesktop] = useMediaQuery('(min-width: 992px)');
|
||||
|
||||
if (isDesktop) {
|
||||
return (
|
||||
<Box
|
||||
<Flex
|
||||
flexDir='column'
|
||||
borderRightWidth='1px'
|
||||
w='18rem'
|
||||
position='fixed'
|
||||
@ -49,7 +49,19 @@ const Nav: React.FC = () => {
|
||||
>
|
||||
<NavList links={config.links} />
|
||||
</Flex>
|
||||
<Box textAlign='center' mt='auto' mb='5'>
|
||||
<Text fontSize='xs' color='gray.500' lineHeight='1.5'>
|
||||
Learning Management System <br /> Made by Sergey Yarkov
|
||||
</Text>
|
||||
<Box textAlign='center' mt='2'>
|
||||
<IconButton variant='link' aria-label='GitHub repository'>
|
||||
<Link isExternal href='https://github.com/sergeyyarkov/educt-client'>
|
||||
<Box as={FaGithub} />
|
||||
</Link>
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { createContext } from 'react';
|
||||
import { CoursesPageContextType, ProfilePageContextType, UsersPageContextType } from '@educt/types';
|
||||
import { ChangeEmailPageContextType, CoursesPageContextType, UsersPageContextType } from '@educt/types';
|
||||
import RootStore from '../stores/RootStore';
|
||||
|
||||
export const StoreContext = createContext<RootStore | undefined>(undefined);
|
||||
|
||||
export const ProfilePageContext = createContext<ProfilePageContextType>({
|
||||
statusPageView: 'default',
|
||||
setStatusPageView: () => {},
|
||||
pageData: {},
|
||||
setPageData: () => {},
|
||||
export const ChangeEmailPageContext = createContext<ChangeEmailPageContextType>({
|
||||
isCodeSent: false,
|
||||
setIsCodeSent: () => {},
|
||||
confirmEmailData: undefined,
|
||||
setConfirmEmailData: () => {},
|
||||
});
|
||||
|
||||
export const UsersPageContext = createContext<UsersPageContextType>({
|
||||
|
||||
@ -88,7 +88,7 @@ const CourseList: React.FC<CourseListPropsType> = ({ courses, isLoading }) => {
|
||||
<>
|
||||
{deletingCourse && <DeleteCourseDialog onClose={onCloseDeleteDialog} isOpen={isOpenDeleteDialog} />}
|
||||
{courses.length !== 0 ? (
|
||||
<Grid templateColumns='repeat(auto-fill, minmax(400px, 1fr))' gap='6'>
|
||||
<Grid templateColumns={{ sm: 'repeat(auto-fill, minmax(400px, 1fr))' }} gap='4'>
|
||||
{/* Render items */}
|
||||
{courses.map(course => (
|
||||
<CourseItem key={course.id} course={course} onDelete={onDeleteCourse} onSetStatus={onSetStatus} />
|
||||
|
||||
84
src/pages/profile/change-email/change-email.tsx
Normal file
84
src/pages/profile/change-email/change-email.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import { Box, Flex, Heading, Text } from '@chakra-ui/layout';
|
||||
import { IconButton } from '@chakra-ui/button';
|
||||
import { ChevronLeftIcon } from '@chakra-ui/icons';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import { IPageProps } from '@educt/interfaces';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import LoadingPage from '@educt/components/LoadingPage';
|
||||
import UpdateEmailForm from './components/UpdateEmailForm';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useHistory } from 'react-router';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
/**
|
||||
* Providers
|
||||
*/
|
||||
import { ChangeEmailPageContextProvider } from '@educt/providers';
|
||||
import { ChangeEmailPageContext } from '@educt/contexts';
|
||||
import ConfirmEmailContainer from './containers/ConfirmEmailContainer';
|
||||
|
||||
{
|
||||
/* <>
|
||||
{!isCodeSent ? (
|
||||
<UpdateEmailForm currentEmail={me.email} />
|
||||
) : (
|
||||
confirmEmailData && <ConfirmEmailContainer data={confirmEmailData} />
|
||||
)}
|
||||
</> */
|
||||
}
|
||||
|
||||
/**
|
||||
* Change email page
|
||||
*/
|
||||
const ChangeEmailPage: React.FC<IPageProps> = () => {
|
||||
const {
|
||||
userStore: { me },
|
||||
} = useRootStore();
|
||||
const history = useHistory();
|
||||
|
||||
if (me === null) return <LoadingPage />;
|
||||
|
||||
return (
|
||||
<ChangeEmailPageContextProvider>
|
||||
<ChangeEmailPageContext.Consumer>
|
||||
{({ isCodeSent, confirmEmailData }) => (
|
||||
<>
|
||||
{!isCodeSent ? (
|
||||
<Box maxW='700px'>
|
||||
<Flex alignItems='center'>
|
||||
<IconButton
|
||||
aria-label='Back'
|
||||
borderRadius='full'
|
||||
icon={<ChevronLeftIcon />}
|
||||
onClick={() => history.push('/profile')}
|
||||
mr='5'
|
||||
/>
|
||||
<Heading as='h1'>Edit email address</Heading>
|
||||
</Flex>
|
||||
<Box mt='3'>
|
||||
<Text>Type your new email address.</Text>
|
||||
</Box>
|
||||
<UpdateEmailForm currentEmail={me.email} />
|
||||
</Box>
|
||||
) : (
|
||||
confirmEmailData && <ConfirmEmailContainer data={confirmEmailData} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ChangeEmailPageContext.Consumer>
|
||||
</ChangeEmailPageContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(ChangeEmailPage);
|
||||
@ -1,26 +1,46 @@
|
||||
import React from 'react';
|
||||
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 { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import type { SubmitHandler } from 'react-hook-form';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import useUpdateUserEmailQuery from '@educt/hooks/useUpdateUserEmailQuery.ts';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
|
||||
/**
|
||||
* Contexts
|
||||
*/
|
||||
import { ChangeEmailPageContext } from '@educt/contexts';
|
||||
|
||||
/**
|
||||
* Schema
|
||||
*/
|
||||
import UpdateEmailSchema from './UpdateEmailForm.validator';
|
||||
|
||||
type UpdateEmailInputType = {
|
||||
email: string;
|
||||
};
|
||||
|
||||
type UpdateEmailFormPropsType = {
|
||||
currentEmail: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update email using form
|
||||
* Send confirmation code before change email using form
|
||||
*/
|
||||
const UpdateEmailForm: React.FC = () => {
|
||||
const [email, setEmail] = useState<string | null>(null);
|
||||
const { setStatusPageView, setPageData } = useContext(ProfilePageContext);
|
||||
const { userStore } = useRootStore();
|
||||
const UpdateEmailForm: React.FC<UpdateEmailFormPropsType> = ({ currentEmail }) => {
|
||||
const [newEmail, setNewEmail] = useState<string | null>(null);
|
||||
const { setIsCodeSent, setConfirmEmailData } = useContext(ChangeEmailPageContext);
|
||||
const { sendConfirmationCode, loading, result } = useUpdateUserEmailQuery();
|
||||
const {
|
||||
handleSubmit,
|
||||
@ -30,16 +50,25 @@ const UpdateEmailForm: React.FC = () => {
|
||||
resolver: yupResolver(UpdateEmailSchema),
|
||||
});
|
||||
|
||||
/**
|
||||
* Change page view in confirmation code has been sent
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (email !== null && result !== null) {
|
||||
setStatusPageView('confirm-email');
|
||||
setPageData({ confirmEmailData: { newEmail: email, expired_seconds: result.data.expired_seconds } });
|
||||
if (newEmail !== null && result !== null) {
|
||||
setIsCodeSent(true);
|
||||
setConfirmEmailData({ newEmail, expired_seconds: result.data.expired_seconds });
|
||||
}
|
||||
});
|
||||
}, [result]);
|
||||
|
||||
const onSubmit: SubmitHandler<UpdateEmailInputType> = ({ email }) => {
|
||||
setEmail(email);
|
||||
sendConfirmationCode(email);
|
||||
/**
|
||||
* Submit form handler
|
||||
*/
|
||||
const onSubmit: SubmitHandler<UpdateEmailInputType> = async ({ email }) => {
|
||||
/**
|
||||
* Set new email state and send confirmation code
|
||||
*/
|
||||
setNewEmail(email);
|
||||
await sendConfirmationCode(email);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -48,7 +77,7 @@ const UpdateEmailForm: React.FC = () => {
|
||||
<Stack spacing='15px' mt='10'>
|
||||
<FormControl id='email'>
|
||||
<FormLabel>Current email</FormLabel>
|
||||
<Input type='email' size='md' variant='filled' disabled value={userStore.me?.email} />
|
||||
<Input type='email' size='md' variant='filled' disabled value={currentEmail} />
|
||||
</FormControl>
|
||||
<FormControl id='new_email' isRequired>
|
||||
<FormLabel>New email</FormLabel>
|
||||
@ -1,22 +1,30 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React 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 '@educt/types';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import { ConfirmEmailDataType } from '@educt/types';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import useUpdateUserEmailQuery from '@educt/hooks/useUpdateUserEmailQuery.ts';
|
||||
import useIsMountedRef from '@educt/hooks/useIsMountedRef';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { useToast } from '@chakra-ui/toast';
|
||||
import { useErrorHandler } from 'react-error-boundary';
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
import useIsMountedRef from '@educt/hooks/useIsMountedRef';
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
type ConfirmEmailContainerPropsType = {
|
||||
data: ConfirmEmailContainerDataType;
|
||||
data: ConfirmEmailDataType;
|
||||
};
|
||||
|
||||
const ConfirmEmailContainer: React.FC<ConfirmEmailContainerPropsType> = ({ data }) => {
|
||||
const { userStore } = useRootStore();
|
||||
const { setStatusPageView } = useContext(ProfilePageContext);
|
||||
const { sendConfirmationCode, loading } = useUpdateUserEmailQuery();
|
||||
const [isVerifying, setIsVerifying] = useState<boolean>(false);
|
||||
const [code, setCode] = useState<string>('');
|
||||
@ -24,6 +32,7 @@ const ConfirmEmailContainer: React.FC<ConfirmEmailContainerPropsType> = ({ data
|
||||
const isMountedRef = useIsMountedRef();
|
||||
const toast = useToast();
|
||||
const handleError = useErrorHandler();
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
const interval = window.setInterval(() => {
|
||||
@ -47,7 +56,7 @@ const ConfirmEmailContainer: React.FC<ConfirmEmailContainerPropsType> = ({ data
|
||||
status: 'info',
|
||||
});
|
||||
if (isMountedRef.current) {
|
||||
setStatusPageView('default');
|
||||
history.push('/profile');
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.response) {
|
||||
54
src/pages/profile/change-password/change-password.tsx
Normal file
54
src/pages/profile/change-password/change-password.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Box, Heading, Flex, Text, IconButton } from '@chakra-ui/react';
|
||||
import { ChevronLeftIcon } from '@chakra-ui/icons';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import { IPageProps } from '@educt/interfaces';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import UpdatePasswordForm from './components/UpdatePasswordForm';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { useHistory } from 'react-router';
|
||||
import LoadingPage from '@educt/components/LoadingPage';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
/**
|
||||
* Change password page
|
||||
*/
|
||||
const ChangePasswordPage: React.FC<IPageProps> = () => {
|
||||
const {
|
||||
userStore: { me },
|
||||
} = useRootStore();
|
||||
const history = useHistory();
|
||||
|
||||
if (me === null) return <LoadingPage />;
|
||||
|
||||
return (
|
||||
<Box maxW='700px'>
|
||||
<Flex alignItems='center'>
|
||||
<IconButton
|
||||
aria-label='Profile page'
|
||||
borderRadius='full'
|
||||
icon={<ChevronLeftIcon />}
|
||||
onClick={() => history.push('/profile')}
|
||||
mr='5'
|
||||
/>
|
||||
<Heading as='h1'>Update password</Heading>
|
||||
</Flex>
|
||||
<Box mt='3'>
|
||||
<Text>Your new password must be different from the current one.</Text>
|
||||
</Box>
|
||||
<UpdatePasswordForm />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(ChangePasswordPage);
|
||||
@ -1,16 +1,30 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import React from 'react';
|
||||
import { Box, Stack } from '@chakra-ui/layout';
|
||||
import { FormControl, FormLabel, FormHelperText } from '@chakra-ui/form-control';
|
||||
import { Button } from '@chakra-ui/button';
|
||||
import { Input } from '@chakra-ui/input';
|
||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import UpdatePasswordSchema from './UpdatePasswordForm.validator';
|
||||
import { useToast } from '@chakra-ui/toast';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import type { SubmitHandler } from 'react-hook-form';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useState } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useErrorHandler } from 'react-error-boundary';
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import useIsMountedRef from '@educt/hooks/useIsMountedRef';
|
||||
import { useToast } from '@chakra-ui/toast';
|
||||
|
||||
/**
|
||||
* Schema
|
||||
*/
|
||||
import UpdatePasswordSchema from './UpdatePasswordForm.validator';
|
||||
|
||||
type UpdatePasswordInputType = {
|
||||
old_password: string;
|
||||
@ -22,10 +36,9 @@ type UpdatePasswordInputType = {
|
||||
* Update password using form
|
||||
*/
|
||||
const UpdatePasswordForm: React.FC = () => {
|
||||
const { setStatusPageView } = useContext(ProfilePageContext);
|
||||
const { userStore } = useRootStore();
|
||||
const isMountedRef = useIsMountedRef();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const {
|
||||
handleSubmit,
|
||||
register,
|
||||
@ -35,19 +48,25 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
} = useForm<UpdatePasswordInputType>({
|
||||
resolver: yupResolver(UpdatePasswordSchema),
|
||||
});
|
||||
|
||||
const history = useHistory();
|
||||
const toast = useToast();
|
||||
const handleError = useErrorHandler();
|
||||
|
||||
/**
|
||||
* Submit form handler
|
||||
*/
|
||||
const onSubmit: SubmitHandler<UpdatePasswordInputType> = async ({ old_password, new_password, confirm_password }) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setIsLoading(true);
|
||||
await userStore.updateCurrentUserPassword(old_password, new_password);
|
||||
toast({ title: 'Password changed.', status: 'success' });
|
||||
reset();
|
||||
setStatusPageView('default');
|
||||
history.push('/profile');
|
||||
} catch (error: any) {
|
||||
if (error.response) {
|
||||
/**
|
||||
* Invalid current password handler
|
||||
*/
|
||||
if (error.response.status === 401) {
|
||||
toast({ title: 'Invalid current password.', status: 'error', duration: 2000 });
|
||||
reset({ old_password: '', new_password, confirm_password });
|
||||
@ -60,7 +79,7 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
}
|
||||
} finally {
|
||||
if (isMountedRef.current) {
|
||||
setLoading(false);
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -76,7 +95,7 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
size='md'
|
||||
variant='filled'
|
||||
placeholder='*******'
|
||||
isInvalid={errors.old_password ? true : false}
|
||||
isInvalid={!!errors.old_password}
|
||||
{...register('old_password')}
|
||||
/>
|
||||
<FormHelperText color='gray.500'>Type your current password.</FormHelperText>
|
||||
@ -88,7 +107,7 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
size='md'
|
||||
variant='filled'
|
||||
placeholder='*******'
|
||||
isInvalid={errors.new_password ? true : false}
|
||||
isInvalid={!!errors.new_password}
|
||||
{...register('new_password')}
|
||||
/>
|
||||
<FormHelperText color={errors.new_password ? 'red' : 'gray.500'}>
|
||||
@ -102,7 +121,7 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
size='md'
|
||||
variant='filled'
|
||||
placeholder='*******'
|
||||
isInvalid={errors.confirm_password ? true : false}
|
||||
isInvalid={!!errors.confirm_password}
|
||||
{...register('confirm_password')}
|
||||
/>
|
||||
<FormHelperText color={errors.confirm_password ? 'red' : 'gray.500'}>
|
||||
@ -116,7 +135,7 @@ const UpdatePasswordForm: React.FC = () => {
|
||||
type='submit'
|
||||
size='md'
|
||||
variant='outline'
|
||||
isLoading={loading}
|
||||
isLoading={isLoading}
|
||||
loadingText='Saving...'
|
||||
>
|
||||
Change
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link as ReactRouterLink } from 'react-router-dom';
|
||||
import { Tag, TagLabel } from '@chakra-ui/react';
|
||||
import { Tag, TagLabel, LinkBox, Heading, LinkOverlay } from '@chakra-ui/react';
|
||||
import { Text, Link, Box, Flex } from '@chakra-ui/layout';
|
||||
import { MdVideoLibrary, MdGroup, MdThumbUp } from 'react-icons/md';
|
||||
|
||||
@ -15,24 +15,12 @@ type CourseItemPropsType = {
|
||||
|
||||
const CourseItem: React.FC<CourseItemPropsType> = ({ course }) => {
|
||||
return (
|
||||
<Flex flexDir='column' borderWidth='1px' borderRadius='lg' p='10px' boxShadow='sm' mb='3'>
|
||||
<Tag colorScheme='purple' borderRadius='full' alignSelf='flex-start'>
|
||||
<TagLabel>{course.category.title}</TagLabel>
|
||||
</Tag>
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Link
|
||||
as={ReactRouterLink}
|
||||
to={`course/${course.id}`}
|
||||
overflowWrap='anywhere'
|
||||
fontWeight='bold'
|
||||
fontSize='xl'
|
||||
mr='5'
|
||||
>
|
||||
{course.title}
|
||||
</Link>
|
||||
</Flex>
|
||||
<LinkBox as='div' p='5' borderWidth='1px' rounded='lg'>
|
||||
<Heading size='md' my='2'>
|
||||
<LinkOverlay href='#'>{course.title}</LinkOverlay>
|
||||
</Heading>
|
||||
<Text>{course.description}</Text>
|
||||
<Flex mt='5' alignItems='center'>
|
||||
<Flex mt='2' alignItems='center'>
|
||||
<MdVideoLibrary />
|
||||
<Text pl='1' pr='4'>
|
||||
{course.lessons_count} lessons
|
||||
@ -46,7 +34,40 @@ const CourseItem: React.FC<CourseItemPropsType> = ({ course }) => {
|
||||
{course.likes_count} likes
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</LinkBox>
|
||||
|
||||
// <Flex flexDir='column' borderWidth='1px' borderRadius='lg' p='10px' boxShadow='sm' mb='3'>
|
||||
// <Tag colorScheme='purple' borderRadius='full' alignSelf='flex-start'>
|
||||
// <TagLabel>{course.category.title}</TagLabel>
|
||||
// </Tag>
|
||||
// <Flex justifyContent='space-between' alignItems='center'>
|
||||
// <Link
|
||||
// as={ReactRouterLink}
|
||||
// to={`course/${course.id}`}
|
||||
// overflowWrap='anywhere'
|
||||
// fontWeight='bold'
|
||||
// fontSize='xl'
|
||||
// mr='5'
|
||||
// >
|
||||
// {course.title}
|
||||
// </Link>
|
||||
// </Flex>
|
||||
// <Text>{course.description}</Text>
|
||||
// <Flex mt='5' alignItems='center'>
|
||||
// <MdVideoLibrary />
|
||||
// <Text pl='1' pr='4'>
|
||||
// {course.lessons_count} lessons
|
||||
// </Text>
|
||||
// <MdGroup />
|
||||
// <Text pl='1' pr='4'>
|
||||
// {course.students_count} students
|
||||
// </Text>
|
||||
// <MdThumbUp />
|
||||
// <Text pl='1' pr='4'>
|
||||
// {course.likes_count} likes
|
||||
// </Text>
|
||||
// </Flex>
|
||||
// </Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Box, Text, Flex } from '@chakra-ui/layout';
|
||||
import { Box, Text, Flex, Stack } from '@chakra-ui/layout';
|
||||
|
||||
/**
|
||||
* Types
|
||||
@ -16,9 +16,7 @@ type CourseListPropsType = {
|
||||
};
|
||||
|
||||
const CourseList: React.FC<CourseListPropsType> = ({ courses }) => {
|
||||
if (courses === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (courses === undefined) return null;
|
||||
|
||||
if (courses.length === 0) {
|
||||
return (
|
||||
@ -31,7 +29,7 @@ const CourseList: React.FC<CourseListPropsType> = ({ courses }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDirection='column'>
|
||||
<Flex flexDir='column'>
|
||||
{courses.map(course => (
|
||||
<CourseItem course={course} key={course.id} />
|
||||
))}
|
||||
|
||||
@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Box, Heading, Stack, Flex, StackDivider, Text, Button } from '@chakra-ui/react';
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import { IUser } from '@educt/interfaces';
|
||||
|
||||
/**
|
||||
* Contexts
|
||||
*/
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useContext } from 'react';
|
||||
|
||||
type UserAccountInfoPropsType = {
|
||||
user: IUser;
|
||||
};
|
||||
|
||||
const UserAccountInfo: React.FC<UserAccountInfoPropsType> = ({ user }) => {
|
||||
const { setStatusPageView } = useContext(ProfilePageContext);
|
||||
|
||||
return (
|
||||
<Box borderRadius='lg' borderWidth='1px' padding='20px' boxShadow='sm'>
|
||||
<Stack spacing='10px' divider={<StackDivider />}>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
First Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.first_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Last Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.last_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Email
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{user.email}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button onClick={() => setStatusPageView('update-email')}>Edit</Button>
|
||||
</Flex>
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Password
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
**********
|
||||
</Text>
|
||||
</Box>
|
||||
<Button onClick={() => setStatusPageView('update-password')}>Change</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserAccountInfo;
|
||||
@ -1,3 +0,0 @@
|
||||
import UserAccountInfo from './UserAccountInfo';
|
||||
|
||||
export default UserAccountInfo;
|
||||
@ -1,82 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Box, Heading, Flex, Avatar, Text, Tabs, TabList, Tab, TabPanels, TabPanel, Button } from '@chakra-ui/react';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import UserBadge from '@educt/components/UserBadge';
|
||||
import UserAccountInfo from '@educt/pages/profile/components/UserAccountInfo';
|
||||
import UpdateUserContactsForm from '@educt/pages/profile/components/UpdateUserContactsForm';
|
||||
import CourseList from '@educt/pages/profile/components/CourseList';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import useLogoutQuery from '@educt/hooks/useLogoutQuery';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { useColorMode } from '@chakra-ui/color-mode';
|
||||
|
||||
const MainContainer: React.FC = () => {
|
||||
const {
|
||||
userStore: { me },
|
||||
} = useRootStore();
|
||||
const { colorMode } = useColorMode();
|
||||
const { logout } = useLogoutQuery();
|
||||
|
||||
if (me === null) return null;
|
||||
|
||||
return (
|
||||
<Box maxW='900px'>
|
||||
<Heading as='h1'>My account</Heading>
|
||||
<Text mt='2'>Update you contacts information or password here.</Text>
|
||||
<Flex
|
||||
alignItems='center'
|
||||
flexDir={{ base: 'column', md: 'row' }}
|
||||
textAlign={{ base: 'center', md: 'left' }}
|
||||
mt='20'
|
||||
>
|
||||
<Box>
|
||||
<Avatar border={`4px solid ${colorMode === 'dark' ? '#2D3748' : '#E2E8F0'}`} size='2xl' name={me.fullname} />
|
||||
</Box>
|
||||
<Flex ml={{ md: '50' }} mt={{ base: '2', md: '0' }} flexDirection='column'>
|
||||
<Heading as='h2'>{me.fullname}</Heading>
|
||||
<Flex alignItems='center' flexDir={{ base: 'column', md: 'row' }}>
|
||||
<Text mr='10px' mb={{ base: '2', md: '0' }}>
|
||||
{me.email}
|
||||
</Text>
|
||||
<UserBadge roles={me.roles} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Box mt='10'>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Account information</Tab>
|
||||
<Tab>My contacts</Tab>
|
||||
{me.isStudent && <Tab>Available courses</Tab>}
|
||||
</TabList>
|
||||
<TabPanels mt='2'>
|
||||
<TabPanel>
|
||||
<UserAccountInfo user={me} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<UpdateUserContactsForm contacts={me.contacts} />
|
||||
</TabPanel>
|
||||
{me.isStudent && (
|
||||
<TabPanel>
|
||||
<CourseList courses={me.courses} />
|
||||
</TabPanel>
|
||||
)}
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Box>
|
||||
<Box textAlign='center' mt='3'>
|
||||
<Button onClick={logout} w={{ base: 'full', sm: '150px' }}>
|
||||
Sign Out
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainContainer;
|
||||
@ -1,3 +0,0 @@
|
||||
import MainContainer from './MainContainer';
|
||||
|
||||
export default MainContainer;
|
||||
@ -1,31 +0,0 @@
|
||||
import { IconButton } from '@chakra-ui/button';
|
||||
import { ChevronLeftIcon } from '@chakra-ui/icons';
|
||||
import { Box, Flex, Heading, Text } from '@chakra-ui/layout';
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
import React, { useContext } from 'react';
|
||||
import UpdateEmailForm from './UpdateEmailForm';
|
||||
|
||||
const UpdateEmailContainer: React.FC = () => {
|
||||
const { setStatusPageView } = useContext(ProfilePageContext);
|
||||
|
||||
return (
|
||||
<Box maxW='700px'>
|
||||
<Flex alignItems='center'>
|
||||
<IconButton
|
||||
aria-label='Back'
|
||||
borderRadius='full'
|
||||
icon={<ChevronLeftIcon />}
|
||||
onClick={() => setStatusPageView('default')}
|
||||
mr='5'
|
||||
/>
|
||||
<Heading as='h1'>Edit email address</Heading>
|
||||
</Flex>
|
||||
<Box mt='3'>
|
||||
<Text>Type your new email address.</Text>
|
||||
</Box>
|
||||
<UpdateEmailForm />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateEmailContainer;
|
||||
@ -1,3 +0,0 @@
|
||||
import UpdateEmailContainer from './UpdateEmailContainer';
|
||||
|
||||
export default UpdateEmailContainer;
|
||||
@ -1,30 +0,0 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { Box, Heading, Flex, Text, IconButton } from '@chakra-ui/react';
|
||||
import { ChevronLeftIcon } from '@chakra-ui/icons';
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
import UpdatePasswordForm from './UpdatePasswordForm';
|
||||
|
||||
const UpdatePasswordContainer: React.FC = () => {
|
||||
const { setStatusPageView } = useContext(ProfilePageContext);
|
||||
|
||||
return (
|
||||
<Box maxW='700px'>
|
||||
<Flex alignItems='center'>
|
||||
<IconButton
|
||||
aria-label='Back'
|
||||
borderRadius='full'
|
||||
icon={<ChevronLeftIcon />}
|
||||
onClick={() => setStatusPageView('default')}
|
||||
mr='5'
|
||||
/>
|
||||
<Heading as='h1'>Update password</Heading>
|
||||
</Flex>
|
||||
<Box mt='3'>
|
||||
<Text>Your new password must be different from the current one.</Text>
|
||||
</Box>
|
||||
<UpdatePasswordForm />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdatePasswordContainer;
|
||||
@ -1,3 +0,0 @@
|
||||
import UpdatePasswordContainer from './UpdatePasswordContainer';
|
||||
|
||||
export default UpdatePasswordContainer;
|
||||
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Avatar, Tabs, TabList, Tab, TabPanels, TabPanel, Button } from '@chakra-ui/react';
|
||||
import { Box, Flex, Heading, Text, Stack, StackDivider } from '@chakra-ui/layout';
|
||||
|
||||
/**
|
||||
* Types
|
||||
@ -10,31 +12,17 @@ import { IPageProps } from '@educt/interfaces';
|
||||
* Components
|
||||
*/
|
||||
import LoadingPage from './components/LoadingPage';
|
||||
|
||||
/**
|
||||
* Containers
|
||||
*/
|
||||
import MainContainer from './containers/MainContainer';
|
||||
import UpdatePasswordContainer from './containers/UpdatePasswordContainer';
|
||||
import UpdateEmailContainer from './containers/UpdateEmailContainer';
|
||||
import ConfirmEmailContainer from './containers/ConfirmEmailContainer';
|
||||
import UserBadge from '@educt/components/UserBadge';
|
||||
import UpdateUserContactsForm from '@educt/pages/profile/components/UpdateUserContactsForm';
|
||||
import CourseList from '@educt/pages/profile/components/CourseList';
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
import { useEffect } from 'react';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* Contexts
|
||||
*/
|
||||
import { ProfilePageContext } from '@educt/contexts';
|
||||
|
||||
/**
|
||||
* Providers
|
||||
*/
|
||||
import { ProfilePageContextProvider } from '@educt/providers';
|
||||
import { useColorMode } from '@chakra-ui/color-mode';
|
||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||
import useLogoutQuery from '@educt/hooks/useLogoutQuery';
|
||||
|
||||
/**
|
||||
* Profile page
|
||||
@ -42,39 +30,109 @@ import { ProfilePageContextProvider } from '@educt/providers';
|
||||
const ProfilePage: React.FC<IPageProps> = () => {
|
||||
const {
|
||||
userStore: { me },
|
||||
authStore,
|
||||
} = useRootStore();
|
||||
const history = useHistory();
|
||||
const { logout } = useLogoutQuery();
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
useEffect(() => {
|
||||
if (!authStore.isLoggedIn) {
|
||||
history.push('/auth');
|
||||
}
|
||||
});
|
||||
|
||||
if (me === null) {
|
||||
return <LoadingPage />;
|
||||
}
|
||||
if (me === null) return <LoadingPage />;
|
||||
|
||||
return (
|
||||
<ProfilePageContextProvider>
|
||||
<ProfilePageContext.Consumer>
|
||||
{({ statusPageView, pageData }) => {
|
||||
switch (statusPageView) {
|
||||
case 'default':
|
||||
return <MainContainer />;
|
||||
case 'update-password':
|
||||
return <UpdatePasswordContainer />;
|
||||
case 'update-email':
|
||||
return <UpdateEmailContainer />;
|
||||
case 'confirm-email':
|
||||
return pageData.confirmEmailData && <ConfirmEmailContainer data={pageData.confirmEmailData} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}}
|
||||
</ProfilePageContext.Consumer>
|
||||
</ProfilePageContextProvider>
|
||||
<Box maxW='900px'>
|
||||
<Heading as='h1'>My account</Heading>
|
||||
<Text mt='2'>Update you contacts information or password here.</Text>
|
||||
<Flex
|
||||
alignItems='center'
|
||||
flexDir={{ base: 'column', md: 'row' }}
|
||||
textAlign={{ base: 'center', md: 'left' }}
|
||||
mt='20'
|
||||
>
|
||||
<Box>
|
||||
<Avatar border={`4px solid ${colorMode === 'dark' ? '#2D3748' : '#E2E8F0'}`} size='2xl' name={me.fullname} />
|
||||
</Box>
|
||||
<Flex ml={{ md: '50' }} mt={{ base: '2', md: '0' }} flexDirection='column'>
|
||||
<Heading as='h2'>{me.fullname}</Heading>
|
||||
<Flex alignItems='center' flexDir={{ base: 'column', md: 'row' }}>
|
||||
<Text mr='10px' mb={{ base: '2', md: '0' }}>
|
||||
{me.email}
|
||||
</Text>
|
||||
<UserBadge roles={me.roles} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Box mt='10'>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Account information</Tab>
|
||||
<Tab>My contacts</Tab>
|
||||
{me.isStudent && <Tab>Available courses</Tab>}
|
||||
</TabList>
|
||||
<TabPanels mt='2'>
|
||||
<TabPanel>
|
||||
<Box borderRadius='lg' borderWidth='1px' padding='20px' boxShadow='sm'>
|
||||
<Stack spacing='10px' divider={<StackDivider />}>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
First Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{me.first_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Last Name
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{me.last_name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Email
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
{me.email}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button onClick={() => history.push('/profile/change-email')}>Edit</Button>
|
||||
</Flex>
|
||||
<Flex justifyContent='space-between' alignItems='center'>
|
||||
<Box>
|
||||
<Text as='small' color='gray.500'>
|
||||
Password
|
||||
</Text>
|
||||
<Text fontWeight='medium' fontSize='lg'>
|
||||
**********
|
||||
</Text>
|
||||
</Box>
|
||||
<Button onClick={() => history.push('/profile/change-password')}>Change</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Box>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<UpdateUserContactsForm contacts={me.contacts} />
|
||||
</TabPanel>
|
||||
{me.isStudent && (
|
||||
<TabPanel>
|
||||
<CourseList courses={me.courses} />
|
||||
</TabPanel>
|
||||
)}
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Box>
|
||||
<Box textAlign='center' mt='3'>
|
||||
<Button onClick={logout} w={{ base: 'full', sm: '150px' }}>
|
||||
Sign Out
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
import React, { useState, ReactNode } from 'react';
|
||||
import { CoursesPageContext, ProfilePageContext, StoreContext, UsersPageContext } from '@educt/contexts';
|
||||
import {
|
||||
CoursesPageContextType,
|
||||
ProfilePageDataType,
|
||||
ProfilePageStatusType,
|
||||
SearchingRoleStateType,
|
||||
} from '@educt/types';
|
||||
import { ChangeEmailPageContext, CoursesPageContext, StoreContext, UsersPageContext } from '@educt/contexts';
|
||||
import { ConfirmEmailDataType, SearchingRoleStateType } from '@educt/types';
|
||||
import RootStore from '@educt/stores/RootStore';
|
||||
import { ICategory, ICourse, IUser } from '@educt/interfaces';
|
||||
import { CourseStatusEnum } from '@educt/enums';
|
||||
@ -20,16 +15,16 @@ export const RootStoreProvider = ({ children }: { children: ReactNode }) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Profile page context provider
|
||||
* Change email page context provider
|
||||
*/
|
||||
export const ProfilePageContextProvider: React.FC = ({ children }) => {
|
||||
const [statusPageView, setStatusPageView] = useState<ProfilePageStatusType>('default');
|
||||
const [pageData, setPageData] = useState<ProfilePageDataType>({});
|
||||
export const ChangeEmailPageContextProvider: React.FC = ({ children }) => {
|
||||
const [isCodeSent, setIsCodeSent] = useState<boolean>(false);
|
||||
const [confirmEmailData, setConfirmEmailData] = useState<ConfirmEmailDataType | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<ProfilePageContext.Provider value={{ statusPageView, setStatusPageView, pageData, setPageData }}>
|
||||
<ChangeEmailPageContext.Provider value={{ isCodeSent, setIsCodeSent, confirmEmailData, setConfirmEmailData }}>
|
||||
{children}
|
||||
</ProfilePageContext.Provider>
|
||||
</ChangeEmailPageContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
39
src/types/index.d.ts
vendored
39
src/types/index.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { CourseStatusEnum, UserRoleEnum } from '@educt/enums';
|
||||
import { ICategory, ICourse, IUser } from '@educt/interfaces';
|
||||
import React from 'react';
|
||||
import { IconType } from 'react-icons/lib';
|
||||
|
||||
export type LinkType = {
|
||||
@ -23,35 +23,32 @@ export type AttachmentFileType = {
|
||||
extname: string;
|
||||
};
|
||||
|
||||
export type ConfirmEmailContainerDataType = {
|
||||
newEmail: string;
|
||||
expired_seconds: number;
|
||||
};
|
||||
|
||||
export type OptionType = {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type ProfilePageStatusType = 'update-password' | 'update-email' | 'confirm-email' | 'default';
|
||||
export type ProfilePageDataType = {
|
||||
/**
|
||||
* The field that is set when trying to change the mail address through form
|
||||
*/
|
||||
confirmEmailData?: ConfirmEmailContainerDataType;
|
||||
export type ConfirmEmailContainerDataType = {
|
||||
newEmail: string;
|
||||
expired_seconds: number;
|
||||
};
|
||||
export type ProfilePageContextType = {
|
||||
/**
|
||||
* Render current container by status
|
||||
*/
|
||||
statusPageView: ProfilePageStatusType;
|
||||
setStatusPageView: React.Dispatch<React.SetStateAction<ProfilePageStatusType>>;
|
||||
|
||||
/**
|
||||
* Some data for other components
|
||||
* Change email page context
|
||||
*/
|
||||
pageData: ProfilePageDataType;
|
||||
setPageData: React.Dispatch<React.SetStateAction<ProfilePageDataType>>;
|
||||
export type ConfirmEmailDataType = {
|
||||
newEmail: string;
|
||||
expired_seconds: number;
|
||||
};
|
||||
export type ChangeEmailPageContextType = {
|
||||
isCodeSent: boolean;
|
||||
setIsCodeSent: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
/**
|
||||
* Set this data when confirmation code has been sent
|
||||
*/
|
||||
confirmEmailData?: ConfirmEmailDataType;
|
||||
setConfirmEmailData: React.Dispatch<React.SetStateAction<ConfirmEmailDataType | undefined>>;
|
||||
};
|
||||
|
||||
export type SearchingRoleStateType = UserRoleEnum | 'any' | undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user