mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
refactor: profile layout
This commit is contained in:
parent
a14ed5eff9
commit
ab662a50f6
12
src/components/UserProfile/Base/Base.tsx
Normal file
12
src/components/UserProfile/Base/Base.tsx
Normal 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 };
|
||||||
3
src/components/UserProfile/Base/index.ts
Normal file
3
src/components/UserProfile/Base/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { Base } from './Base';
|
||||||
|
|
||||||
|
export { Base };
|
||||||
8
src/components/UserProfile/Settings/Entry.tsx
Normal file
8
src/components/UserProfile/Settings/Entry.tsx
Normal 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 };
|
||||||
12
src/components/UserProfile/Settings/EntryContent.tsx
Normal file
12
src/components/UserProfile/Settings/EntryContent.tsx
Normal 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 };
|
||||||
31
src/components/UserProfile/Settings/Settings.tsx
Normal file
31
src/components/UserProfile/Settings/Settings.tsx
Normal 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 };
|
||||||
18
src/components/UserProfile/Settings/Title.tsx
Normal file
18
src/components/UserProfile/Settings/Title.tsx
Normal 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 };
|
||||||
3
src/components/UserProfile/Settings/index.ts
Normal file
3
src/components/UserProfile/Settings/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { Settings } from './Settings';
|
||||||
|
|
||||||
|
export { Settings };
|
||||||
@ -1,30 +1,37 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BoxProps, Flex, FlexProps } from '@chakra-ui/react';
|
import { BoxProps, Flex, FlexProps } from '@chakra-ui/react';
|
||||||
|
import { Base } from './Base';
|
||||||
import { Avatar, ChatButton, IAvatarProps, IChatButtonProps } from './Avatar';
|
import { Avatar, ChatButton, IAvatarProps, IChatButtonProps } from './Avatar';
|
||||||
import { About, Details, Heading, IAboutProps, IDetailsProps, IHeadingProps, Info } from './Info';
|
import { About, Details, Heading, IAboutProps, IDetailsProps, IHeadingProps, Info } from './Info';
|
||||||
|
import { Settings } from './Settings';
|
||||||
|
import { ISettingsComposition } from './Settings/Settings';
|
||||||
|
|
||||||
interface IUserProfileComposition {
|
interface IUserProfileComposition {
|
||||||
|
Base: React.FC<FlexProps>;
|
||||||
Avatar: React.FC<IAvatarProps>;
|
Avatar: React.FC<IAvatarProps>;
|
||||||
ChatButton: React.FC<IChatButtonProps>;
|
ChatButton: React.FC<IChatButtonProps>;
|
||||||
Info: React.FC<BoxProps>;
|
Info: React.FC<BoxProps>;
|
||||||
Heading: React.FC<IHeadingProps>;
|
Heading: React.FC<IHeadingProps>;
|
||||||
Details: React.FC<IDetailsProps>;
|
Details: React.FC<IDetailsProps>;
|
||||||
About: React.FC<IAboutProps>;
|
About: React.FC<IAboutProps>;
|
||||||
|
Settings: React.FC<BoxProps> & ISettingsComposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserProfile: React.FC<FlexProps> & IUserProfileComposition = props => {
|
const UserProfile: React.FC<FlexProps> & IUserProfileComposition = props => {
|
||||||
return (
|
return (
|
||||||
<Flex flexDir={{ base: 'column', md: 'row' }} {...props}>
|
<Flex flexDir={{ base: 'column' }} {...props}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UserProfile.Base = Base;
|
||||||
UserProfile.Avatar = Avatar;
|
UserProfile.Avatar = Avatar;
|
||||||
UserProfile.ChatButton = ChatButton;
|
UserProfile.ChatButton = ChatButton;
|
||||||
UserProfile.Info = Info;
|
UserProfile.Info = Info;
|
||||||
UserProfile.Heading = Heading;
|
UserProfile.Heading = Heading;
|
||||||
UserProfile.Details = Details;
|
UserProfile.Details = Details;
|
||||||
UserProfile.About = About;
|
UserProfile.About = About;
|
||||||
|
UserProfile.Settings = Settings;
|
||||||
|
|
||||||
export { UserProfile };
|
export { UserProfile };
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Tabs,
|
|
||||||
TabList,
|
|
||||||
Tab,
|
|
||||||
TabPanels,
|
|
||||||
TabPanel,
|
|
||||||
Button,
|
|
||||||
FormControl,
|
|
||||||
FormHelperText,
|
|
||||||
Input,
|
|
||||||
InputGroup,
|
InputGroup,
|
||||||
InputRightElement,
|
InputRightElement,
|
||||||
|
Flex,
|
||||||
|
Switch,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
Input,
|
||||||
|
Textarea,
|
||||||
|
FormHelperText,
|
||||||
|
Select,
|
||||||
|
Button,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { Box, Stack } from '@chakra-ui/layout';
|
import { Box, Stack } from '@chakra-ui/layout';
|
||||||
|
|
||||||
@ -25,15 +25,13 @@ import { IPageProps } from '@educt/interfaces';
|
|||||||
import { Page } from '@educt/components/PageElements';
|
import { Page } from '@educt/components/PageElements';
|
||||||
import { ProfileLoading } from './components';
|
import { ProfileLoading } from './components';
|
||||||
import { UserProfile } from '@educt/components/UserProfile';
|
import { UserProfile } from '@educt/components/UserProfile';
|
||||||
import { CourseList } from './components/CourseList';
|
|
||||||
import UpdateUserContactsForm from '@educt/pages/profile/components/UpdateUserContactsForm';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks
|
* Hooks
|
||||||
*/
|
*/
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
import { useRootStore } from '@educt/hooks/useRootStore';
|
import { useRootStore } from '@educt/hooks/useRootStore';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
import { MdOutlineSave } from 'react-icons/md';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Profile page
|
* Profile page
|
||||||
@ -42,7 +40,6 @@ const ProfilePage: React.FC<IPageProps> = () => {
|
|||||||
const {
|
const {
|
||||||
userStore: { me },
|
userStore: { me },
|
||||||
} = useRootStore();
|
} = useRootStore();
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
if (me === null) return <ProfileLoading />;
|
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.Heading heading='My account' description='Update you contacts information or password here.' />
|
||||||
<Page.Content>
|
<Page.Content>
|
||||||
<UserProfile mt='14'>
|
<UserProfile mt='14'>
|
||||||
<UserProfile.Avatar name={me.fullname} />
|
<UserProfile.Base>
|
||||||
<UserProfile.Info>
|
<UserProfile.Avatar name={me.fullname} />
|
||||||
<UserProfile.Heading fullname={me.fullname} roles={me.roles} />
|
<UserProfile.Info>
|
||||||
<UserProfile.Details registered={me.created_at} lastLogin={me.last_login} />
|
<UserProfile.Heading fullname={me.fullname} roles={me.roles} />
|
||||||
<UserProfile.About about={me.about} />
|
<UserProfile.Details registered={me.created_at} lastLogin={me.last_login} />
|
||||||
</UserProfile.Info>
|
<UserProfile.About about={me.about} />
|
||||||
</UserProfile>
|
</UserProfile.Info>
|
||||||
<Tabs mt='7'>
|
</UserProfile.Base>
|
||||||
<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>
|
|
||||||
|
|
||||||
<FormControl isDisabled>
|
<UserProfile.Settings>
|
||||||
<FormHelperText color='gray.500'>Last name</FormHelperText>
|
{/* Personal Info */}
|
||||||
<Input type='text' value={me.last_name} size='md' variant='flushed' />
|
<UserProfile.Settings.Entry>
|
||||||
</FormControl>
|
<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>
|
{/* Contacts */}
|
||||||
<FormHelperText color='gray.500'>Email</FormHelperText>
|
<UserProfile.Settings.Entry>
|
||||||
<InputGroup>
|
<UserProfile.Settings.Title title={'Contacts'} />
|
||||||
<Input type='text' value={me.email} size='md' variant='flushed' />
|
<UserProfile.Settings.EntryContent>
|
||||||
<InputRightElement width='4rem'>
|
<Stack spacing={'6'}>
|
||||||
<Button size='sm' h='1.90rem' w='full' onClick={() => history.push('/profile/change-email')}>
|
<FormControl>
|
||||||
Edit
|
<FormLabel>Phone</FormLabel>
|
||||||
</Button>
|
<Input placeholder='+1 (234) 555-1234' />
|
||||||
</InputRightElement>
|
</FormControl>
|
||||||
</InputGroup>
|
<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>
|
{/* Security */}
|
||||||
<FormHelperText color='gray.500'>Password</FormHelperText>
|
<UserProfile.Settings.Entry>
|
||||||
<InputGroup>
|
<UserProfile.Settings.Title title='Security' />
|
||||||
<Input type='text' value='**********' size='md' variant='flushed' />
|
<UserProfile.Settings.EntryContent>
|
||||||
<InputRightElement width='5rem'>
|
<FormControl isReadOnly>
|
||||||
<Button
|
<FormLabel>Password</FormLabel>
|
||||||
size='sm'
|
<InputGroup size='md'>
|
||||||
h='1.90rem'
|
<Input defaultValue={'**********'} />
|
||||||
w='full'
|
<InputRightElement width='4.5rem' pr='0.5rem'>
|
||||||
onClick={() => history.push('/profile/change-password')}
|
<Button h='1.75rem' size='sm'>
|
||||||
>
|
Change
|
||||||
Change
|
</Button>
|
||||||
</Button>
|
</InputRightElement>
|
||||||
</InputRightElement>
|
</InputGroup>
|
||||||
</InputGroup>
|
</FormControl>
|
||||||
</FormControl>
|
</UserProfile.Settings.EntryContent>
|
||||||
</Stack>
|
</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>
|
</Box>
|
||||||
</form>
|
</UserProfile.Settings.EntryContent>
|
||||||
</TabPanel>
|
</UserProfile.Settings.Entry>
|
||||||
<TabPanel>
|
</UserProfile.Settings>
|
||||||
<UpdateUserContactsForm contacts={me.contacts} />
|
</UserProfile>
|
||||||
</TabPanel>
|
|
||||||
{me.isStudent && (
|
|
||||||
<TabPanel>
|
|
||||||
<CourseList courses={me.courses} />
|
|
||||||
</TabPanel>
|
|
||||||
)}
|
|
||||||
</TabPanels>
|
|
||||||
</Tabs>
|
|
||||||
</Page.Content>
|
</Page.Content>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -33,14 +33,16 @@ const UserPage: React.FC<IPageProps> = () => {
|
|||||||
<Page>
|
<Page>
|
||||||
<Page.Content maxW={'900px'}>
|
<Page.Content maxW={'900px'}>
|
||||||
<UserProfile>
|
<UserProfile>
|
||||||
<UserProfile.Avatar name={user.fullname} isOnline>
|
<UserProfile.Base>
|
||||||
<UserProfile.ChatButton userid={user.id} />
|
<UserProfile.Avatar name={user.fullname} isOnline>
|
||||||
</UserProfile.Avatar>
|
<UserProfile.ChatButton userid={user.id} />
|
||||||
<UserProfile.Info>
|
</UserProfile.Avatar>
|
||||||
<UserProfile.Heading fullname={user.fullname} roles={user.roles} />
|
<UserProfile.Info>
|
||||||
<UserProfile.Details registered={user.created_at} lastLogin={user.last_login} />
|
<UserProfile.Heading fullname={user.fullname} roles={user.roles} />
|
||||||
<UserProfile.About about={user.about} />
|
<UserProfile.Details registered={user.created_at} lastLogin={user.last_login} />
|
||||||
</UserProfile.Info>
|
<UserProfile.About about={user.about} />
|
||||||
|
</UserProfile.Info>
|
||||||
|
</UserProfile.Base>
|
||||||
</UserProfile>
|
</UserProfile>
|
||||||
</Page.Content>
|
</Page.Content>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user