Merge pull request #11060 from strapi/profile-fix

MigrationQA/ Profile page fix
This commit is contained in:
cyril lopez 2021-09-24 14:25:46 +02:00 committed by GitHub
commit e3b018cbb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 792 additions and 613 deletions

View File

@ -1,4 +1,5 @@
import React from 'react';
import React, { useState } from 'react';
import styled from 'styled-components';
import {
Form,
GenericInput,
@ -24,12 +25,28 @@ import { Grid, GridItem } from '@strapi/parts/Grid';
import { Stack } from '@strapi/parts/Stack';
import { useNotifyAT } from '@strapi/parts/LiveRegions';
import { Select, Option } from '@strapi/parts/Select';
import { FieldAction } from '@strapi/parts/Field';
import { TextInput } from '@strapi/parts/TextInput';
import Show from '@strapi/icons/Show';
import Hide from '@strapi/icons/Hide';
import CheckIcon from '@strapi/icons/CheckIcon';
import useLocalesProvider from '../../components/LocalesProvider/useLocalesProvider';
import { fetchUser, putUser } from './utils/api';
import { schema, layout } from './utils';
import schema from './utils/schema';
const FieldActionWrapper = styled(FieldAction)`
svg {
height: 1rem;
width: 1rem;
path {
fill: ${({ theme }) => theme.colors.neutral600};
}
}
`;
const ProfilePage = () => {
const [passwordShown, setPasswordShown] = useState(false);
const [passwordConfirmShown, setPasswordConfirmShown] = useState(false);
const { changeLocale, localeNames } = useLocalesProvider();
const { setUserDisplayName } = useAppInfos();
const queryClient = useQueryClient();
@ -145,6 +162,7 @@ const ProfilePage = () => {
</Button>
}
/>
<Box paddingBottom={10}>
<ContentLayout>
<Stack size={6}>
<Box
@ -164,18 +182,55 @@ const ProfilePage = () => {
})}
</H3>
<Grid gap={5}>
{layout[0].map(input => {
return (
<GridItem key={input.name} {...input.size}>
<GridItem s={12} col={6}>
<GenericInput
{...input}
error={errors[input.name]}
intlLabel={{
id: 'Auth.form.firstname.label',
defaultMessage: 'First name',
}}
error={errors.firstname}
onChange={handleChange}
value={values[input.name] || ''}
value={values.firstname || ''}
type="text"
name="firstname"
/>
</GridItem>
<GridItem s={12} col={6}>
<GenericInput
intlLabel={{
id: 'Auth.form.lastname.label',
defaultMessage: 'Last name',
}}
error={errors.lastname}
onChange={handleChange}
value={values.lastname || ''}
type="text"
name="lastname"
/>
</GridItem>
<GridItem s={12} col={6}>
<GenericInput
intlLabel={{ id: 'Auth.form.email.label', defaultMessage: 'Email' }}
error={errors.email}
onChange={handleChange}
value={values.email || ''}
type="email"
name="email"
/>
</GridItem>
<GridItem s={12} col={6}>
<GenericInput
intlLabel={{
id: 'Auth.form.username.label',
defaultMessage: 'Username',
}}
error={errors.username}
onChange={handleChange}
value={values.username || ''}
type="text"
name="username"
/>
</GridItem>
);
})}
</Grid>
</Stack>
</Box>
@ -196,18 +251,88 @@ const ProfilePage = () => {
})}
</H3>
<Grid gap={5}>
{layout[1].map(input => {
return (
<GridItem key={input.name} {...input.size}>
<GenericInput
{...input}
error={errors[input.name]}
<GridItem s={12} col={6}>
<TextInput
error={
errors.password
? formatMessage({
id: errors.password,
defaultMessage: 'This value is required.',
})
: ''
}
onChange={handleChange}
value={values[input.name] || ''}
value={values.password || ''}
label={formatMessage({
id: 'Auth.form.password.label',
defaultMessage: 'Password',
})}
name="password"
type={passwordShown ? 'text' : 'password'}
endAction={
<FieldActionWrapper
onClick={e => {
e.stopPropagation();
setPasswordShown(prev => !prev);
}}
label={formatMessage(
passwordShown
? {
id: 'Auth.form.password.show-password',
defaultMessage: 'Show password',
}
: {
id: 'Auth.form.password.hide-password',
defaultMessage: 'Hide password',
}
)}
>
{passwordShown ? <Show /> : <Hide />}
</FieldActionWrapper>
}
/>
</GridItem>
);
<GridItem s={12} col={6}>
<TextInput
error={
errors.password
? formatMessage({
id: errors.password,
defaultMessage: 'This value is required.',
})
: ''
}
onChange={handleChange}
value={values.confirmPassword || ''}
label={formatMessage({
id: 'Auth.form.confirmPassword.label',
defaultMessage: 'Password confirmation',
})}
name="confirmPassword"
type={passwordConfirmShown ? 'text' : 'password'}
endAction={
<FieldActionWrapper
onClick={e => {
e.stopPropagation();
setPasswordConfirmShown(prev => !prev);
}}
label={formatMessage(
passwordConfirmShown
? {
id: 'Auth.form.password.show-password',
defaultMessage: 'Show password',
}
: {
id: 'Auth.form.password.hide-password',
defaultMessage: 'Hide password',
}
)}
>
{passwordConfirmShown ? <Show /> : <Hide />}
</FieldActionWrapper>
}
/>
</GridItem>
</Grid>
</Stack>
</Box>
@ -227,6 +352,8 @@ const ProfilePage = () => {
defaultMessage: 'Experience',
})}
</H3>
<Grid gap={5}>
<GridItem s={12} col={6}>
<Select
label={formatMessage({
id: 'Settings.profile.form.section.experience.interfaceLanguage',
@ -237,7 +364,8 @@ const ProfilePage = () => {
defaultMessage: 'Select',
})}
hint={formatMessage({
id: 'Settings.profile.form.section.experience.interfaceLanguage.hint',
id:
'Settings.profile.form.section.experience.interfaceLanguage.hint',
defaultMessage:
'This will only display your own interface in the chosen language.',
})}
@ -261,10 +389,13 @@ const ProfilePage = () => {
);
})}
</Select>
</GridItem>
</Grid>
</Stack>
</Box>
</Stack>
</ContentLayout>
</Box>
</Form>
);
}}

View File

@ -61,7 +61,11 @@ describe('ADMIN | Pages | Profile page', () => {
});
expect(container.firstChild).toMatchInlineSnapshot(`
.c16 {
.c14 {
padding-bottom: 56px;
}
.c17 {
background: #ffffff;
padding-top: 24px;
padding-right: 32px;
@ -174,6 +178,22 @@ describe('ADMIN | Pages | Profile page', () => {
}
.c31 {
border: none;
background: transparent;
font-size: 1.6rem;
width: auto;
padding: 0;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c36 {
position: absolute;
left: 0;
right: 0;
@ -184,41 +204,41 @@ describe('ADMIN | Pages | Profile page', () => {
border: none;
}
.c31:focus {
.c36:focus {
outline: none;
}
.c29 {
.c34 {
font-weight: 500;
font-size: 0.75rem;
line-height: 1.33;
color: #32324d;
}
.c36 {
.c41 {
font-weight: 400;
font-size: 0.875rem;
line-height: 1.43;
color: #32324d;
}
.c40 {
.c45 {
font-weight: 400;
font-size: 0.75rem;
line-height: 1.33;
color: #666687;
}
.c35 {
.c40 {
padding-right: 16px;
padding-left: 16px;
}
.c38 {
.c43 {
padding-left: 12px;
}
.c32 {
.c37 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -236,7 +256,7 @@ describe('ADMIN | Pages | Profile page', () => {
align-items: center;
}
.c34 {
.c39 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -250,7 +270,7 @@ describe('ADMIN | Pages | Profile page', () => {
align-items: center;
}
.c28 {
.c33 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -260,16 +280,16 @@ describe('ADMIN | Pages | Profile page', () => {
flex-direction: column;
}
.c28 > * {
.c33 > * {
margin-top: 0;
margin-bottom: 0;
}
.c28 > * + * {
.c33 > * + * {
margin-top: 4px;
}
.c30 {
.c35 {
position: relative;
border: 1px solid #dcdce4;
padding-right: 12px;
@ -278,27 +298,27 @@ describe('ADMIN | Pages | Profile page', () => {
overflow: hidden;
}
.c30:focus-within {
.c35:focus-within {
border: 1px solid #4945ff;
}
.c37 {
.c42 {
background: transparent;
border: none;
position: relative;
z-index: 1;
}
.c37 svg {
.c42 svg {
height: 0.6875rem;
width: 0.6875rem;
}
.c37 svg path {
.c42 svg path {
fill: #666687;
}
.c39 {
.c44 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -307,15 +327,15 @@ describe('ADMIN | Pages | Profile page', () => {
border: none;
}
.c39 svg {
.c44 svg {
width: 0.375rem;
}
.c33 {
.c38 {
min-height: 2.5rem;
}
.c15 {
.c16 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -325,16 +345,16 @@ describe('ADMIN | Pages | Profile page', () => {
flex-direction: column;
}
.c15 > * {
.c16 > * {
margin-top: 0;
margin-bottom: 0;
}
.c15 > * + * {
.c16 > * + * {
margin-top: 24px;
}
.c17 {
.c18 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -344,30 +364,35 @@ describe('ADMIN | Pages | Profile page', () => {
flex-direction: column;
}
.c17 > * {
.c18 > * {
margin-top: 0;
margin-bottom: 0;
}
.c17 > * + * {
.c18 > * + * {
margin-top: 16px;
}
.c18 {
.c19 {
font-weight: 500;
font-size: 1rem;
line-height: 1.25;
color: #32324d;
}
.c24 {
.c25 {
font-weight: 500;
font-size: 0.75rem;
line-height: 1.33;
color: #32324d;
}
.c23 {
.c30 {
padding-right: 12px;
padding-left: 8px;
}
.c24 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -381,7 +406,7 @@ describe('ADMIN | Pages | Profile page', () => {
align-items: center;
}
.c25 {
.c26 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -399,7 +424,7 @@ describe('ADMIN | Pages | Profile page', () => {
align-items: center;
}
.c27 {
.c28 {
border: none;
border-radius: 4px;
padding-left: 16px;
@ -412,38 +437,76 @@ describe('ADMIN | Pages | Profile page', () => {
height: 2.5rem;
}
.c27::-webkit-input-placeholder {
.c28::-webkit-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c27::-moz-placeholder {
.c28::-moz-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c27:-ms-input-placeholder {
.c28:-ms-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c27::placeholder {
.c28::placeholder {
color: #8e8ea9;
opacity: 1;
}
.c27[aria-disabled='true'] {
.c28[aria-disabled='true'] {
background: inherit;
color: inherit;
}
.c26 {
.c29 {
border: none;
border-radius: 4px;
padding-left: 16px;
padding-right: 0;
color: #32324d;
font-weight: 400;
font-size: 0.875rem;
display: block;
width: 100%;
height: 2.5rem;
}
.c29::-webkit-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c29::-moz-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c29:-ms-input-placeholder {
color: #8e8ea9;
opacity: 1;
}
.c29::placeholder {
color: #8e8ea9;
opacity: 1;
}
.c29[aria-disabled='true'] {
background: inherit;
color: inherit;
}
.c27 {
border: 1px solid #dcdce4;
border-radius: 4px;
background: #ffffff;
}
.c22 {
.c23 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -453,16 +516,16 @@ describe('ADMIN | Pages | Profile page', () => {
flex-direction: column;
}
.c22 > * {
.c23 > * {
margin-top: 0;
margin-bottom: 0;
}
.c22 > * + * {
.c23 > * + * {
margin-top: 4px;
}
.c21 textarea {
.c22 textarea {
height: 5rem;
}
@ -478,7 +541,7 @@ describe('ADMIN | Pages | Profile page', () => {
padding-left: 56px;
}
.c14 {
.c15 {
padding-right: 56px;
padding-left: 56px;
}
@ -534,26 +597,35 @@ describe('ADMIN | Pages | Profile page', () => {
line-height: 1.5;
}
.c19 {
.c20 {
display: grid;
grid-template-columns: repeat(12,1fr);
gap: 20px;
}
.c20 {
.c21 {
grid-column: span 6;
word-break: break-all;
}
.c32 svg {
height: 1rem;
width: 1rem;
}
.c32 svg path {
fill: #666687;
}
@media (max-width:68.75rem) {
.c20 {
grid-column: span;
.c21 {
grid-column: span 12;
}
}
@media (max-width:34.375rem) {
.c20 {
grid-column: span 12;
.c21 {
grid-column: span;
}
}
@ -634,44 +706,47 @@ describe('ADMIN | Pages | Profile page', () => {
<div
class="c17"
>
<h2
<div
class="c18"
>
<h2
class="c19"
>
Profile
</h2>
<div
class="c19"
class="c20"
>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-1"
>
First name
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c28"
id="textinput-1"
name="firstname"
placeholder=""
@ -685,35 +760,35 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-2"
>
Last name
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c28"
id="textinput-2"
name="lastname"
placeholder=""
@ -727,35 +802,35 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-3"
>
Email
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c28"
id="textinput-3"
name="email"
placeholder=""
@ -769,35 +844,35 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-4"
>
Username
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c28"
id="textinput-4"
name="username"
placeholder=""
@ -813,56 +888,77 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
</div>
<div
class="c16"
>
<div
class="c17"
>
<h2
<div
class="c18"
>
<h2
class="c19"
>
Change password
</h2>
<div
class="c19"
class="c20"
>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-5"
>
Password
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c29"
id="textinput-5"
name="password"
placeholder=""
type="password"
value=""
/>
<div
class="c30"
>
<button
aria-label="Hide password"
class="c31 c32"
type="button"
>
<svg
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.048 6.875L2.103 4.93a1 1 0 111.414-1.415l16.966 16.966a1 1 0 11-1.414 1.415l-2.686-2.686a12.247 12.247 0 01-4.383.788c-3.573 0-6.559-1.425-8.962-3.783a15.842 15.842 0 01-2.116-2.568 11.096 11.096 0 01-.711-1.211 1.145 1.145 0 010-.875c.124-.258.36-.68.711-1.211.58-.876 1.283-1.75 2.116-2.569.326-.32.663-.622 1.01-.906zm10.539 10.539l-1.551-1.551a4.005 4.005 0 01-4.9-4.9L6.584 9.411a6 6 0 008.002 8.002zM7.617 4.787A12.248 12.248 0 0112 3.998c3.572 0 6.559 1.426 8.961 3.783a15.845 15.845 0 012.117 2.569c.351.532.587.954.711 1.211.116.242.115.636 0 .875-.124.257-.36.68-.711 1.211-.58.876-1.283 1.75-2.117 2.568-.325.32-.662.623-1.01.907l-2.536-2.537a6 6 0 00-8.002-8.002L7.617 4.787zm3.347 3.347A4.005 4.005 0 0116 11.998c0 .359-.047.706-.136 1.037l-4.9-4.901z"
fill="#212134"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
@ -870,74 +966,104 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<div
class="c20"
class="c21"
>
<div
class=""
>
<div
class="c21"
class="c22"
>
<div>
<div
class="c22"
>
<div
class="c23"
>
<label
<div
class="c24"
>
<label
class="c25"
for="textinput-6"
>
Password confirmation
</label>
</div>
<div
class="c25 c26"
class="c26 c27"
>
<input
aria-disabled="false"
aria-invalid="false"
class="c27"
class="c29"
id="textinput-6"
name="confirmPassword"
placeholder=""
type="password"
value=""
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c16"
class="c30"
>
<button
aria-label="Hide password"
class="c31 c32"
type="button"
>
<svg
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.048 6.875L2.103 4.93a1 1 0 111.414-1.415l16.966 16.966a1 1 0 11-1.414 1.415l-2.686-2.686a12.247 12.247 0 01-4.383.788c-3.573 0-6.559-1.425-8.962-3.783a15.842 15.842 0 01-2.116-2.568 11.096 11.096 0 01-.711-1.211 1.145 1.145 0 010-.875c.124-.258.36-.68.711-1.211.58-.876 1.283-1.75 2.116-2.569.326-.32.663-.622 1.01-.906zm10.539 10.539l-1.551-1.551a4.005 4.005 0 01-4.9-4.9L6.584 9.411a6 6 0 008.002 8.002zM7.617 4.787A12.248 12.248 0 0112 3.998c3.572 0 6.559 1.426 8.961 3.783a15.845 15.845 0 012.117 2.569c.351.532.587.954.711 1.211.116.242.115.636 0 .875-.124.257-.36.68-.711 1.211-.58.876-1.283 1.75-2.117 2.568-.325.32-.662.623-1.01.907l-2.536-2.537a6 6 0 00-8.002-8.002L7.617 4.787zm3.347 3.347A4.005 4.005 0 0116 11.998c0 .359-.047.706-.136 1.037l-4.9-4.901z"
fill="#212134"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c17"
>
<h2
<div
class="c18"
>
<h2
class="c19"
>
Experience
</h2>
<div
class="c20"
>
<div
class="c21"
>
<div
class=""
>
<div>
<div
class="c28"
class="c33"
>
<span
class="c29"
class="c34"
for="select-1"
id="select-1-label"
>
Interface language
</span>
<div
class="c30"
class="c35"
>
<button
aria-describedby="select-1-hint"
@ -945,21 +1071,21 @@ describe('ADMIN | Pages | Profile page', () => {
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="select-1-label select-1-content"
class="c31"
class="c36"
id="select-1"
type="button"
/>
<div
class="c32 c33"
class="c37 c38"
>
<div
class="c34"
class="c39"
>
<div
class="c35"
class="c40"
>
<span
class="c36"
class="c41"
id="select-1-content"
>
Select
@ -967,12 +1093,12 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<div
class="c34"
class="c39"
>
<button
aria-disabled="false"
aria-label="Clear the interface language selected"
class="c37"
class="c42"
>
<svg
fill="none"
@ -989,7 +1115,7 @@ describe('ADMIN | Pages | Profile page', () => {
</button>
<button
aria-hidden="true"
class="c38 c37 c39"
class="c43 c42 c44"
tabindex="-1"
type="button"
>
@ -1012,7 +1138,7 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
<p
class="c40"
class="c45"
id="select-1-hint"
>
This will only display your own interface in the chosen language.
@ -1023,6 +1149,10 @@ describe('ADMIN | Pages | Profile page', () => {
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</main>
`);

View File

@ -1,2 +0,0 @@
export { default as layout } from './layout';
export { default as schema } from './schema';

View File

@ -1,80 +0,0 @@
const layout = [
[
{
intlLabel: {
id: 'Auth.form.firstname.label',
defaultMessage: 'First name',
},
name: 'firstname',
type: 'text',
size: {
col: 6,
xs: 12,
},
},
{
intlLabel: {
id: 'Auth.form.lastname.label',
defaultMessage: 'Last name',
},
name: 'lastname',
type: 'text',
size: {
col: 6,
xs: 12,
},
},
{
intlLabel: {
id: 'Auth.form.email.label',
defaultMessage: 'Email',
},
name: 'email',
type: 'email',
size: {
col: 6,
xs: 12,
},
},
{
intlLabel: {
id: 'Auth.form.username.label',
defaultMessage: 'Username',
},
name: 'username',
type: 'text',
size: {
col: 6,
xs: 12,
},
},
],
[
{
intlLabel: {
id: 'Auth.form.password.label',
defaultMessage: 'Password',
},
name: 'password',
type: 'password',
size: {
col: 6,
xs: 12,
},
},
{
intlLabel: {
id: 'Auth.form.confirmPassword.label',
defaultMessage: 'Password confirmation',
},
name: 'confirmPassword',
type: 'password',
size: {
col: 6,
xs: 12,
},
},
],
];
export default layout;