Migrate AllowedTypesSelect

Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
soupette 2021-10-12 10:56:28 +02:00
parent 548cc9a88e
commit 7148972f00
8 changed files with 41 additions and 324 deletions

View File

@ -1,115 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { components } from 'react-select';
import { useIntl } from 'react-intl';
import { CheckboxWrapper, Label } from '@buffetjs/styles';
import getTrad from '../../utils/getTrad';
import SelectCheckbox from '../SelectCheckbox';
import SubUl from '../SelectMenuSubUl';
import UpperFirst from '../UpperFirst';
import Ul from '../SelectMenuUl';
import Text from './Text';
const MenuList = ({ selectProps: { changeMediaAllowedTypes, value }, ...rest }) => {
const { formatMessage } = useIntl();
const Component = components.MenuList;
const areAllAllowedTypesSelected = value.value && value.value.length === 3;
const someChecked = value.value && !areAllAllowedTypesSelected && value.value.length > 0;
const options = [
{
name: 'images',
infos: '(JPEG, PNG, GIF, SVG, TIFF, ICO, DVU)',
},
{
name: 'videos',
infos: '(MPEG, MP4, Quicktime, WMV, AVI, FLV)',
},
{
name: 'files',
infos: '(CSV, ZIP, MP3, PDF, Excel, JSON, ...)',
},
];
return (
<Component {...rest}>
<Ul>
<li className="li-multi-menu">
<div style={{ marginTop: 3 }}>
<CheckboxWrapper>
<Label
htmlFor="overrideReactSelectBehavior"
onClick={() => {
changeMediaAllowedTypes({
target: { name: 'all', value: !areAllAllowedTypesSelected },
});
}}
>
<SelectCheckbox
id="checkAll"
checked={areAllAllowedTypesSelected}
someChecked={someChecked}
name="all"
onChange={() => {}}
/>
<UpperFirst content="All" />
</Label>
</CheckboxWrapper>
</div>
<SubUl tad="ul" isOpen>
{options.map(({ name, infos }) => {
const isChecked = value.value && value.value.includes(name);
const target = { name, value: !isChecked };
return (
<li key={name}>
<CheckboxWrapper>
<Label
htmlFor={name}
onClick={() => {
changeMediaAllowedTypes({ target });
}}
>
<SelectCheckbox
id="check"
name={name}
// Remove the handler
onChange={() => {}}
checked={isChecked}
/>
<Text>
<UpperFirst
content={formatMessage({
id: getTrad(`form.attribute.media.allowed-types.option-${name}`),
})}
/>
</Text>
<Text fontSize="sm" color="#B3B5B9" textTransform="italic">
&nbsp;{infos}
</Text>
</Label>
</CheckboxWrapper>
</li>
);
})}
</SubUl>
</li>
</Ul>
</Component>
);
};
MenuList.defaultProps = {
selectProps: {
value: {},
},
};
MenuList.propTypes = {
selectProps: PropTypes.shape({
changeMediaAllowedTypes: PropTypes.func.isRequired,
value: PropTypes.object,
}),
};
export default MenuList;

View File

@ -1,26 +0,0 @@
import styled from 'styled-components';
import PropTypes from 'prop-types';
const Text = styled.p`
display: contents;
color: ${({ theme, color }) => theme.main.colors[color] || color};
font-size: ${({ theme, fontSize }) => theme.main.sizes.fonts[fontSize]};
font-weight: ${({ theme, fontWeight }) => theme.main.fontWeights[fontWeight]};
text-transform: ${({ textTransform }) => textTransform};
`;
Text.defaultProps = {
color: 'black',
fontSize: 'md',
fontWeight: 'regular',
textTransform: 'none',
};
Text.propTypes = {
color: PropTypes.string,
fontSize: PropTypes.string,
fontWeight: PropTypes.string,
textTransform: PropTypes.string,
};
export default Text;

View File

@ -1,18 +1,23 @@
import React, { useRef } from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Select from 'react-select';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { MultiSelectNested } from '@strapi/parts/Select';
import upperFirst from 'lodash/upperFirst'; import upperFirst from 'lodash/upperFirst';
import MenuList from './MenuList';
import getTrad from '../../utils/getTrad'; import getTrad from '../../utils/getTrad';
const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) => { const options = [
{
label: 'All',
children: [
{ label: 'images (JPEG, PNG, GIF, SVG, TIFF, ICO, DVU)', value: 'images' },
{ label: 'videos (MPEG, MP4, Quicktime, WMV, AVI, FLV)', value: 'videos' },
{ label: 'files (CSV, ZIP, MP3, PDF, Excel, JSON, ...)', value: 'files' },
],
},
];
const AllowedTypesSelect = ({ intlLabel, name, onChange, value }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
// Create a ref in order to access the StateManager
// So we can close the menu after clicking on a menu item
// This allows us to get rid of the menuIsOpen state management
// So we let the custom components taking care of it
const ref = useRef();
/* eslint-disable indent */ /* eslint-disable indent */
@ -26,17 +31,24 @@ const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) =>
/* eslint-enable indent */ /* eslint-enable indent */
const label = intlLabel.id
? formatMessage({ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage })
: name;
return ( return (
<Select <MultiSelectNested
components={{ MenuList }} id="select1"
isClearable={false} label={label}
isSearchable={false} customizeContent={() => displayedValue}
name={name} onChange={values => {
changeMediaAllowedTypes={changeMediaAllowedTypes} if (values.length > 0) {
ref={ref} onChange({ target: { name, value: values, type: 'allowed-types-select' } });
refState={ref} } else {
styles={styles} onChange({ target: { name, value: null, type: 'allowed-types-select' } });
value={{ label: displayedValue, value: value || '' }} }
}}
options={options}
value={value || []}
/> />
); );
}; };
@ -46,9 +58,13 @@ AllowedTypesSelect.defaultProps = {
}; };
AllowedTypesSelect.propTypes = { AllowedTypesSelect.propTypes = {
changeMediaAllowedTypes: PropTypes.func.isRequired, intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}).isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
styles: PropTypes.object.isRequired, onChange: PropTypes.func.isRequired,
value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
}; };

View File

@ -239,7 +239,8 @@ const advancedForm = {
defaultMessage: 'Select allowed types of media', defaultMessage: 'Select allowed types of media',
}, },
name: 'allowedTypes', name: 'allowedTypes',
type: 'allowedTypesSelect', type: 'allowed-types-select',
size: 7,
value: '', value: '',
validations: {}, validations: {},
}, },

View File

@ -1,7 +1,6 @@
export const ADD_COMPONENTS_TO_DYNAMIC_ZONE = export const ADD_COMPONENTS_TO_DYNAMIC_ZONE =
'ContentTypeBuilder/FormModal/ADD_COMPONENTS_TO_DYNAMIC_ZONE'; 'ContentTypeBuilder/FormModal/ADD_COMPONENTS_TO_DYNAMIC_ZONE';
export const ON_CHANGE = 'ContentTypeBuilder/FormModal/ON_CHANGE'; export const ON_CHANGE = 'ContentTypeBuilder/FormModal/ON_CHANGE';
export const ON_CHANGE_ALLOWED_TYPE = 'ContentTypeBuilder/FormModal/ON_CHANGE_ALLOWED_TYPE';
export const ON_CHANGE_RELATION_TARGET = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TARGET'; export const ON_CHANGE_RELATION_TARGET = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TARGET';
export const ON_CHANGE_RELATION_TYPE = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TYPE'; export const ON_CHANGE_RELATION_TYPE = 'ContentTypeBuilder/FormModal/ON_CHANGE_RELATION_TYPE';
export const RESET_PROPS = 'ContentTypeBuilder/FormModal/RESET_PROPS'; export const RESET_PROPS = 'ContentTypeBuilder/FormModal/RESET_PROPS';

View File

@ -25,6 +25,7 @@ import { Stack } from '@strapi/parts/Stack';
import pluginId from '../../pluginId'; import pluginId from '../../pluginId';
import useDataManager from '../../hooks/useDataManager'; import useDataManager from '../../hooks/useDataManager';
// New compos // New compos
import AllowedTypesSelect from '../AllowedTypesSelect';
import AttributeOptions from '../AttributeOptions'; import AttributeOptions from '../AttributeOptions';
import DraftAndPublishToggle from '../DraftAndPublishToggle'; import DraftAndPublishToggle from '../DraftAndPublishToggle';
import FormModalHeader from '../FormModalHeader'; import FormModalHeader from '../FormModalHeader';
@ -57,7 +58,6 @@ import {
SET_DYNAMIC_ZONE_DATA_SCHEMA, SET_DYNAMIC_ZONE_DATA_SCHEMA,
SET_ATTRIBUTE_DATA_SCHEMA, SET_ATTRIBUTE_DATA_SCHEMA,
// ADD_COMPONENTS_TO_DYNAMIC_ZONE, // ADD_COMPONENTS_TO_DYNAMIC_ZONE,
// ON_CHANGE_ALLOWED_TYPE,
SET_ERRORS, SET_ERRORS,
ON_CHANGE, ON_CHANGE,
RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ, RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ,
@ -564,14 +564,6 @@ const FormModal = () => {
// }); // });
// }; // };
// const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
// dispatch({
// type: ON_CHANGE_ALLOWED_TYPE,
// name,
// value,
// });
// };
const handleChange = useCallback( const handleChange = useCallback(
({ target: { name, value, type, ...rest } }) => { ({ target: { name, value, type, ...rest } }) => {
const namesThatCanResetToNullValue = [ const namesThatCanResetToNullValue = [
@ -1095,6 +1087,7 @@ const FormModal = () => {
const genericInputProps = { const genericInputProps = {
customInputs: { customInputs: {
'allowed-types-select': AllowedTypesSelect,
'checkbox-with-number-field': CheckboxWithNumberField, 'checkbox-with-number-field': CheckboxWithNumberField,
'select-default-boolean': BooleanDefaultValueSelect, 'select-default-boolean': BooleanDefaultValueSelect,
'radio-group': CustomRadioGroup, 'radio-group': CustomRadioGroup,

View File

@ -183,40 +183,7 @@ const reducer = (state = initialState, action) =>
break; break;
} }
case actions.ON_CHANGE_ALLOWED_TYPE: {
if (action.name === 'all') {
if (action.value) {
set(draftState, ['modifiedData', 'allowedTypes'], ['images', 'videos', 'files']);
break;
}
set(draftState, ['modifiedData', 'allowedTypes'], null);
break;
}
const currentList = state.modifiedData.allowedTypes || [];
let updatedList = [...currentList];
if (currentList.includes(action.name)) {
updatedList = updatedList.filter(v => v !== action.name);
if (updatedList.length === 0) {
set(draftState, ['modifiedData', 'allowedTypes'], null);
break;
}
set(draftState, ['modifiedData', 'allowedTypes'], updatedList);
break;
}
updatedList.push(action.name);
set(draftState, ['modifiedData', 'allowedTypes'], updatedList);
break;
}
case actions.RESET_PROPS: case actions.RESET_PROPS:
return initialState; return initialState;
case actions.RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO: { case actions.RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO: {

View File

@ -141,124 +141,6 @@ describe('CTB | components | FormModal | reducer | actions', () => {
}); });
}); });
describe('ON_CHANGE_ALLOWED_TYPE', () => {
it('Should add the missing types', () => {
const state = {
...initialState,
modifiedData: {
allowedTypes: ['images', 'videos'],
},
};
const action = {
name: 'all',
value: true,
type: actions.ON_CHANGE_ALLOWED_TYPE,
};
const expected = {
...initialState,
modifiedData: {
allowedTypes: ['images', 'videos', 'files'],
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('Should remove the missing types', () => {
const state = {
...initialState,
modifiedData: {
allowedTypes: ['images', 'videos', 'files'],
},
};
const action = {
name: 'all',
value: false,
type: actions.ON_CHANGE_ALLOWED_TYPE,
};
const expected = {
...initialState,
modifiedData: {
allowedTypes: null,
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('Shoul add the missing type', () => {
const state = {
...initialState,
modifiedData: {
allowedTypes: ['videos', 'files'],
},
};
const action = {
name: 'images',
value: null,
type: actions.ON_CHANGE_ALLOWED_TYPE,
};
const expected = {
...initialState,
modifiedData: {
allowedTypes: ['videos', 'files', 'images'],
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('Should remove the type', () => {
const state = {
...initialState,
modifiedData: {
allowedTypes: ['videos', 'images', 'files'],
},
};
const action = {
name: 'images',
value: null,
type: actions.ON_CHANGE_ALLOWED_TYPE,
};
const expected = {
...initialState,
modifiedData: {
allowedTypes: ['videos', 'files'],
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('Should remove set the allowedTypes to null if removing the last type', () => {
const state = {
...initialState,
modifiedData: {
allowedTypes: ['videos'],
},
};
const action = {
name: 'videos',
value: null,
type: actions.ON_CHANGE_ALLOWED_TYPE,
};
const expected = {
...initialState,
modifiedData: {
allowedTypes: null,
},
};
expect(reducer(state, action)).toEqual(expected);
});
});
describe('ON_CHANGE_RELATION_TARGET', () => { describe('ON_CHANGE_RELATION_TARGET', () => {
it('Should handle the target change correctly for a one side relation (oneWay, manyWay)', () => { it('Should handle the target change correctly for a one side relation (oneWay, manyWay)', () => {
const state = { const state = {