diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 6f1407d5b..af8f94464 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -265,37 +265,104 @@ export default function TaskShow() { return null; }; + const formatDateString = (dateString?: string) => { + let dateObject = new Date(); + if (dateString) { + dateObject = new Date(dateString); + } + return dateObject.toISOString().split('T')[0]; + }; + + const checkFieldComparisons = ( + formData: any, + propertyKey: string, + propertyMetadata: any, + formattedDateString: string, + errors: any + ) => { + const fieldIdentifierToCompareWith = propertyMetadata.minimumDate.replace( + /^field:/, + '' + ); + if (fieldIdentifierToCompareWith in formData) { + const dateToCompareWith = formData[fieldIdentifierToCompareWith]; + if (dateToCompareWith) { + const dateStringToCompareWith = formatDateString(dateToCompareWith); + if (dateStringToCompareWith > formattedDateString) { + errors[propertyKey].addError( + `must be equal to or greater than '${fieldIdentifierToCompareWith}'` + ); + } + } else { + errors[propertyKey].addError( + `was supposed to be compared against '${fieldIdentifierToCompareWith}' but that field did not have a value` + ); + } + } else { + errors[propertyKey].addError( + `was supposed to be compared against '${fieldIdentifierToCompareWith}' but it either doesn't have a value or does not exist` + ); + } + }; + + const checkMinimumDate = ( + formData: any, + propertyKey: string, + propertyMetadata: any, + errors: any + ) => { + const dateString = formData[propertyKey]; + if (dateString) { + const formattedDateString = formatDateString(dateString); + if (propertyMetadata.minimumDate === 'today') { + const dateTodayString = formatDateString(); + if (dateTodayString > formattedDateString) { + errors[propertyKey].addError('must be today or after'); + } + } else if (propertyMetadata.minimumDate.startsWith('field:')) { + checkFieldComparisons( + formData, + propertyKey, + propertyMetadata, + formattedDateString, + errors + ); + } + } + }; + const getFieldsWithDateValidations = ( jsonSchema: any, formData: any, errors: any + // eslint-disable-next-line sonarjs/cognitive-complexity ) => { - if ('properties' in jsonSchema) { - Object.keys(jsonSchema.properties).forEach((propertyKey: string) => { - const propertyMetadata = jsonSchema.properties[propertyKey]; - if ( - typeof propertyMetadata === 'object' && - 'minimumDate' in propertyMetadata && - propertyMetadata.minimumDate === 'today' - ) { - const dateToday = new Date(); - const dateValue = formData[propertyKey]; - if (dateValue) { - const dateValueObject = new Date(dateValue); - const dateValueString = dateValueObject.toISOString().split('T')[0]; - const dateTodayString = dateToday.toISOString().split('T')[0]; - if (dateTodayString > dateValueString) { - errors[propertyKey].addError('must be today or after'); - } - } + // if the jsonSchema has an items attribute then assume the element itself + // doesn't have a custom validation but it's children could so use that + const jsonSchemaToUse = + 'items' in jsonSchema ? jsonSchema.items : jsonSchema; + + if ('properties' in jsonSchemaToUse) { + Object.keys(jsonSchemaToUse.properties).forEach((propertyKey: string) => { + const propertyMetadata = jsonSchemaToUse.properties[propertyKey]; + if ('minimumDate' in propertyMetadata) { + checkMinimumDate(formData, propertyKey, propertyMetadata, errors); } // recurse through all nested properties as well - getFieldsWithDateValidations( - propertyMetadata, - formData[propertyKey], - errors[propertyKey] - ); + let formDataToSend = formData[propertyKey]; + if (formDataToSend) { + if (formDataToSend.constructor.name !== 'Array') { + formDataToSend = [formDataToSend]; + } + formDataToSend.forEach((item: any, index: number) => { + let errorsToSend = errors[propertyKey]; + if (index in errorsToSend) { + errorsToSend = errorsToSend[index]; + } + getFieldsWithDateValidations(propertyMetadata, item, errorsToSend); + }); + } }); } return errors;