feat: add primitive profile settings
This commit is contained in:

committed by
Ömer Faruk Aydın

parent
68e5e6d011
commit
140734b32c
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import Menu, { MenuProps } from '@mui/material/Menu';
|
import Menu, { MenuProps } from '@mui/material/Menu';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
import useAuthentication from 'hooks/useAuthentication';
|
import useAuthentication from 'hooks/useAuthentication';
|
||||||
@@ -49,7 +50,18 @@ function AccountDropdownMenu(props: AccountDropdownMenuProps): React.ReactElemen
|
|||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={logout}>{formatMessage('accountDropdownMenu.logout')}</MenuItem>
|
<MenuItem
|
||||||
|
component={Link}
|
||||||
|
to={URLS.SETTINGS_DASHBOARD}
|
||||||
|
>
|
||||||
|
{formatMessage('accountDropdownMenu.settings')}
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
<MenuItem
|
||||||
|
onClick={logout}
|
||||||
|
>
|
||||||
|
{formatMessage('accountDropdownMenu.logout')}
|
||||||
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -4,21 +4,28 @@ import { SwipeableDrawerProps } from '@mui/material/SwipeableDrawer';
|
|||||||
import Toolbar from '@mui/material/Toolbar';
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
import List from '@mui/material/List';
|
import List from '@mui/material/List';
|
||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import AppsIcon from '@mui/icons-material/Apps';
|
|
||||||
import SwapCallsIcon from '@mui/icons-material/SwapCalls';
|
|
||||||
import HistoryIcon from '@mui/icons-material/History';
|
|
||||||
import ExploreIcon from '@mui/icons-material/Explore';
|
|
||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
|
|
||||||
import ListItemLink from 'components/ListItemLink';
|
import ListItemLink from 'components/ListItemLink';
|
||||||
import HideOnScroll from 'components/HideOnScroll';
|
import HideOnScroll from 'components/HideOnScroll';
|
||||||
import useFormatMessage from 'hooks/useFormatMessage';
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
import * as URLS from 'config/urls';
|
|
||||||
import { Drawer as BaseDrawer } from './style';
|
import { Drawer as BaseDrawer } from './style';
|
||||||
|
|
||||||
const iOS = typeof navigator !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
const iOS = typeof navigator !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||||
|
|
||||||
export default function Drawer(props: SwipeableDrawerProps): React.ReactElement {
|
type DrawerLink = {
|
||||||
|
Icon: React.ElementType;
|
||||||
|
primary: string;
|
||||||
|
to: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DrawerProps = {
|
||||||
|
links: DrawerLink[];
|
||||||
|
bottomLinks?: DrawerLink[];
|
||||||
|
} & SwipeableDrawerProps;
|
||||||
|
|
||||||
|
export default function Drawer(props: DrawerProps): React.ReactElement {
|
||||||
|
const { links = [], bottomLinks = [], ...drawerProps } = props;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { noSsr: true });
|
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'), { noSsr: true });
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
@@ -31,46 +38,43 @@ export default function Drawer(props: SwipeableDrawerProps): React.ReactElement
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDrawer
|
<BaseDrawer
|
||||||
{...props}
|
{...drawerProps}
|
||||||
disableBackdropTransition={!iOS}
|
disableBackdropTransition={!iOS}
|
||||||
disableDiscovery={iOS}
|
disableDiscovery={iOS}
|
||||||
variant={matchSmallScreens ? 'temporary' : 'permanent'}
|
variant={matchSmallScreens ? 'temporary' : 'permanent'}
|
||||||
>
|
>
|
||||||
<HideOnScroll unmountOnExit>
|
{/* keep the following encapsulating `div` to have `space-between` children */}
|
||||||
<Toolbar />
|
<div>
|
||||||
</HideOnScroll>
|
<HideOnScroll unmountOnExit>
|
||||||
|
<Toolbar />
|
||||||
|
</HideOnScroll>
|
||||||
|
|
||||||
|
<List sx={{ py: 0, mt: 3 }}>
|
||||||
|
{links.map(({ Icon, primary, to }, index) => (
|
||||||
|
<ListItemLink
|
||||||
|
key={`${to}-${index}`}
|
||||||
|
icon={<Icon htmlColor={theme.palette.primary.main} />}
|
||||||
|
primary={formatMessage(primary)}
|
||||||
|
to={to}
|
||||||
|
onClick={closeOnClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
</div>
|
||||||
|
|
||||||
<List sx={{ py: 0, mt: 3 }}>
|
<List sx={{ py: 0, mt: 3 }}>
|
||||||
<ListItemLink
|
{bottomLinks.map(({ Icon, primary, to }, index) => (
|
||||||
icon={<SwapCallsIcon htmlColor={theme.palette.primary.main} />}
|
<ListItemLink
|
||||||
primary={formatMessage('drawer.flows')}
|
key={`${to}-${index}`}
|
||||||
to={URLS.FLOWS}
|
icon={<Icon htmlColor={theme.palette.primary.main} />}
|
||||||
onClick={closeOnClick}
|
primary={formatMessage(primary)}
|
||||||
/>
|
to={to}
|
||||||
|
onClick={closeOnClick}
|
||||||
<ListItemLink
|
/>
|
||||||
icon={<AppsIcon htmlColor={theme.palette.primary.main} />}
|
))}
|
||||||
primary={formatMessage('drawer.apps')}
|
|
||||||
to={URLS.APPS}
|
|
||||||
onClick={closeOnClick}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ListItemLink
|
|
||||||
icon={<HistoryIcon htmlColor={theme.palette.primary.main} />}
|
|
||||||
primary={formatMessage('drawer.executions')}
|
|
||||||
to={URLS.EXECUTIONS}
|
|
||||||
onClick={closeOnClick}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ListItemLink
|
|
||||||
icon={<ExploreIcon htmlColor={theme.palette.primary.main} />}
|
|
||||||
primary={formatMessage('drawer.explore')}
|
|
||||||
to={URLS.EXPLORE}
|
|
||||||
onClick={closeOnClick}
|
|
||||||
/>
|
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Divider />
|
|
||||||
</BaseDrawer>
|
</BaseDrawer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { styled, Theme, CSSObject } from '@mui/material/styles';
|
import { styled, Theme, CSSObject } from '@mui/material/styles';
|
||||||
|
import { drawerClasses } from '@mui/material/Drawer';
|
||||||
import MuiSwipeableDrawer from '@mui/material/SwipeableDrawer';
|
import MuiSwipeableDrawer from '@mui/material/SwipeableDrawer';
|
||||||
|
|
||||||
const drawerWidth = 300;
|
const drawerWidth = 300;
|
||||||
@@ -35,11 +36,19 @@ export const Drawer = styled(MuiSwipeableDrawer)(
|
|||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
...(open && {
|
...(open && {
|
||||||
...openedMixin(theme),
|
...openedMixin(theme),
|
||||||
'& .MuiDrawer-paper': openedMixin(theme),
|
[`& .${drawerClasses.paper}`]: {
|
||||||
|
...openedMixin(theme),
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
...(!open && {
|
...(!open && {
|
||||||
...closedMixin(theme),
|
...closedMixin(theme),
|
||||||
'& .MuiDrawer-paper': closedMixin(theme),
|
[`& .${drawerClasses.paper}`]: {
|
||||||
|
...closedMixin(theme),
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@@ -7,7 +7,7 @@ type FormProps = {
|
|||||||
defaultValues?: UseFormProps['defaultValues'];
|
defaultValues?: UseFormProps['defaultValues'];
|
||||||
onSubmit?: SubmitHandler<FieldValues>;
|
onSubmit?: SubmitHandler<FieldValues>;
|
||||||
render?: (props: UseFormReturn) => React.ReactNode;
|
render?: (props: UseFormReturn) => React.ReactNode;
|
||||||
}
|
};
|
||||||
|
|
||||||
const noop = () => null;
|
const noop = () => null;
|
||||||
|
|
||||||
|
@@ -1,16 +1,44 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
|
import AppsIcon from '@mui/icons-material/Apps';
|
||||||
|
import SwapCallsIcon from '@mui/icons-material/SwapCalls';
|
||||||
|
import HistoryIcon from '@mui/icons-material/History';
|
||||||
|
import ExploreIcon from '@mui/icons-material/Explore';
|
||||||
|
|
||||||
import Box from '@mui/material/Box';
|
import * as URLS from 'config/urls';
|
||||||
import AppBar from 'components/AppBar';
|
import AppBar from 'components/AppBar';
|
||||||
import Drawer from 'components/Drawer';
|
import Drawer from 'components/Drawer';
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
|
||||||
|
|
||||||
type PublicLayoutProps = {
|
type PublicLayoutProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drawerLinks = [
|
||||||
|
{
|
||||||
|
Icon: SwapCallsIcon,
|
||||||
|
primary: 'drawer.flows',
|
||||||
|
to: URLS.FLOWS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icon: AppsIcon,
|
||||||
|
primary: 'drawer.apps',
|
||||||
|
to: URLS.APPS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icon: HistoryIcon,
|
||||||
|
primary: 'drawer.executions',
|
||||||
|
to: URLS.EXECUTIONS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icon: ExploreIcon,
|
||||||
|
primary: 'drawer.explore',
|
||||||
|
to: URLS.EXPLORE,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function PublicLayout({ children }: PublicLayoutProps): React.ReactElement {
|
export default function PublicLayout({ children }: PublicLayoutProps): React.ReactElement {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'), { noSsr: true });
|
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'), { noSsr: true });
|
||||||
@@ -25,6 +53,7 @@ export default function PublicLayout({ children }: PublicLayoutProps): React.Rea
|
|||||||
|
|
||||||
<Box sx={{ display: 'flex', }}>
|
<Box sx={{ display: 'flex', }}>
|
||||||
<Drawer
|
<Drawer
|
||||||
|
links={drawerLinks}
|
||||||
open={isDrawerOpen}
|
open={isDrawerOpen}
|
||||||
onOpen={openDrawer}
|
onOpen={openDrawer}
|
||||||
onClose={closeDrawer}
|
onClose={closeDrawer}
|
||||||
|
@@ -14,7 +14,7 @@ type ListItemLinkProps = {
|
|||||||
|
|
||||||
export default function ListItemLink(props: ListItemLinkProps): React.ReactElement {
|
export default function ListItemLink(props: ListItemLinkProps): React.ReactElement {
|
||||||
const { icon, primary, to, onClick } = props;
|
const { icon, primary, to, onClick } = props;
|
||||||
const selected = useMatch({ path: to, end: false });
|
const selected = useMatch({ path: to, end: true });
|
||||||
|
|
||||||
const CustomLink = React.useMemo(
|
const CustomLink = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
62
packages/web/src/components/SettingsLayout/index.tsx
Normal file
62
packages/web/src/components/SettingsLayout/index.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
|
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||||
|
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
|
||||||
|
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
|
import AppBar from 'components/AppBar';
|
||||||
|
import Drawer from 'components/Drawer';
|
||||||
|
|
||||||
|
type SettingsLayoutProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawerLinks = [
|
||||||
|
{
|
||||||
|
Icon: AccountCircleIcon,
|
||||||
|
primary: 'settingsDrawer.myProfile',
|
||||||
|
to: URLS.SETTINGS_PROFILE,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const drawerBottomLinks = [
|
||||||
|
{
|
||||||
|
Icon: ArrowBackIosNewIcon,
|
||||||
|
primary: 'settingsDrawer.goBack',
|
||||||
|
to: '/',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function SettingsLayout({ children }: SettingsLayoutProps): React.ReactElement {
|
||||||
|
const theme = useTheme();
|
||||||
|
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('lg'), { noSsr: true });
|
||||||
|
const [isDrawerOpen, setDrawerOpen] = React.useState(!matchSmallScreens);
|
||||||
|
|
||||||
|
const openDrawer = () => setDrawerOpen(true);
|
||||||
|
const closeDrawer = () => setDrawerOpen(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AppBar drawerOpen={isDrawerOpen} onDrawerOpen={openDrawer} onDrawerClose={closeDrawer} />
|
||||||
|
|
||||||
|
<Box sx={{ display: 'flex', }}>
|
||||||
|
<Drawer
|
||||||
|
links={drawerLinks}
|
||||||
|
bottomLinks={drawerBottomLinks}
|
||||||
|
open={isDrawerOpen}
|
||||||
|
onOpen={openDrawer}
|
||||||
|
onClose={closeDrawer}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box sx={{ flex: 1, }}>
|
||||||
|
<Toolbar />
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@@ -29,5 +29,10 @@ export const FLOWS = '/flows';
|
|||||||
export const FLOW = (flowId: string): string => `/editor/${flowId}`;
|
export const FLOW = (flowId: string): string => `/editor/${flowId}`;
|
||||||
export const FLOW_PATTERN = '/flows/:flowId';
|
export const FLOW_PATTERN = '/flows/:flowId';
|
||||||
|
|
||||||
|
export const SETTINGS = '/settings';
|
||||||
|
export const SETTINGS_DASHBOARD = SETTINGS;
|
||||||
|
export const SETTINGS_PROFILE = '/settings/profile';
|
||||||
|
export const PROFILE = 'profile';
|
||||||
|
|
||||||
|
|
||||||
export const DASHBOARD = FLOWS;
|
export const DASHBOARD = FLOWS;
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
{
|
{
|
||||||
"brandText": "Automatisch",
|
"brandText": "Automatisch",
|
||||||
"searchPlaceholder": "Search",
|
"searchPlaceholder": "Search",
|
||||||
|
"accountDropdownMenu.settings": "Settings",
|
||||||
"accountDropdownMenu.logout": "Logout",
|
"accountDropdownMenu.logout": "Logout",
|
||||||
"drawer.dashboard": "Dashboard",
|
"drawer.dashboard": "Dashboard",
|
||||||
"drawer.flows": "Flows",
|
"drawer.flows": "Flows",
|
||||||
"drawer.apps": "My Apps",
|
"drawer.apps": "My Apps",
|
||||||
"drawer.executions": "Executions",
|
"drawer.executions": "Executions",
|
||||||
"drawer.explore": "Explore",
|
"drawer.explore": "Explore",
|
||||||
|
"settingsDrawer.myProfile": "My Profile",
|
||||||
|
"settingsDrawer.goBack": "Go to the dashboard",
|
||||||
"app.connectionCount": "{count} connections",
|
"app.connectionCount": "{count} connections",
|
||||||
"app.flowCount": "{count} flows",
|
"app.flowCount": "{count} flows",
|
||||||
"app.addConnection": "Add connection",
|
"app.addConnection": "Add connection",
|
||||||
@@ -38,5 +41,11 @@
|
|||||||
"flowStep.actionType": "Action",
|
"flowStep.actionType": "Action",
|
||||||
"flows.create": "Create flow",
|
"flows.create": "Create flow",
|
||||||
"flows.title": "Flows",
|
"flows.title": "Flows",
|
||||||
"executions.title": "Executions"
|
"executions.title": "Executions",
|
||||||
|
"profileSettings.title": "My Profile",
|
||||||
|
"profileSettings.email": "E-mail",
|
||||||
|
"profileSettings.updateEmail": "Update e-mail",
|
||||||
|
"profileSettings.newPassword": "New password",
|
||||||
|
"profileSettings.confirmNewPassword": "Confirm new password",
|
||||||
|
"profileSettings.updatePassword": "Update password"
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useQuery } from '@apollo/client';
|
import { useQuery } from '@apollo/client';
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
import type { IExecutionStep } from '@automatisch/types';
|
import type { IExecutionStep } from '@automatisch/types';
|
||||||
|
|
||||||
@@ -39,14 +38,12 @@ export default function Execution(): React.ReactElement {
|
|||||||
}, [executionId, fetchMore, pageInfo]);
|
}, [executionId, fetchMore, pageInfo]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ py: 3 }}>
|
<Container sx={{ py: 3 }}>
|
||||||
<Container>
|
<Grid container item sx={{ mb: [2, 5] }} rowGap={3}>
|
||||||
<Grid container item sx={{ mb: [2, 5] }} columnSpacing={1.5} rowGap={3}>
|
{executionSteps?.map((executionStep) => (
|
||||||
{executionSteps?.map((executionStep) => (
|
<ExecutionStep key={executionStep.id} executionStep={executionStep} step={executionStep.step} />
|
||||||
<ExecutionStep key={executionStep.id} executionStep={executionStep} step={executionStep.step} />
|
))}
|
||||||
))}
|
</Grid>
|
||||||
</Grid>
|
</Container>
|
||||||
</Container>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
77
packages/web/src/pages/ProfileSettings/index.tsx
Normal file
77
packages/web/src/pages/ProfileSettings/index.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
|
import PageTitle from 'components/PageTitle';
|
||||||
|
import Container from 'components/Container';
|
||||||
|
import Form from 'components/Form';
|
||||||
|
import TextField from 'components/TextField';
|
||||||
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
|
||||||
|
const StyledForm = styled(Form)`
|
||||||
|
display: flex;
|
||||||
|
align-items: end;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
function ProfileSettings() {
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<Grid container item xs={12} sm={9} md={6}>
|
||||||
|
<Grid item xs={12} sx={{ mb: [2, 5] }} >
|
||||||
|
<PageTitle>
|
||||||
|
{formatMessage('profileSettings.title')}
|
||||||
|
</PageTitle>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} justifyContent="flex-end">
|
||||||
|
<StyledForm>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="email"
|
||||||
|
label={formatMessage('profileSettings.email')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{ mt: 2 }}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{formatMessage('profileSettings.updateEmail')}
|
||||||
|
</Button>
|
||||||
|
</StyledForm>
|
||||||
|
|
||||||
|
<StyledForm>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="password"
|
||||||
|
label={formatMessage('profileSettings.newPassword')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="confirmPassword"
|
||||||
|
label={formatMessage('profileSettings.confirmNewPassword')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{ mt: 2 }}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{formatMessage('profileSettings.updatePassword')}
|
||||||
|
</Button>
|
||||||
|
</StyledForm>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProfileSettings;
|
@@ -11,6 +11,7 @@ import Explore from 'pages/Explore';
|
|||||||
import Login from 'pages/Login';
|
import Login from 'pages/Login';
|
||||||
import EditorRoutes from 'pages/Editor/routes';
|
import EditorRoutes from 'pages/Editor/routes';
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
|
import settingsRoutes from './settingsRoutes';
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
<Routes>
|
<Routes>
|
||||||
@@ -34,6 +35,10 @@ export default (
|
|||||||
|
|
||||||
<Route path="/" element={<Navigate to={URLS.FLOWS} />} />
|
<Route path="/" element={<Navigate to={URLS.FLOWS} />} />
|
||||||
|
|
||||||
|
<Route path={`${URLS.SETTINGS}`}>
|
||||||
|
{settingsRoutes}
|
||||||
|
</Route>
|
||||||
|
|
||||||
<Route element={<Layout><div>404</div></Layout>} />
|
<Route element={<Layout><div>404</div></Layout>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
13
packages/web/src/settingsRoutes.tsx
Normal file
13
packages/web/src/settingsRoutes.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Route, Navigate } from 'react-router-dom';
|
||||||
|
import SettingsLayout from 'components/SettingsLayout';
|
||||||
|
import ProfileSettings from 'pages/ProfileSettings';
|
||||||
|
|
||||||
|
import * as URLS from 'config/urls';
|
||||||
|
|
||||||
|
export default (
|
||||||
|
<>
|
||||||
|
<Route path={URLS.SETTINGS_PROFILE} element={<SettingsLayout><ProfileSettings /></SettingsLayout>} />
|
||||||
|
|
||||||
|
<Route path={URLS.SETTINGS} element={<Navigate to={URLS.SETTINGS_PROFILE} />} />
|
||||||
|
</>
|
||||||
|
);
|
Reference in New Issue
Block a user