diff --git a/packages/strapi-admin/admin/src/containers/Admin/index.js b/packages/strapi-admin/admin/src/containers/Admin/index.js index 807be32aee..6696983a68 100644 --- a/packages/strapi-admin/admin/src/containers/Admin/index.js +++ b/packages/strapi-admin/admin/src/containers/Admin/index.js @@ -31,7 +31,7 @@ import Header from '../../components/Header/index'; import NavTopRightWrapper from '../../components/NavTopRightWrapper'; import LeftMenu from '../LeftMenu'; import InstalledPluginsPage from '../InstalledPluginsPage'; -import LocaleToggle from '../LocaleToggle'; + import HomePage from '../HomePage'; import MarketplacePage from '../MarketplacePage'; import NotFoundPage from '../NotFoundPage'; @@ -292,7 +292,6 @@ export class Admin extends React.Component { {/* Injection zone not ready yet */} -
diff --git a/packages/strapi-admin/admin/src/containers/LanguageProvider/hooks/useLanguages.js b/packages/strapi-admin/admin/src/containers/LanguageProvider/hooks/useLanguages.js new file mode 100644 index 0000000000..8bcbe775a9 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/LanguageProvider/hooks/useLanguages.js @@ -0,0 +1,15 @@ +import { useSelector, useDispatch } from 'react-redux'; +import { changeLocale } from '../actions'; + +const languageSelector = state => state.get('language').toJS(); + +const useLanguages = () => { + const { locale } = useSelector(languageSelector); + const dispatch = useDispatch(); + + const selectLanguage = nextLocale => dispatch(changeLocale(nextLocale)); + + return { currentLanguage: locale, selectLanguage }; +}; + +export default useLanguages; diff --git a/packages/strapi-admin/admin/src/containers/ProfilePage/components.js b/packages/strapi-admin/admin/src/containers/ProfilePage/components.js new file mode 100644 index 0000000000..c83041daf2 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/ProfilePage/components.js @@ -0,0 +1,11 @@ +import styled from 'styled-components'; +import { Label, Text } from '@buffetjs/core'; + +export const Title = styled(Text)` + text-transform: uppercase; + color: ${({ theme }) => theme.main.colors.grey}; +`; + +export const ProfilePageLabel = styled(Label)` + margin-bottom: 1rem; +`; diff --git a/packages/strapi-admin/admin/src/containers/ProfilePage/index.js b/packages/strapi-admin/admin/src/containers/ProfilePage/index.js index 727072313c..d5a62ec8fa 100644 --- a/packages/strapi-admin/admin/src/containers/ProfilePage/index.js +++ b/packages/strapi-admin/admin/src/containers/ProfilePage/index.js @@ -1,22 +1,32 @@ import React, { useMemo } from 'react'; -import { BackHeader, BaselineAlignment, auth } from 'strapi-helper-plugin'; +import { BackHeader, BaselineAlignment, auth, Select, Option, Row } from 'strapi-helper-plugin'; +import { Padded, Text } from '@buffetjs/core'; +import { Col } from 'reactstrap'; import { useHistory } from 'react-router-dom'; import { get } from 'lodash'; +import { useIntl } from 'react-intl'; import ContainerFluid from '../../components/ContainerFluid'; -import FormBloc from '../../components/FormBloc'; +import PageTitle from '../../components/PageTitle'; import SizedInput from '../../components/SizedInput'; import { Header } from '../../components/Settings'; import { useSettingsForm } from '../../hooks'; import { form, schema } from './utils'; +import useLanguages from '../LanguageProvider/hooks/useLanguages'; +import { languages, languageNativeNames } from '../../i18n'; +import { Title, ProfilePageLabel } from './components'; +import Bloc from '../../components/Bloc'; const ProfilePage = () => { const { goBack } = useHistory(); + const { currentLanguage, selectLanguage } = useLanguages(); + const { formatMessage } = useIntl(); + const onSubmitSuccessCb = data => auth.setUserInfo(data); const [ { formErrors, initialData, isLoading, modifiedData, showHeaderLoader, showHeaderButtonLoader }, // eslint-disable-next-line no-unused-vars - dispatch, + _, { handleCancel, handleChange, handleSubmit }, ] = useSettingsForm('/admin/users/me', schema, onSubmitSuccessCb, [ 'email', @@ -37,9 +47,13 @@ const ProfilePage = () => { return ( <> + + + +
- +
{ onCancel={handleCancel} showHeaderButtonLoader={showHeaderButtonLoader} /> - - - {Object.keys(form).map(key => { - return ( - - ); - })} - + + + + {/* Experience block */} + + + + + + + {formatMessage({ id: 'Settings.profile.form.section.profile.title' })} + + + + + + + + {Object.keys(form).map(key => ( + + ))} + + + + + + + + {/* Password block */} + + + + + + + {formatMessage({ id: 'Settings.profile.form.section.password.title' })} + + + + + + + + + + + + + + + + + + {/* Interface block */} + + + + + + + {formatMessage({ id: 'Settings.profile.form.section.experience.title' })} + + + + + + +
+ + {formatMessage({ + id: 'Settings.profile.form.section.experience.interfaceLanguage', + })} + + + + + + + {formatMessage({ + id: 'Settings.profile.form.section.experience.interfaceLanguage.hint', + })} + + +
+
+
+
); diff --git a/packages/strapi-admin/admin/src/containers/ProfilePage/utils/form.js b/packages/strapi-admin/admin/src/containers/ProfilePage/utils/form.js index 55720667bf..99c25c232e 100644 --- a/packages/strapi-admin/admin/src/containers/ProfilePage/utils/form.js +++ b/packages/strapi-admin/admin/src/containers/ProfilePage/utils/form.js @@ -31,17 +31,6 @@ const form = { autoComplete: 'no', validations: {}, }, - password: { - label: 'Auth.form.password.label', - type: 'password', - autoComplete: 'new-password', - validations: {}, - }, - confirmPassword: { - label: 'Auth.form.confirmPassword.label', - type: 'password', - validations: {}, - }, }; export default form; diff --git a/packages/strapi-admin/admin/src/containers/Users/EditPage/index.js b/packages/strapi-admin/admin/src/containers/Users/EditPage/index.js index 430de82151..062331bb7f 100644 --- a/packages/strapi-admin/admin/src/containers/Users/EditPage/index.js +++ b/packages/strapi-admin/admin/src/containers/Users/EditPage/index.js @@ -99,7 +99,9 @@ const EditPage = ({ canUpdate }) => { ); })} + + {!isLoading && ( { + const theme = useTheme(); + + return ( + + + + ); +}; + +export const Select = ({ children, onChange, selectedValue, ...props }) => { + const theme = useTheme(); + const selectStyles = getStyles(theme); + const childrenArray = React.Children.toArray(children); + + const options = childrenArray.map(child => ({ + value: child.props.value, + label: child.props.children, + })); + + const selectedOption = options.find(({ value }) => value === selectedValue); + + return ( + onChange(value)} + components={{ DropdownIndicator }} + styles={selectStyles} + value={selectedOption} + /> + ); +}; + +/** + * Do not remove this component. + * The Select component is a mimic of the select HTML element: + * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select + * The Select component will map over its "Option" components and verify their + * "value" in order to pass them down to react-select + */ +export const Option = () => <>; + +Select.defaultProps = { + selectedValue: undefined, +}; + +Select.propTypes = { + children: PropTypes.node.isRequired, + onChange: PropTypes.func.isRequired, + selectedValue: PropTypes.string, +}; diff --git a/packages/strapi-helper-plugin/lib/src/components/Select/styles.js b/packages/strapi-helper-plugin/lib/src/components/Select/styles.js new file mode 100644 index 0000000000..f5f56f2c19 --- /dev/null +++ b/packages/strapi-helper-plugin/lib/src/components/Select/styles.js @@ -0,0 +1,116 @@ +/* eslint-disable indent */ +/* eslint-disable no-nested-ternary */ + +const getStyles = theme => { + const { colors, fontWeights, sizes } = theme.main; + + // Colors that does not exist in the theme.main.colors + const unknownLightGrey = `#f6f6f6`; + const unknownGrey = `#aaa`; + const unknownLightblue = `#78caff`; + + // Sizes that does not exist in the theme.main.sizes + const unknownBorderSize1 = `1px`; + const optionHeight = `36px`; + const controlMinHeight = `34px`; + + return { + container: base => ({ + ...base, + width: '100%', + }), + control: (base, state) => { + const { + selectProps: { error, value }, + } = state; + + let border; + let borderBottom; + let backgroundColor; + + if (state.isFocused) { + border = `${unknownBorderSize1} solid ${unknownLightblue} !important`; + } else if (error && !value.length) { + border = `${unknownBorderSize1} solid ${colors.lightOrange} !important`; + } else { + border = `${unknownBorderSize1} solid ${colors.border} !important`; + } + + if (state.menuIsOpen === true) { + borderBottom = `${unknownBorderSize1} solid ${colors.border} !important`; + } + + if (state.isDisabled) { + backgroundColor = `${colors.content.background} !important`; + } + + return { + ...base, + fontSize: sizes.fonts.md, + minHeight: controlMinHeight, + border, + outline: 0, + boxShadow: 0, + borderRadius: `${sizes.borderRadius} !important`, + borderBottom, + backgroundColor, + width: '100%', + }; + }, + menu: base => ({ + ...base, + width: '100%', + margin: '0', + paddingTop: 0, + borderRadius: `${sizes.borderRadius} !important`, + borderTopLeftRadius: '0 !important', + borderTopRightRadius: '0 !important', + border: `${unknownBorderSize1} solid ${unknownLightblue} !important`, + boxShadow: 0, + borderTop: '0 !important', + fontSize: sizes.fonts.md, + }), + menuList: base => ({ + ...base, + maxHeight: '112px', + paddingTop: sizes.borderRadius, + }), + option: (base, state) => ({ + ...base, + height: optionHeight, + + backgroundColor: state.isFocused ? unknownLightGrey : colors.white, + ':active': { + ...base[':active'], + backgroundColor: unknownLightGrey, + }, + WebkitFontSmoothing: 'antialiased', + color: colors.black, + fontWeight: state.isFocused ? fontWeights.bold : fontWeights.regular, + cursor: 'pointer', + }), + placeholder: base => ({ + ...base, + marginTop: 0, + color: unknownGrey, + }), + valueContainer: base => ({ + ...base, + padding: '2px 4px 4px 4px', // These value don't exist in the theme + fontSize: sizes.fonts.md, + }), + indicatorsContainer: base => ({ + ...base, + width: '32px', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + background: colors.content.background, + }), + indicatorSeparator: () => ({ + display: 'none', + }), + }; +}; + +export default getStyles; diff --git a/packages/strapi-helper-plugin/lib/src/index.js b/packages/strapi-helper-plugin/lib/src/index.js index 74d286b69a..f10895ac0d 100644 --- a/packages/strapi-helper-plugin/lib/src/index.js +++ b/packages/strapi-helper-plugin/lib/src/index.js @@ -26,6 +26,7 @@ export { default as IcoContainer } from './components/IcoContainer'; export { default as InputAddon } from './components/InputAddon'; export { default as EmptyState } from './components/EmptyState'; export * from './components/Tabs'; +export * from './components/Select'; export { default as InputAddonWithErrors } from './components/InputAddonWithErrors'; export { default as InputCheckbox } from './components/InputCheckbox';