Move input component to helper plugin

Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
soupette 2021-09-02 14:59:40 +02:00
parent 53563d82a3
commit d69ee57dae
11 changed files with 165 additions and 36 deletions

View File

@ -0,0 +1,108 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import {
Stack,
Grid,
GridItem,
ModalLayout,
ModalHeader,
ModalFooter,
ModalBody,
Button,
Breadcrumbs,
Crumb,
Text,
Box,
H2,
} from '@strapi/parts';
import { Formik } from 'formik';
import { Form } from '@strapi/helper-plugin';
import schema from './utils/schema';
import stepper from './utils/stepper';
const ModalForm = ({ onToggle }) => {
const [currentStep, setStep] = useState('create');
const { formatMessage } = useIntl();
const headerTitle = formatMessage({
id: 'Settings.permissions.users.create',
defaultMessage: 'Create new user',
});
const goNext = () => {
if (next) {
setStep(next);
} else {
onToggle();
}
};
const { buttonSubmitLabel, isDisabled, next } = stepper[currentStep];
return (
<ModalLayout onClose={onToggle} labelledBy="title">
<ModalHeader>
<Breadcrumbs label={headerTitle}>
<Crumb>{headerTitle}</Crumb>
</Breadcrumbs>
</ModalHeader>
<Formik
initialValues={{ firstname: '', lastname: '', email: '', roles: [] }}
onSubmit={() => {}}
validationSchema={schema}
validateOnChange={false}
>
{({ errors, handleChange, values }) => {
return (
<Form>
<ModalBody>
<Stack size={6}>
<Box>
<H2>
{formatMessage({
id: 'app.components.Users.ModalCreateBody.block-title.details',
defaultMessage: 'Details',
})}
</H2>
</Box>
<Box>
<H2>
{formatMessage({
id: 'app.components.Users.ModalCreateBody.block-title.login',
defaultMessage: 'Login settings',
})}
</H2>
</Box>
</Stack>
<input type="text" value={values.firstname} name="firstname" />
</ModalBody>
<ModalFooter
startActions={
<Button variant="tertiary" onClick={onToggle} type="button">
{formatMessage({
id: 'app.components.Button.cancel',
defaultMessage: 'Cancel',
})}
</Button>
}
endActions={
<>
<Button type="submit" loading={false}>
{formatMessage(buttonSubmitLabel)}
</Button>
</>
}
/>
</Form>
);
}}
</Formik>
</ModalLayout>
);
};
ModalForm.propTypes = {
onToggle: PropTypes.func.isRequired,
};
export default ModalForm;

View File

@ -0,0 +1,17 @@
import * as yup from 'yup';
import { translatedErrors } from '@strapi/helper-plugin';
const schema = yup.object().shape({
firstname: yup.string().required(translatedErrors.required),
lastname: yup.string().required(translatedErrors.required),
email: yup
.string()
.email(translatedErrors.email)
.required(translatedErrors.required),
roles: yup
.array()
.min(1, translatedErrors.min)
.required(translatedErrors.required),
});
export default schema;

View File

@ -0,0 +1,21 @@
// import { ModalCreateBody } fro../../../../../components/Usersers';
const stepper = {
create: {
buttonSubmitLabel: {
id: 'app.containers.Users.ModalForm.footer.button-success',
defaultMessage: 'Create user',
},
// Component: ModalCreateBody,
isDisabled: false,
next: 'magic-link',
},
'magic-link': {
buttonSubmitLabel: { id: 'form.button.finish', defaultMessage: 'Finish' },
// Component: ModalCreateBody,
isDisabled: true,
next: null,
},
};
export default stepper;

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Button } from '@buffetjs/core'; import { Button } from '@buffetjs/core';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { Modal, ModalFooter, ModalHeader } from '@strapi/helper-plugin'; import { Modal, ModalFooter, ModalHeader } from '@strapi/helper-plugin';
import stepper from './stepper'; import stepper from './ModalForm/utils/stepper';
const ModalForm = ({ isOpen, onClosed, onToggle }) => { const ModalForm = ({ isOpen, onClosed, onToggle }) => {
const [currentStep, setStep] = useState('create'); const [currentStep, setStep] = useState('create');

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { import {
CustomContentLayout, CustomContentLayout,
useRBAC, useRBAC,
@ -15,6 +15,7 @@ import get from 'lodash/get';
import adminPermissions from '../../../permissions'; import adminPermissions from '../../../permissions';
import DynamicTable from './DynamicTable'; import DynamicTable from './DynamicTable';
import Filters from './Filters'; import Filters from './Filters';
import ModalForm from './ModalForm';
import Search from './Search'; import Search from './Search';
import PaginationFooter from './PaginationFooter'; import PaginationFooter from './PaginationFooter';
import { deleteData, fetchData } from './utils/api'; import { deleteData, fetchData } from './utils/api';
@ -22,6 +23,7 @@ import displayedFilters from './utils/displayedFilters';
import tableHeaders from './utils/tableHeaders'; import tableHeaders from './utils/tableHeaders';
const ListPage = () => { const ListPage = () => {
const [isModalOpened, setIsModalOpen] = useState(true);
const { const {
allowedActions: { canCreate, canDelete, canRead, canUpdate }, allowedActions: { canCreate, canDelete, canRead, canUpdate },
} = useRBAC(adminPermissions.settings.users); } = useRBAC(adminPermissions.settings.users);
@ -29,6 +31,7 @@ const ListPage = () => {
const toggleNotification = useNotification(); const toggleNotification = useNotification();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const { search } = useLocation(); const { search } = useLocation();
useFocusWhenNavigate();
const { status, data, isFetching } = useQuery(['users', search], () => fetchData(search), { const { status, data, isFetching } = useQuery(['users', search], () => fetchData(search), {
enabled: canRead, enabled: canRead,
@ -43,7 +46,9 @@ const ListPage = () => {
}, },
}); });
useFocusWhenNavigate(); const handleToggle = () => {
setIsModalOpen(prev => !prev);
};
const total = get(data, 'pagination.total', 0); const total = get(data, 'pagination.total', 0);
@ -68,11 +73,7 @@ const ListPage = () => {
(status !== 'success' && status !== 'error') || (status === 'success' && isFetching); (status !== 'success' && status !== 'error') || (status === 'success' && isFetching);
const createAction = canCreate ? ( const createAction = canCreate ? (
<Button <Button data-testid="create-user-button" onClick={handleToggle} startIcon={<Mail />}>
data-testid="create-user-button"
onClick={() => 'handleToggleModalForCreatingRole'}
startIcon={<Mail />}
>
{formatMessage({ {formatMessage({
id: 'Settings.permissions.users.create', id: 'Settings.permissions.users.create',
defaultMessage: 'Create new user', defaultMessage: 'Create new user',
@ -129,6 +130,7 @@ const ListPage = () => {
</> </>
)} )}
</CustomContentLayout> </CustomContentLayout>
{isModalOpened && <ModalForm onToggle={handleToggle} />}
</Main> </Main>
); );

View File

@ -1,18 +0,0 @@
import { ModalCreateBody } from '../../../components/Users';
const stepper = {
create: {
buttonSubmitLabel: 'app.containers.Users.ModalForm.footer.button-success',
Component: ModalCreateBody,
isDisabled: false,
next: 'magic-link',
},
'magic-link': {
buttonSubmitLabel: 'form.button.continue',
Component: ModalCreateBody,
isDisabled: true,
next: null,
},
};
export default stepper;

View File

@ -110,7 +110,6 @@
"Settings.permissions.conditions.when": "When", "Settings.permissions.conditions.when": "When",
"Settings.permissions.menu.link.roles.label": "Roles", "Settings.permissions.menu.link.roles.label": "Roles",
"Settings.permissions.menu.link.users.label": "Users", "Settings.permissions.menu.link.users.label": "Users",
"Settings.permissions.users.add-new": "Add new user",
"Settings.permissions.users.create": "Create new user", "Settings.permissions.users.create": "Create new user",
"Settings.permissions.users.form.email": "Email", "Settings.permissions.users.form.email": "Email",
"Settings.permissions.users.form.firstname": "First name", "Settings.permissions.users.form.firstname": "First name",

View File

@ -10,7 +10,7 @@ import { ToggleInput } from '@strapi/parts/ToggleInput';
import { TextInput } from '@strapi/parts/TextInput'; import { TextInput } from '@strapi/parts/TextInput';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
const Input = ({ const GenericInput = ({
description, description,
disabled, disabled,
intlLabel, intlLabel,
@ -85,7 +85,7 @@ const Input = ({
); );
}; };
Input.defaultProps = { GenericInput.defaultProps = {
description: null, description: null,
disabled: false, disabled: false,
error: '', error: '',
@ -93,7 +93,7 @@ Input.defaultProps = {
value: '', value: '',
}; };
Input.propTypes = { GenericInput.propTypes = {
description: PropTypes.shape({ description: PropTypes.shape({
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired, defaultMessage: PropTypes.string.isRequired,
@ -118,4 +118,4 @@ Input.propTypes = {
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
}; };
export default Input; export default GenericInput;

View File

@ -1,6 +1,6 @@
/** /**
* *
* Tests for Input * Tests for GenericInput
* *
*/ */
@ -29,7 +29,7 @@ const makeApp = (name, type, value) => (
</IntlProvider> </IntlProvider>
); );
describe('<Input />', () => { describe('<GenericInput />', () => {
it('renders and matches the snapshot', () => { it('renders and matches the snapshot', () => {
const { const {
container: { firstChild }, container: { firstChild },

View File

@ -175,6 +175,7 @@ export { default as CheckPermissions } from './components/CheckPermissions';
export { default as CustomContentLayout } from './components/CustomContentLayout'; export { default as CustomContentLayout } from './components/CustomContentLayout';
export { default as EmptyStateLayout } from './components/EmptyStateLayout'; export { default as EmptyStateLayout } from './components/EmptyStateLayout';
export { default as EmptyBodyTable } from './components/EmptyBodyTable'; export { default as EmptyBodyTable } from './components/EmptyBodyTable';
export { default as GenericInput } from './components/GenericInput';
export * from './components/InjectionZone'; export * from './components/InjectionZone';
export { default as LoadingIndicatorPage } from './components/LoadingIndicatorPage'; export { default as LoadingIndicatorPage } from './components/LoadingIndicatorPage';
export { default as SettingsPageTitle } from './components/SettingsPageTitle'; export { default as SettingsPageTitle } from './components/SettingsPageTitle';

View File

@ -20,8 +20,7 @@ import {
} from '@strapi/parts'; } from '@strapi/parts';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { Form } from '@strapi/helper-plugin'; import { Form, GenericInput } from '@strapi/helper-plugin';
import Input from './Input';
const FormModal = ({ const FormModal = ({
headerBreadcrumbs, headerBreadcrumbs,
@ -64,7 +63,7 @@ const FormModal = ({
return row.map(input => { return row.map(input => {
return ( return (
<GridItem key={input.name} col={input.size} xs={12}> <GridItem key={input.name} col={input.size} xs={12}>
<Input <GenericInput
{...input} {...input}
error={errors[input.name]} error={errors[input.name]}
onChange={handleChange} onChange={handleChange}