refactor: profile layout

This commit is contained in:
Sergey Yarkov 2022-02-02 21:32:44 +03:00
parent a14ed5eff9
commit ab662a50f6
10 changed files with 224 additions and 88 deletions

View File

@ -0,0 +1,12 @@
import { Flex, FlexProps } from '@chakra-ui/react';
import React from 'react';
const Base: React.FC<FlexProps> = props => {
return (
<Flex flexDir={{ base: 'column', md: 'row' }} {...props}>
{props.children}
</Flex>
);
};
export { Base };

View File

@ -0,0 +1,3 @@
import { Base } from './Base';
export { Base };

View File

@ -0,0 +1,8 @@
import React from 'react';
import { Flex } from '@chakra-ui/react';
const Entry: React.FC = props => {
return <Flex flexDir={{ base: 'column', md: 'row' }}>{props.children}</Flex>;
};
export { Entry };

View File

@ -0,0 +1,12 @@
import React from 'react';
import { Flex } from '@chakra-ui/react';
const EntryContent: React.FC = props => {
return (
<Flex flexDir={'column'} w='full' mt={{ base: '6', md: '0' }}>
{props.children}
</Flex>
);
};
export { EntryContent };

View File

@ -0,0 +1,31 @@
import React from 'react';
import { Box, BoxProps, Heading as ChakraHeading, Divider, Stack, StackDivider } from '@chakra-ui/react';
import { Title, ITitleProps } from './Title';
import { Entry } from './Entry';
import { EntryContent } from './EntryContent';
export interface ISettingsComposition {
Title: React.FC<ITitleProps & BoxProps>;
Entry: React.FC;
EntryContent: React.FC;
}
const Settings: React.FC<BoxProps> & ISettingsComposition = props => {
return (
<Box maxW={{ base: 'full', lg: '750px' }} {...props}>
<ChakraHeading as='h2' mt='12' fontSize={'2xl'} fontWeight={'bold'}>
Account Settings
</ChakraHeading>
<Divider my='5' />
<Stack divider={<StackDivider />} spacing={'5'}>
{props.children}
</Stack>
</Box>
);
};
Settings.Title = Title;
Settings.Entry = Entry;
Settings.EntryContent = EntryContent;
export { Settings };

View File

@ -0,0 +1,18 @@
import React from 'react';
import { Box, BoxProps, Heading } from '@chakra-ui/react';
export interface ITitleProps {
title?: string | undefined;
}
const Title: React.FC<ITitleProps & BoxProps> = props => {
return (
<Box minW='3xs' {...props}>
<Heading as='h2' fontWeight={'semibold'} fontSize={'lg'}>
{props.title}
</Heading>
</Box>
);
};
export { Title };

View File

@ -0,0 +1,3 @@
import { Settings } from './Settings';
export { Settings };

View File

@ -1,30 +1,37 @@
import React from 'react';
import { BoxProps, Flex, FlexProps } from '@chakra-ui/react';
import { Base } from './Base';
import { Avatar, ChatButton, IAvatarProps, IChatButtonProps } from './Avatar';
import { About, Details, Heading, IAboutProps, IDetailsProps, IHeadingProps, Info } from './Info';
import { Settings } from './Settings';
import { ISettingsComposition } from './Settings/Settings';
interface IUserProfileComposition {
Base: React.FC<FlexProps>;
Avatar: React.FC<IAvatarProps>;
ChatButton: React.FC<IChatButtonProps>;
Info: React.FC<BoxProps>;
Heading: React.FC<IHeadingProps>;
Details: React.FC<IDetailsProps>;
About: React.FC<IAboutProps>;
Settings: React.FC<BoxProps> & ISettingsComposition;
}
const UserProfile: React.FC<FlexProps> & IUserProfileComposition = props => {
return (
<Flex flexDir={{ base: 'column', md: 'row' }} {...props}>
<Flex flexDir={{ base: 'column' }} {...props}>
{props.children}
</Flex>
);
};
UserProfile.Base = Base;
UserProfile.Avatar = Avatar;
UserProfile.ChatButton = ChatButton;
UserProfile.Info = Info;
UserProfile.Heading = Heading;
UserProfile.Details = Details;
UserProfile.About = About;
UserProfile.Settings = Settings;
export { UserProfile };

View File

@ -1,16 +1,16 @@
import React from 'react';
import {
Tabs,
TabList,
Tab,
TabPanels,
TabPanel,
Button,
FormControl,
FormHelperText,
Input,
InputGroup,
InputRightElement,
Flex,
Switch,
FormControl,
FormLabel,
Input,
Textarea,
FormHelperText,
Select,
Button,
} from '@chakra-ui/react';
import { Box, Stack } from '@chakra-ui/layout';
@ -25,15 +25,13 @@ import { IPageProps } from '@educt/interfaces';
import { Page } from '@educt/components/PageElements';
import { ProfileLoading } from './components';
import { UserProfile } from '@educt/components/UserProfile';
import { CourseList } from './components/CourseList';
import UpdateUserContactsForm from '@educt/pages/profile/components/UpdateUserContactsForm';
/**
* Hooks
*/
import { useHistory } from 'react-router-dom';
import { useRootStore } from '@educt/hooks/useRootStore';
import { observer } from 'mobx-react';
import { MdOutlineSave } from 'react-icons/md';
/**
* Profile page
@ -42,7 +40,6 @@ const ProfilePage: React.FC<IPageProps> = () => {
const {
userStore: { me },
} = useRootStore();
const history = useHistory();
if (me === null) return <ProfileLoading />;
@ -51,76 +48,119 @@ const ProfilePage: React.FC<IPageProps> = () => {
<Page.Heading heading='My account' description='Update you contacts information or password here.' />
<Page.Content>
<UserProfile mt='14'>
<UserProfile.Avatar name={me.fullname} />
<UserProfile.Info>
<UserProfile.Heading fullname={me.fullname} roles={me.roles} />
<UserProfile.Details registered={me.created_at} lastLogin={me.last_login} />
<UserProfile.About about={me.about} />
</UserProfile.Info>
</UserProfile>
<Tabs mt='7'>
<TabList>
<Tab>Account information</Tab>
<Tab>My contacts</Tab>
{me.isStudent && <Tab>Available courses</Tab>}
</TabList>
<TabPanels mt='2'>
<TabPanel>
<form>
<Box borderRadius='md' borderWidth='1px' padding='5'>
<Stack spacing='5px'>
<FormControl isDisabled>
<FormHelperText color='gray.500'>First name</FormHelperText>
<Input type='text' value={me.first_name} size='md' variant='flushed' />
</FormControl>
<UserProfile.Base>
<UserProfile.Avatar name={me.fullname} />
<UserProfile.Info>
<UserProfile.Heading fullname={me.fullname} roles={me.roles} />
<UserProfile.Details registered={me.created_at} lastLogin={me.last_login} />
<UserProfile.About about={me.about} />
</UserProfile.Info>
</UserProfile.Base>
<FormControl isDisabled>
<FormHelperText color='gray.500'>Last name</FormHelperText>
<Input type='text' value={me.last_name} size='md' variant='flushed' />
</FormControl>
<UserProfile.Settings>
{/* Personal Info */}
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title title={'Personal Info'} />
<UserProfile.Settings.EntryContent>
<Stack spacing={'6'}>
<FormControl>
<FormLabel>Fullname</FormLabel>
<Input />
</FormControl>
<FormControl isReadOnly>
<FormLabel>Email</FormLabel>
<InputGroup size='md'>
<Input defaultValue={'serzh.yarkov@gmail.com'} />
<InputRightElement width='4.5rem' pr='0.5rem'>
<Button h='1.75rem' size='sm'>
Change
</Button>
</InputRightElement>
</InputGroup>
</FormControl>
<FormControl>
<FormLabel>About</FormLabel>
<Textarea minH='130px' maxH='500px' />
<FormHelperText>Write description for your profile.</FormHelperText>
</FormControl>
</Stack>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
<FormControl isDisabled>
<FormHelperText color='gray.500'>Email</FormHelperText>
<InputGroup>
<Input type='text' value={me.email} size='md' variant='flushed' />
<InputRightElement width='4rem'>
<Button size='sm' h='1.90rem' w='full' onClick={() => history.push('/profile/change-email')}>
Edit
</Button>
</InputRightElement>
</InputGroup>
</FormControl>
{/* Contacts */}
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title title={'Contacts'} />
<UserProfile.Settings.EntryContent>
<Stack spacing={'6'}>
<FormControl>
<FormLabel>Phone</FormLabel>
<Input placeholder='+1 (234) 555-1234' />
</FormControl>
<FormControl>
<FormLabel>Twitter</FormLabel>
<Input placeholder='@sergeyyarkov' />
</FormControl>
<FormControl>
<FormLabel>Telegram</FormLabel>
<Input placeholder='@sergeyyarkov' />
</FormControl>
</Stack>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
<FormControl isDisabled>
<FormHelperText color='gray.500'>Password</FormHelperText>
<InputGroup>
<Input type='text' value='**********' size='md' variant='flushed' />
<InputRightElement width='5rem'>
<Button
size='sm'
h='1.90rem'
w='full'
onClick={() => history.push('/profile/change-password')}
>
Change
</Button>
</InputRightElement>
</InputGroup>
</FormControl>
</Stack>
{/* Security */}
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title title='Security' />
<UserProfile.Settings.EntryContent>
<FormControl isReadOnly>
<FormLabel>Password</FormLabel>
<InputGroup size='md'>
<Input defaultValue={'**********'} />
<InputRightElement width='4.5rem' pr='0.5rem'>
<Button h='1.75rem' size='sm'>
Change
</Button>
</InputRightElement>
</InputGroup>
</FormControl>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
{/* Language */}
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title title='Language' />
<UserProfile.Settings.EntryContent>
<FormControl>
<FormLabel>Display Language</FormLabel>
<Select>
<option value='en'>English</option>
</Select>
</FormControl>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
{/* Night Theme */}
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title title='Night Theme' />
<UserProfile.Settings.EntryContent>
<Flex mt={{ base: '6', md: '0' }}>
<Switch size='lg' />
</Flex>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
<UserProfile.Settings.Entry>
<UserProfile.Settings.Title />
<UserProfile.Settings.EntryContent>
<Box>
<Button variant={'outline'} leftIcon={<MdOutlineSave />}>
Save
</Button>
</Box>
</form>
</TabPanel>
<TabPanel>
<UpdateUserContactsForm contacts={me.contacts} />
</TabPanel>
{me.isStudent && (
<TabPanel>
<CourseList courses={me.courses} />
</TabPanel>
)}
</TabPanels>
</Tabs>
</UserProfile.Settings.EntryContent>
</UserProfile.Settings.Entry>
</UserProfile.Settings>
</UserProfile>
</Page.Content>
</Page>
);

View File

@ -33,14 +33,16 @@ const UserPage: React.FC<IPageProps> = () => {
<Page>
<Page.Content maxW={'900px'}>
<UserProfile>
<UserProfile.Avatar name={user.fullname} isOnline>
<UserProfile.ChatButton userid={user.id} />
</UserProfile.Avatar>
<UserProfile.Info>
<UserProfile.Heading fullname={user.fullname} roles={user.roles} />
<UserProfile.Details registered={user.created_at} lastLogin={user.last_login} />
<UserProfile.About about={user.about} />
</UserProfile.Info>
<UserProfile.Base>
<UserProfile.Avatar name={user.fullname} isOnline>
<UserProfile.ChatButton userid={user.id} />
</UserProfile.Avatar>
<UserProfile.Info>
<UserProfile.Heading fullname={user.fullname} roles={user.roles} />
<UserProfile.Details registered={user.created_at} lastLogin={user.last_login} />
<UserProfile.About about={user.about} />
</UserProfile.Info>
</UserProfile.Base>
</UserProfile>
</Page.Content>
</Page>