diff --git a/src/App.tsx b/src/App.tsx index 7c635de..237cb83 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -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]} /> - + + + { - 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} > diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 4585475..8d28180 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -44,24 +44,7 @@ const Layout: React.FC = ({ children, roles }) => {
- + }> {(() => { /** diff --git a/src/components/Nav/Desktop/index.tsx b/src/components/Nav/Desktop/index.tsx index 24c2762..02a9e5c 100644 --- a/src/components/Nav/Desktop/index.tsx +++ b/src/components/Nav/Desktop/index.tsx @@ -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 ( - { > - + + + Learning Management System
Made by Sergey Yarkov +
+ + + + + + + +
+ ); } return null; diff --git a/src/contexts/index.ts b/src/contexts/index.ts index cc7afd6..4a1b5e4 100644 --- a/src/contexts/index.ts +++ b/src/contexts/index.ts @@ -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(undefined); -export const ProfilePageContext = createContext({ - statusPageView: 'default', - setStatusPageView: () => {}, - pageData: {}, - setPageData: () => {}, +export const ChangeEmailPageContext = createContext({ + isCodeSent: false, + setIsCodeSent: () => {}, + confirmEmailData: undefined, + setConfirmEmailData: () => {}, }); export const UsersPageContext = createContext({ diff --git a/src/pages/courses/components/CourseList/CourseList.tsx b/src/pages/courses/components/CourseList/CourseList.tsx index 054521c..5fad702 100644 --- a/src/pages/courses/components/CourseList/CourseList.tsx +++ b/src/pages/courses/components/CourseList/CourseList.tsx @@ -88,7 +88,7 @@ const CourseList: React.FC = ({ courses, isLoading }) => { <> {deletingCourse && } {courses.length !== 0 ? ( - + {/* Render items */} {courses.map(course => ( diff --git a/src/pages/profile/change-email/change-email.tsx b/src/pages/profile/change-email/change-email.tsx new file mode 100644 index 0000000..9ebfec1 --- /dev/null +++ b/src/pages/profile/change-email/change-email.tsx @@ -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 ? ( + + ) : ( + confirmEmailData && + )} + */ +} + +/** + * Change email page + */ +const ChangeEmailPage: React.FC = () => { + const { + userStore: { me }, + } = useRootStore(); + const history = useHistory(); + + if (me === null) return ; + + return ( + + + {({ isCodeSent, confirmEmailData }) => ( + <> + {!isCodeSent ? ( + + + } + onClick={() => history.push('/profile')} + mr='5' + /> + Edit email address + + + Type your new email address. + + + + ) : ( + confirmEmailData && + )} + + )} + + + ); +}; + +export default observer(ChangeEmailPage); diff --git a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx b/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx similarity index 60% rename from src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx rename to src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx index 5e9aaa8..6cc11ad 100644 --- a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.tsx +++ b/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx @@ -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(null); - const { setStatusPageView, setPageData } = useContext(ProfilePageContext); - const { userStore } = useRootStore(); +const UpdateEmailForm: React.FC = ({ currentEmail }) => { + const [newEmail, setNewEmail] = useState(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 = ({ email }) => { - setEmail(email); - sendConfirmationCode(email); + /** + * Submit form handler + */ + const onSubmit: SubmitHandler = async ({ email }) => { + /** + * Set new email state and send confirmation code + */ + setNewEmail(email); + await sendConfirmationCode(email); }; return ( @@ -48,7 +77,7 @@ const UpdateEmailForm: React.FC = () => { Current email - + New email diff --git a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.validator.ts b/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.validator.ts similarity index 100% rename from src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/UpdateEmailForm.validator.ts rename to src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.validator.ts diff --git a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/index.ts b/src/pages/profile/change-email/components/UpdateEmailForm/index.ts similarity index 100% rename from src/pages/profile/containers/UpdateEmailContainer/UpdateEmailForm/index.ts rename to src/pages/profile/change-email/components/UpdateEmailForm/index.ts diff --git a/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx b/src/pages/profile/change-email/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx similarity index 93% rename from src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx rename to src/pages/profile/change-email/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx index 5efc44f..693c418 100644 --- a/src/pages/profile/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx +++ b/src/pages/profile/change-email/containers/ConfirmEmailContainer/ConfirmEmailContainer.tsx @@ -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 = ({ data }) => { const { userStore } = useRootStore(); - const { setStatusPageView } = useContext(ProfilePageContext); const { sendConfirmationCode, loading } = useUpdateUserEmailQuery(); const [isVerifying, setIsVerifying] = useState(false); const [code, setCode] = useState(''); @@ -24,6 +32,7 @@ const ConfirmEmailContainer: React.FC = ({ 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 = ({ data status: 'info', }); if (isMountedRef.current) { - setStatusPageView('default'); + history.push('/profile'); } } catch (error: any) { if (error.response) { diff --git a/src/pages/profile/containers/ConfirmEmailContainer/index.ts b/src/pages/profile/change-email/containers/ConfirmEmailContainer/index.ts similarity index 100% rename from src/pages/profile/containers/ConfirmEmailContainer/index.ts rename to src/pages/profile/change-email/containers/ConfirmEmailContainer/index.ts diff --git a/src/pages/profile/change-password/change-password.tsx b/src/pages/profile/change-password/change-password.tsx new file mode 100644 index 0000000..d159591 --- /dev/null +++ b/src/pages/profile/change-password/change-password.tsx @@ -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 = () => { + const { + userStore: { me }, + } = useRootStore(); + const history = useHistory(); + + if (me === null) return ; + + return ( + + + } + onClick={() => history.push('/profile')} + mr='5' + /> + Update password + + + Your new password must be different from the current one. + + + + ); +}; + +export default observer(ChangePasswordPage); diff --git a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/UpdatePasswordForm.tsx b/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx similarity index 83% rename from src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/UpdatePasswordForm.tsx rename to src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx index 3fbec06..4acb56b 100644 --- a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/UpdatePasswordForm.tsx +++ b/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx @@ -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(false); + const [isLoading, setIsLoading] = useState(false); const { handleSubmit, register, @@ -35,19 +48,25 @@ const UpdatePasswordForm: React.FC = () => { } = useForm({ resolver: yupResolver(UpdatePasswordSchema), }); - + const history = useHistory(); const toast = useToast(); const handleError = useErrorHandler(); + /** + * Submit form handler + */ const onSubmit: SubmitHandler = 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')} /> Type your current password. @@ -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')} /> @@ -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')} /> @@ -116,7 +135,7 @@ const UpdatePasswordForm: React.FC = () => { type='submit' size='md' variant='outline' - isLoading={loading} + isLoading={isLoading} loadingText='Saving...' > Change diff --git a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/UpdatePasswordForm.validator.ts b/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.validator.ts similarity index 100% rename from src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/UpdatePasswordForm.validator.ts rename to src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.validator.ts diff --git a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/index.ts b/src/pages/profile/change-password/components/UpdatePasswordForm/index.ts similarity index 100% rename from src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordForm/index.ts rename to src/pages/profile/change-password/components/UpdatePasswordForm/index.ts diff --git a/src/pages/profile/components/CourseList/CourseItem.tsx b/src/pages/profile/components/CourseList/CourseItem.tsx index c15a3fb..d2dc475 100644 --- a/src/pages/profile/components/CourseList/CourseItem.tsx +++ b/src/pages/profile/components/CourseList/CourseItem.tsx @@ -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 = ({ course }) => { return ( - - - {course.category.title} - - - - {course.title} - - + + + {course.title} + {course.description} - + {course.lessons_count} lessons @@ -46,7 +34,40 @@ const CourseItem: React.FC = ({ course }) => { {course.likes_count} likes - + + + // + // + // {course.category.title} + // + // + // + // {course.title} + // + // + // {course.description} + // + // + // + // {course.lessons_count} lessons + // + // + // + // {course.students_count} students + // + // + // + // {course.likes_count} likes + // + // + // ); }; diff --git a/src/pages/profile/components/CourseList/CourseList.tsx b/src/pages/profile/components/CourseList/CourseList.tsx index 97db274..26ea9ee 100644 --- a/src/pages/profile/components/CourseList/CourseList.tsx +++ b/src/pages/profile/components/CourseList/CourseList.tsx @@ -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 = ({ courses }) => { - if (courses === undefined) { - return null; - } + if (courses === undefined) return null; if (courses.length === 0) { return ( @@ -31,7 +29,7 @@ const CourseList: React.FC = ({ courses }) => { } return ( - + {courses.map(course => ( ))} diff --git a/src/pages/profile/components/UserAccountInfo/UserAccountInfo.tsx b/src/pages/profile/components/UserAccountInfo/UserAccountInfo.tsx deleted file mode 100644 index 672a2af..0000000 --- a/src/pages/profile/components/UserAccountInfo/UserAccountInfo.tsx +++ /dev/null @@ -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 = ({ user }) => { - const { setStatusPageView } = useContext(ProfilePageContext); - - return ( - - }> - - - - First Name - - - {user.first_name} - - - - - - - Last Name - - - {user.last_name} - - - - - - - Email - - - {user.email} - - - - - - - - Password - - - ********** - - - - - - - ); -}; - -export default UserAccountInfo; diff --git a/src/pages/profile/components/UserAccountInfo/index.ts b/src/pages/profile/components/UserAccountInfo/index.ts deleted file mode 100644 index 53711b5..0000000 --- a/src/pages/profile/components/UserAccountInfo/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import UserAccountInfo from './UserAccountInfo'; - -export default UserAccountInfo; diff --git a/src/pages/profile/containers/MainContainer/MainContainer.tsx b/src/pages/profile/containers/MainContainer/MainContainer.tsx deleted file mode 100644 index a3faa31..0000000 --- a/src/pages/profile/containers/MainContainer/MainContainer.tsx +++ /dev/null @@ -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 ( - - My account - Update you contacts information or password here. - - - - - - {me.fullname} - - - {me.email} - - - - - - - - - Account information - My contacts - {me.isStudent && Available courses} - - - - - - - - - {me.isStudent && ( - - - - )} - - - - - - - - ); -}; - -export default MainContainer; diff --git a/src/pages/profile/containers/MainContainer/index.ts b/src/pages/profile/containers/MainContainer/index.ts deleted file mode 100644 index 416f536..0000000 --- a/src/pages/profile/containers/MainContainer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import MainContainer from './MainContainer'; - -export default MainContainer; diff --git a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailContainer.tsx b/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailContainer.tsx deleted file mode 100644 index d86108c..0000000 --- a/src/pages/profile/containers/UpdateEmailContainer/UpdateEmailContainer.tsx +++ /dev/null @@ -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 ( - - - } - onClick={() => setStatusPageView('default')} - mr='5' - /> - Edit email address - - - Type your new email address. - - - - ); -}; - -export default UpdateEmailContainer; diff --git a/src/pages/profile/containers/UpdateEmailContainer/index.ts b/src/pages/profile/containers/UpdateEmailContainer/index.ts deleted file mode 100644 index 818243b..0000000 --- a/src/pages/profile/containers/UpdateEmailContainer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import UpdateEmailContainer from './UpdateEmailContainer'; - -export default UpdateEmailContainer; diff --git a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordContainer.tsx b/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordContainer.tsx deleted file mode 100644 index 21d18e2..0000000 --- a/src/pages/profile/containers/UpdatePasswordContainer/UpdatePasswordContainer.tsx +++ /dev/null @@ -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 ( - - - } - onClick={() => setStatusPageView('default')} - mr='5' - /> - Update password - - - Your new password must be different from the current one. - - - - ); -}; - -export default UpdatePasswordContainer; diff --git a/src/pages/profile/containers/UpdatePasswordContainer/index.ts b/src/pages/profile/containers/UpdatePasswordContainer/index.ts deleted file mode 100644 index 37feee6..0000000 --- a/src/pages/profile/containers/UpdatePasswordContainer/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import UpdatePasswordContainer from './UpdatePasswordContainer'; - -export default UpdatePasswordContainer; diff --git a/src/pages/profile/profile.tsx b/src/pages/profile/profile.tsx index 6d4a7b0..a8de10f 100644 --- a/src/pages/profile/profile.tsx +++ b/src/pages/profile/profile.tsx @@ -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 = () => { 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 ; - } + if (me === null) return ; return ( - - - {({ statusPageView, pageData }) => { - switch (statusPageView) { - case 'default': - return ; - case 'update-password': - return ; - case 'update-email': - return ; - case 'confirm-email': - return pageData.confirmEmailData && ; - default: - return null; - } - }} - - + + My account + Update you contacts information or password here. + + + + + + {me.fullname} + + + {me.email} + + + + + + + + + Account information + My contacts + {me.isStudent && Available courses} + + + + + }> + + + + First Name + + + {me.first_name} + + + + + + + Last Name + + + {me.last_name} + + + + + + + Email + + + {me.email} + + + + + + + + Password + + + ********** + + + + + + + + + + + {me.isStudent && ( + + + + )} + + + + + + + ); }; diff --git a/src/providers/index.tsx b/src/providers/index.tsx index 38bba7b..8ebcc45 100644 --- a/src/providers/index.tsx +++ b/src/providers/index.tsx @@ -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('default'); - const [pageData, setPageData] = useState({}); +export const ChangeEmailPageContextProvider: React.FC = ({ children }) => { + const [isCodeSent, setIsCodeSent] = useState(false); + const [confirmEmailData, setConfirmEmailData] = useState(undefined); return ( - + {children} - + ); }; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 19674b8..625c7e1 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -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>; + +/** + * Change email page context + */ +export type ConfirmEmailDataType = { + newEmail: string; + expired_seconds: number; +}; +export type ChangeEmailPageContextType = { + isCodeSent: boolean; + setIsCodeSent: React.Dispatch>; /** - * Some data for other components + * Set this data when confirmation code has been sent */ - pageData: ProfilePageDataType; - setPageData: React.Dispatch>; + confirmEmailData?: ConfirmEmailDataType; + setConfirmEmailData: React.Dispatch>; }; export type SearchingRoleStateType = UserRoleEnum | 'any' | undefined;