Fix CTM dz min max validations

This commit is contained in:
soupette 2019-12-11 16:52:35 +01:00
parent 4ad9fdef52
commit e29bd761e4
11 changed files with 94 additions and 25 deletions

View File

@ -43,6 +43,15 @@
"full_name": {
"type": "string",
"required": true
},
"dz": {
"type": "dynamiczone",
"components": [
"default.dish",
"default.openingtimes",
"default.restaurantservice"
],
"min": 2
}
}
}

View File

@ -18,12 +18,6 @@
"price": {
"type": "float"
},
"address": {
"model": "address"
},
"addresses": {
"collection": "address"
},
"picture": {
"model": "file",
"via": "related",

View File

@ -25,7 +25,7 @@ const ComponentWrapper = styled.div`
content: '&';
position: absolute;
top: -30px;
left: 22px;
left: 24.5px;
height: 100%;
width: 2px;
background-color: #e6f0fb;

View File

@ -10,7 +10,7 @@ const Label = styled.div`
content: '•';
position: absolute;
top: 15px;
left: 21.25px;
left: 21.5px;
font-size: 15px;
width: 8px;
height: 8px;

View File

@ -72,6 +72,10 @@ const DynamicZone = ({ max, min, name }) => {
get(dynamicZoneErrors, [0, 'id'], '').includes('min');
const hasRequiredError = hasError && !hasMinError;
const hasMaxError =
hasError &&
get(dynamicZoneErrors, [0, 'id'], '') ===
'components.Input.error.validation.max';
return (
<DynamicZoneWrapper>
@ -144,9 +148,14 @@ const DynamicZone = ({ max, min, name }) => {
}
}}
/>
{hasRequiredError && !isOpen && (
{hasRequiredError && !isOpen && !hasMaxError && (
<div className="error-label">Component is required</div>
)}
{hasMaxError && !isOpen && (
<div className="error-label">
<FormattedMessage id="components.Input.error.validation.max" />
</div>
)}
{hasMinError && !isOpen && (
<div className="error-label">
<FormattedMessage

View File

@ -128,7 +128,8 @@ const BannerWrapper = styled.button`
svg {
font-size: 10px;
path {
fill: #292b2c;
// fill: #292b2c;
fill: #4B515A;
}
}
}
@ -139,14 +140,18 @@ const BannerWrapper = styled.button`
}
${({ hasErrors, isOpen }) => {
let fill = '#B4B6BA';
// let fill = '#B4B6BA';
let fill = '#ABB3C2';
let trashFill = '#4B515A';
if (isOpen) {
fill = '#007EFF';
trashFill = '#007EFF';
}
if (hasErrors) {
fill = '#F64D0A';
fill = '#FAA684';
trashFill = '#F64D0A';
}
return `
@ -155,6 +160,13 @@ const BannerWrapper = styled.button`
fill: ${fill} !important;
}
}
.trash-icon {
svg {
path {
fill: ${trashFill} !important;
}
}
}
`;
}}

View File

@ -33,10 +33,13 @@ const EditViewDataManagerProvider = ({
initialData,
isLoading,
modifiedData,
modifiedDZName,
shouldShowLoadingState,
shouldCheckErrors,
} = reducerState.toJS();
console.log({ formErrors });
const currentContentTypeLayout = get(allLayoutData, ['contentType'], {});
const abortController = new AbortController();
const { signal } = abortController;
@ -167,6 +170,17 @@ const EditViewDataManagerProvider = ({
await schema.validate(updatedData, { abortEarly: false });
} catch (err) {
errors = getYupInnerErrors(err);
if (modifiedDZName) {
errors = Object.keys(errors).reduce((acc, current) => {
const dzName = current.split('.')[0];
if (dzName !== modifiedDZName) {
acc[current] = errors[current];
}
return acc;
}, {});
}
}
dispatch({
@ -313,10 +327,17 @@ const EditViewDataManagerProvider = ({
const removeComponentFromDynamicZone = (dynamicZoneName, index) => {
emitEvent('removeComponentFromDynamicZone');
const doesDZHaveError = Object.keys(formErrors).some(
key => key.split('.')[0] === dynamicZoneName
);
const shouldCheckErrors = !isEmpty(formErrors) && doesDZHaveError;
dispatch({
type: 'REMOVE_COMPONENT_FROM_DYNAMIC_ZONE',
dynamicZoneName,
index,
shouldCheckErrors,
});
};
const removeComponentFromField = (keys, componentUid) => {

View File

@ -9,6 +9,7 @@ const initialState = fromJS({
modifiedData: {},
shouldShowLoadingState: false,
shouldCheckErrors: false,
modifiedDZName: null,
});
const reducer = (state, action) => {
@ -57,6 +58,7 @@ const reducer = (state, action) => {
return fromJS([defaultDataStructure]);
})
.update('modifiedDZName', () => action.keys[0])
.update('shouldCheckErrors', v => {
if (action.shouldCheckErrors === true) {
return !v;
@ -152,11 +154,15 @@ const reducer = (state, action) => {
});
}
case 'REMOVE_COMPONENT_FROM_DYNAMIC_ZONE':
return state.deleteIn([
'modifiedData',
action.dynamicZoneName,
action.index,
]);
return state
.update('shouldCheckErrors', v => {
if (action.shouldCheckErrors) {
return !v;
}
return v;
})
.deleteIn(['modifiedData', action.dynamicZoneName, action.index]);
case 'REMOVE_COMPONENT_FROM_FIELD': {
const componentPathToRemove = ['modifiedData', ...action.keys];
@ -190,7 +196,9 @@ const reducer = (state, action) => {
.update('isLoading', () => false)
.update('modifiedData', () => fromJS(action.contentTypeDataStructure));
case 'SET_ERRORS':
return state.update('formErrors', () => fromJS(action.errors));
return state
.update('modifiedDZName', () => null)
.update('formErrors', () => fromJS(action.errors));
case 'SUBMIT_ERRORS':
return state
.update('formErrors', () => fromJS(action.errors))

View File

@ -1,4 +1,4 @@
import { get, isBoolean, isNaN } from 'lodash';
import { get, isBoolean, isEmpty, isNaN } from 'lodash';
import * as yup from 'yup';
import { translatedErrors as errorsTrads } from 'strapi-helper-plugin';
@ -10,6 +10,15 @@ yup.addMethod(yup.mixed, 'defined', function() {
);
});
yup.addMethod(yup.array, 'notEmptyMin', function(min) {
return this.test('notEmptyMin', errorsTrads.min, value => {
if (isEmpty(value)) {
return true;
}
return value.length > min;
});
});
const getAttributes = data => get(data, ['schema', 'attributes'], {});
const createYupSchema = (model, { components }) => {
@ -110,7 +119,7 @@ const createYupSchema = (model, { components }) => {
}
} else {
if (min) {
dynamicZoneSchema = dynamicZoneSchema.min(min, errorsTrads.min);
dynamicZoneSchema = dynamicZoneSchema.notEmptyMin(min);
}
}

View File

@ -108,6 +108,10 @@ const forms = {
schema = schema.integer();
}
if (attributeType === 'dynamiczone') {
schema = schema.positive();
}
return schema.nullable();
}),
min: yup.lazy(() => {
@ -121,14 +125,15 @@ const forms = {
schema = schema.integer();
}
if (attributeType === 'dynamiczone') {
schema = schema.positive();
}
return schema
.nullable()
.when('max', (max, schema) => {
if (max) {
return schema.lessThan(
max,
getTrad('error.validation.minSupMax')
);
return schema.max(max, getTrad('error.validation.minSupMax'));
} else {
return schema;
}
@ -146,7 +151,7 @@ const forms = {
.integer()
.when('maxLength', (maxLength, schema) => {
if (maxLength) {
return schema.lessThan(
return schema.max(
maxLength,
getTrad('error.validation.minSupMax')
);

View File

@ -41,6 +41,7 @@
"contentType.collectionName.description": "Useful when the name of your Content Type and your table name differ",
"contentType.collectionName.label": "Collection name",
"contentType.displayName.label": "Display name",
"error.validation.minSupMax": "Can't be superior",
"form.attribute.component.option.add": "Add a component",
"form.attribute.component.option.create": "Create a new component",
"form.attribute.component.option.create.description": "A component is shared across types and components, it will be available and accessible everywhere.",
@ -96,6 +97,7 @@
"form.button.save": "Save",
"form.button.select-component": "Select a component",
"from": "from",
"injected-components.content-manager.edit-settings-view.link.content-types": "Edit the content type",
"injected-components.content-manager.edit-settings-view.link.components": "Edit the component",
"menu.section.components.name.plural": "Components",