mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
Add theme toggle to user profile
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
afb2c8e3fc
commit
3a74150d3a
@ -1,9 +1,6 @@
|
||||
import darkTheme from './temp-dark-theme';
|
||||
|
||||
export default {
|
||||
config: {
|
||||
locales: ['fr'],
|
||||
theme: darkTheme,
|
||||
},
|
||||
bootstrap() {},
|
||||
};
|
||||
|
@ -5,10 +5,10 @@ import { useThemeToggle } from '../../hooks';
|
||||
import GlobalStyle from '../GlobalStyle';
|
||||
|
||||
const Theme = ({ children }) => {
|
||||
const { currentTheme } = useThemeToggle();
|
||||
const { currentTheme, themes } = useThemeToggle();
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={currentTheme}>
|
||||
<ThemeProvider theme={themes[currentTheme] || themes.light}>
|
||||
{children}
|
||||
<GlobalStyle />
|
||||
</ThemeProvider>
|
||||
|
@ -9,14 +9,14 @@ import PropTypes from 'prop-types';
|
||||
import { ThemeToggleContext } from '../../contexts';
|
||||
|
||||
const ThemeToggleProvider = ({ children, themes }) => {
|
||||
const [currentTheme, setCurrentTheme] = useState(themes.light);
|
||||
const [currentTheme, setCurrentTheme] = useState('light');
|
||||
|
||||
const handleChangeTheme = nextTheme => {
|
||||
setCurrentTheme(themes[nextTheme]);
|
||||
setCurrentTheme(nextTheme);
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeToggleContext.Provider value={{ currentTheme, onChangeTheme: handleChangeTheme }}>
|
||||
<ThemeToggleContext.Provider value={{ currentTheme, onChangeTheme: handleChangeTheme, themes }}>
|
||||
{children}
|
||||
</ThemeToggleContext.Provider>
|
||||
);
|
||||
|
@ -12,9 +12,9 @@ import {
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Formik } from 'formik';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
||||
import pick from 'lodash/pick';
|
||||
import omit from 'lodash/omit';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Main } from '@strapi/design-system/Main';
|
||||
import { Typography } from '@strapi/design-system/Typography';
|
||||
@ -31,6 +31,7 @@ import Eye from '@strapi/icons/Eye';
|
||||
import EyeStriked from '@strapi/icons/EyeStriked';
|
||||
import Check from '@strapi/icons/Check';
|
||||
import useLocalesProvider from '../../components/LocalesProvider/useLocalesProvider';
|
||||
import { useThemeToggle } from '../../hooks';
|
||||
import { fetchUser, putUser } from './utils/api';
|
||||
import schema from './utils/schema';
|
||||
import { getFullName } from '../../utils';
|
||||
@ -62,6 +63,7 @@ const ProfilePage = () => {
|
||||
const toggleNotification = useNotification();
|
||||
const { lockApp, unlockApp } = useOverlayBlocker();
|
||||
const { notifyStatus } = useNotifyAT();
|
||||
const { currentTheme, themes: allApplicationThemes, onChangeTheme } = useThemeToggle();
|
||||
useFocusWhenNavigate();
|
||||
|
||||
const { status, data } = useQuery('user', () => fetchUser(), {
|
||||
@ -83,14 +85,17 @@ const ProfilePage = () => {
|
||||
|
||||
const isLoading = status !== 'success';
|
||||
|
||||
const submitMutation = useMutation(body => putUser(omit(body, 'confirmPassword')), {
|
||||
const submitMutation = useMutation(body => putUser(body), {
|
||||
onSuccess: async data => {
|
||||
await queryClient.invalidateQueries('user');
|
||||
|
||||
auth.setUserInfo(data);
|
||||
auth.setUserInfo(
|
||||
pick(data, ['email', 'firstname', 'lastname', 'username', 'preferedLanguage'])
|
||||
);
|
||||
const userDisplayName = data.username || getFullName(data.firstname, data.lastname);
|
||||
setUserDisplayName(userDisplayName);
|
||||
changeLocale(data.preferedLanguage);
|
||||
onChangeTheme(data.currentTheme);
|
||||
|
||||
toggleNotification({
|
||||
type: 'success',
|
||||
@ -128,9 +133,16 @@ const ProfilePage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const fieldsToPick = ['email', 'firstname', 'lastname', 'username', 'preferedLanguage'];
|
||||
const fieldsToPick = [
|
||||
'currentTheme',
|
||||
'email',
|
||||
'firstname',
|
||||
'lastname',
|
||||
'username',
|
||||
'preferedLanguage',
|
||||
];
|
||||
|
||||
const initialData = pick(data, fieldsToPick);
|
||||
const initialData = pick({ ...data, currentTheme }, fieldsToPick);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@ -154,6 +166,10 @@ const ProfilePage = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const themesToDisplay = Object.keys(allApplicationThemes).filter(
|
||||
themeName => allApplicationThemes[themeName]
|
||||
);
|
||||
|
||||
return (
|
||||
<Main aria-busy={isSubmittingForm}>
|
||||
<Helmet
|
||||
@ -487,6 +503,47 @@ const ProfilePage = () => {
|
||||
})}
|
||||
</Select>
|
||||
</GridItem>
|
||||
<GridItem s={12} col={6}>
|
||||
<Select
|
||||
label={formatMessage({
|
||||
id: 'Settings.profile.form.section.experience.mode.label',
|
||||
defaultMessage: 'Interface mode',
|
||||
})}
|
||||
placeholder={formatMessage({
|
||||
id: 'components.Select.placeholder',
|
||||
defaultMessage: 'Select',
|
||||
})}
|
||||
hint={formatMessage({
|
||||
id: 'Settings.profile.form.section.experience.mode.hint',
|
||||
defaultMessage: 'Displays your interface in the chosen mode.',
|
||||
})}
|
||||
value={values.currentTheme}
|
||||
onChange={e => {
|
||||
handleChange({
|
||||
target: { name: 'currentTheme', value: e },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{themesToDisplay.map(theme => {
|
||||
const label = formatMessage(
|
||||
{
|
||||
id:
|
||||
'Settings.profile.form.section.experience.mode.option-label',
|
||||
defaultMessage: '{name} mode',
|
||||
},
|
||||
{
|
||||
name: upperFirst(theme),
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Option value={theme} key={theme}>
|
||||
{label}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import omit from 'lodash/omit';
|
||||
import { axiosInstance } from '../../../core/utils';
|
||||
|
||||
const fetchUser = async () => {
|
||||
@ -7,9 +8,10 @@ const fetchUser = async () => {
|
||||
};
|
||||
|
||||
const putUser = async body => {
|
||||
const { data } = await axiosInstance.put('/admin/users/me', body);
|
||||
const dataToSend = omit(body, ['confirmPassword', 'currentTheme']);
|
||||
const { data } = await axiosInstance.put('/admin/users/me', dataToSend);
|
||||
|
||||
return data.data;
|
||||
return { ...data.data, currentTheme: body.currentTheme };
|
||||
};
|
||||
|
||||
export { fetchUser, putUser };
|
||||
|
@ -137,6 +137,9 @@
|
||||
"Settings.profile.form.section.experience.interfaceLanguage": "Interface language",
|
||||
"Settings.profile.form.section.experience.interfaceLanguage.hint": "This will only display your own interface in the chosen language.",
|
||||
"Settings.profile.form.section.experience.interfaceLanguageHelp": "Selection will change the interface language only for you. Please refer to this {documentation} to make other languages available for your team.",
|
||||
"Settings.profile.form.section.experience.mode.label": "Interface mode",
|
||||
"Settings.profile.form.section.experience.mode.hint": "Displays your interface in the chosen mode.",
|
||||
"Settings.profile.form.section.experience.mode.option-label": "{name} mode",
|
||||
"Settings.profile.form.section.experience.title": "Experience",
|
||||
"Settings.profile.form.section.helmet.title": "User profile",
|
||||
"Settings.profile.form.section.password.title": "Change password",
|
||||
|
Loading…
x
Reference in New Issue
Block a user