From 432bcda8d177f0c0a952a8f459ebd66deda5757d Mon Sep 17 00:00:00 2001 From: Max Chopart Date: Tue, 23 Apr 2024 18:17:56 +0200 Subject: [PATCH] [Upd #193] Refactor into functional component to support intl --- src/components/FormManager.jsx | 94 +++++----- src/components/Question.jsx | 7 +- src/components/wizard/WizardStep.jsx | 1 + src/i18n/cs.json | 9 +- src/i18n/en.json | 9 +- src/model/ValidatorFactory.js | 263 +++++++++++++-------------- 6 files changed, 195 insertions(+), 188 deletions(-) diff --git a/src/components/FormManager.jsx b/src/components/FormManager.jsx index 4a9fff13..b7a8cd85 100644 --- a/src/components/FormManager.jsx +++ b/src/components/FormManager.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useContext } from "react"; import QuestionAnswerProcessor from "../model/QuestionAnswerProcessor"; import { FormQuestionsContext } from "../contexts/FormQuestionsContext"; import Wizard from "./wizard/Wizard"; @@ -7,11 +7,16 @@ import { Card } from "react-bootstrap"; import Question from "./Question"; import FormUtils from "../util/FormUtils.js"; import ValidationProcessor from "../model/ValidationProcessor.js"; +import { useIntl } from "react-intl"; -class FormManager extends React.Component { - getFormData = () => { - const data = this.context.getData(); - const formQuestionsData = this.context.getFormQuestionsData(); +const FormManager = (props) => { + const { getFormQuestionsData, updateFormQuestionsData, getData } = + useContext(FormQuestionsContext); + const intl = useIntl(); + + const getFormData = () => { + const data = getData(); + const formQuestionsData = getFormQuestionsData(); return QuestionAnswerProcessor.buildQuestionAnswerModel( data, @@ -20,86 +25,77 @@ class FormManager extends React.Component { }; //TODO: Add optional argument "isRequiredForCompleteness" - validateForm = () => { - const questions = this.context.getFormQuestionsData(); + const validateForm = () => { + const questions = getFormQuestionsData(); for (let i = 0; i < questions.length; i++) { const question = questions[i]; - //TODO: Convert to functional component to add intl from intl context ValidationProcessor.updateQuestionValidation( questions, question, i, - "en" + intl.locale ); } - this.context.updateFormQuestionsData(null, questions); - }; - - getFormQuestionsData = () => { - return this.context.getFormQuestionsData(); + updateFormQuestionsData(null, questions); }; - getFormSpecification = () => { - const questions = this.context.getFormQuestionsData(); + const getFormSpecification = () => { + const questions = getFormQuestionsData(); return FormUtils.getFormSpecification(questions); }; - handleStepChange = (question, index, change) => { - this.context.updateFormQuestionsData(index, { ...question, ...change }); + const handleStepChange = (question, index, change) => { + updateFormQuestionsData(index, { ...question, ...change }); }; - renderWizardlessForm = () => { - const formQuestionsData = this.context.getFormQuestionsData(); + const renderWizardlessForm = () => { + const formQuestionsData = getFormQuestionsData(); return ( - {formQuestionsData.map((q, i) => this._mapQuestion(q, i))} + {formQuestionsData.map((q, i) => _mapQuestion(q, i))} ); }; - _mapQuestion(question, index) { - let component = this.props.mapComponent(question, Question); + const _mapQuestion = (question, index) => { + let component = props.mapComponent(question, Question); return React.createElement(component, { key: question["@id"], question: question, - onChange: (index, change) => - this.handleStepChange(question, index, change), + onChange: (index, change) => handleStepChange(question, index, change), index: index, + intl: intl, }); - } - - render() { - const { modalView } = this.props; + }; - const formQuestionsData = this.context.getFormQuestionsData(); + const { modalView } = props; - if (!formQuestionsData.length) { - return ( - - There are no questions available... - - ); - } + const formQuestionsData = getFormQuestionsData(); - const isWizardless = formQuestionsData.every( - (question) => !FormUtils.isWizardStep(question) + if (!formQuestionsData.length) { + return ( + + There are no questions available... + ); + } - if (modalView) { - return ( - - {isWizardless ? this.renderWizardlessForm() : } - - ); - } + const isWizardless = formQuestionsData.every( + (question) => !FormUtils.isWizardStep(question) + ); - return isWizardless ? this.renderWizardlessForm() : ; + if (modalView) { + return ( + + {isWizardless ? renderWizardlessForm() : } + + ); } -} -FormManager.contextType = FormQuestionsContext; + return isWizardless ? renderWizardlessForm() : ; +}; export default FormManager; diff --git a/src/components/Question.jsx b/src/components/Question.jsx index e4a83ab0..64ed0a12 100644 --- a/src/components/Question.jsx +++ b/src/components/Question.jsx @@ -7,7 +7,7 @@ import Constants from "../constants/Constants"; import FormUtils from "../util/FormUtils"; import JsonLdObjectMap from "../util/JsonLdObjectMap"; import QuestionAnswerProcessor from "../model/QuestionAnswerProcessor"; -import ValidatorFactory from "../model/ValidatorFactory"; +import { createValidator } from "../model/ValidatorFactory"; import JsonLdObjectUtils from "../util/JsonLdObjectUtils"; import PrefixIcon from "./PrefixIcon"; import MediaContent from "./MediaContent"; @@ -33,10 +33,7 @@ export default class Question extends React.Component { componentDidMount() { this.setState({ - validator: ValidatorFactory.createValidator( - this.props.question, - this.context.options.intl - ), + validator: createValidator(this.props.question, this.props.intl), }); } diff --git a/src/components/wizard/WizardStep.jsx b/src/components/wizard/WizardStep.jsx index 264cd018..cbe2b2a0 100644 --- a/src/components/wizard/WizardStep.jsx +++ b/src/components/wizard/WizardStep.jsx @@ -57,6 +57,7 @@ const WizardStep = (props) => { question={question} onChange={onChange} collapsible={FormUtils.isAnswerable(question)} + intl={intl} /> {props.options.wizardStepButtons && _renderWizardStepButtons()} diff --git a/src/i18n/cs.json b/src/i18n/cs.json index 6a016dc6..4c3374a1 100644 --- a/src/i18n/cs.json +++ b/src/i18n/cs.json @@ -5,5 +5,12 @@ "wizard.next": "Další", "wizard.previous": "Předchozí", "section.expand": "Rozbalit", - "section.collapse": "Sbalit" + "section.collapse": "Sbalit", + + "validation.required": "Toto pole je povinné.", + "validation.required_only_for_completeness": "Toto pole je povinné pro vyplnění formuláře.", + "validation.invalid": "Toto pole je neplatné.", + "validation.check": "Toto pole musí být zkontrolováno.", + "validation.lower_or_equal": "Toto pole by mělo být číslo rovné nebo nižší než ", + "validation.greater_or_equal": "Toto pole musí být větší nebo rovno " } diff --git a/src/i18n/en.json b/src/i18n/en.json index 2cb17cc6..43231dcb 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -5,5 +5,12 @@ "wizard.next": "Next", "wizard.previous": "Previous", "section.expand": "Expand", - "section.collapse": "Collapse" + "section.collapse": "Collapse", + + "validation.required": "This field is required.", + "validation.required_only_for_completeness": "This field is required to complete the form.", + "validation.invalid": "This field is invalid.", + "validation.check": "This field must be checked.", + "validation.lower_or_equal": "This field should be a number equal or lower to ", + "validation.greater_or_equal": "This field must be greater or equal to " } diff --git a/src/model/ValidatorFactory.js b/src/model/ValidatorFactory.js index fa90f698..e0504ae1 100644 --- a/src/model/ValidatorFactory.js +++ b/src/model/ValidatorFactory.js @@ -1,180 +1,179 @@ /** * Created by blcha on 4.11.16. */ - -import * as JsonLdUtils from "jsonld-utils"; - import Constants from "../constants/Constants"; import FormUtils from "../util/FormUtils"; -export default class ValidatorFactory { - static createValidator(question, intl) { - const validators = [ - this._intMaxInclusiveValidator, - this._intMinInclusiveValidator, - this._patternValidator, - this._checkboxValidator, - this._requiredValidator, - this._completenessValidator, - ]; - - return () => { - if (FormUtils.hasValidationLogic(question)) { - const answerValue = FormUtils.getAnswerValue(question); - return this._validateAnswer(question, intl, answerValue, validators); - } - }; - } +const createValidator = (question, intl) => { + const validators = [ + _intMaxInclusiveValidator, + _intMinInclusiveValidator, + _patternValidator, + _checkboxValidator, + _requiredValidator, + _completenessValidator, + ]; - static _validateAnswer(question, intl, answerValue, validators) { - const result = {}; - for (const validator of validators) { - const validationResult = validator(question, intl, answerValue); - if (!validationResult.isValid) { - result[Constants.HAS_VALID_ANSWER] = false; - result[Constants.HAS_VALIDATION_MESSAGE] = validationResult.message; - result[Constants.HAS_VALIDATION_SEVERITY] = - validationResult.validationSeverity; - return result; - } - if (result[Constants.HAS_VALID_ANSWER] === false) { - break; - } + return () => { + if (FormUtils.hasValidationLogic(question, intl)) { + const answerValue = FormUtils.getAnswerValue(question); + // console.log(question); + // console.log(intl); + return _validateAnswer(question, intl, answerValue, validators); } - result[Constants.HAS_VALID_ANSWER] = true; - result[Constants.HAS_VALIDATION_MESSAGE] = ""; - result[Constants.HAS_VALIDATION_SEVERITY] = ""; - return result; - } + }; +}; - static _patternValidator(question, intl) { - const answerValue = FormUtils.getAnswerValue(question); - if (answerValue && answerValue.length > 0) { - if (question[Constants.PATTERN]) { - let pattern = question[Constants.PATTERN]; - const regExp = new RegExp(pattern); - const isValid = - regExp.test(answerValue) || !FormUtils.hasAnswer(question); - if (!isValid) { - return { - isValid: false, - validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, - message: question[Constants.HAS_VALIDATION_MESSAGE] - ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE.INVALID, - }; - } - } +const _validateAnswer = (question, intl, answerValue, validators) => { + const result = {}; + for (const validator of validators) { + const validationResult = validator(question, intl); + if (!validationResult.isValid) { + result[Constants.HAS_VALID_ANSWER] = false; + result[Constants.HAS_VALIDATION_MESSAGE] = validationResult.message; + result[Constants.HAS_VALIDATION_SEVERITY] = + validationResult.validationSeverity; + return result; + } + if (result[Constants.HAS_VALID_ANSWER] === false) { + break; } - return { isValid: true }; } + result[Constants.HAS_VALID_ANSWER] = true; + result[Constants.HAS_VALIDATION_MESSAGE] = ""; + result[Constants.HAS_VALIDATION_SEVERITY] = ""; + return result; +}; - static _requiredValidator(question, intl) { - if ( - question[Constants.REQUIRES_ANSWER] && - !question[Constants.USED_ONLY_FOR_COMPLETENESS] - ) { - const isValid = FormUtils.hasAnswer(question); +const _patternValidator = (question, intl) => { + const answerValue = FormUtils.getAnswerValue(question); + if (answerValue && answerValue.length > 0) { + if (question[Constants.PATTERN]) { + let pattern = question[Constants.PATTERN]; + const regExp = new RegExp(pattern); + const isValid = + regExp.test(answerValue) || !FormUtils.hasAnswer(question); if (!isValid) { return { isValid: false, validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, message: question[Constants.HAS_VALIDATION_MESSAGE] ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE.REQUIRED, + : intl.formatMessage({ id: "validation.invalid" }), }; } } - return { isValid: true }; } + return { isValid: true }; +}; - static _checkboxValidator(question, intl) { - if (FormUtils.isCheckbox(question)) { - if (question[Constants.REQUIRES_ANSWER]) { - const isValid = FormUtils.hasAnswer(question); - if (!isValid) { - return { - isValid: false, - validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, - message: question[Constants.HAS_VALIDATION_MESSAGE] - ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE.CHECK, - }; - } - } +const _requiredValidator = (question, intl) => { + if ( + question[Constants.REQUIRES_ANSWER] && + !question[Constants.USED_ONLY_FOR_COMPLETENESS] + ) { + const isValid = FormUtils.hasAnswer(question); + if (!isValid) { + return { + isValid: false, + validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, + message: question[Constants.HAS_VALIDATION_MESSAGE] + ? question[Constants.HAS_VALIDATION_MESSAGE] + : intl.formatMessage({ id: "validation.required" }), + }; } - return { isValid: true }; } + return { isValid: true }; +}; - static _completenessValidator(question, intl) { - if ( - question[Constants.REQUIRES_ANSWER] && - question[Constants.USED_ONLY_FOR_COMPLETENESS] - ) { +const _checkboxValidator = (question, intl) => { + if (FormUtils.isCheckbox(question)) { + if (question[Constants.REQUIRES_ANSWER]) { const isValid = FormUtils.hasAnswer(question); if (!isValid) { return { isValid: false, - validationSeverity: Constants.VALIDATION.SEVERITY.WARNING, + validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, message: question[Constants.HAS_VALIDATION_MESSAGE] ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE - .REQUIRED_ONLY_FOR_COMPLETENESS, + : intl.formatMessage({ id: "validation.check" }), }; } } - return { isValid: true }; } + return { isValid: true }; +}; - static _intMinInclusiveValidator(question, intl) { - if (question[Constants.XSD.MIN_INCLUSIVE]) { - const answerValue = FormUtils.getAnswerValue(question); - if (answerValue && answerValue.length > 0) { - const minInclusive = question[Constants.XSD.MIN_INCLUSIVE]; +const _completenessValidator = (question, intl) => { + // console.log(intl); + if ( + question[Constants.REQUIRES_ANSWER] && + question[Constants.USED_ONLY_FOR_COMPLETENESS] + ) { + const isValid = FormUtils.hasAnswer(question); + if (!isValid) { + return { + isValid: false, + validationSeverity: Constants.VALIDATION.SEVERITY.WARNING, + message: question[Constants.HAS_VALIDATION_MESSAGE] + ? question[Constants.HAS_VALIDATION_MESSAGE] + : intl.formatMessage({ + id: "validation.required_only_for_completeness", + }), + }; + } + } + return { isValid: true }; +}; - const isValid = - Number.isInteger(parseInt(answerValue)) && - answerValue >= minInclusive; +const _intMinInclusiveValidator = (question, intl) => { + if (question[Constants.XSD.MIN_INCLUSIVE]) { + const answerValue = FormUtils.getAnswerValue(question); + if (answerValue && answerValue.length > 0) { + const minInclusive = question[Constants.XSD.MIN_INCLUSIVE]; + + const isValid = + Number.isInteger(parseInt(answerValue)) && answerValue >= minInclusive; - if (!isValid) { - return { - isValid: false, - validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, - message: question[Constants.HAS_VALIDATION_MESSAGE] - ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE.GREATER_OR_EQUAL + - minInclusive + - ".", - }; - } + if (!isValid) { + return { + isValid: false, + validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, + message: question[Constants.HAS_VALIDATION_MESSAGE] + ? question[Constants.HAS_VALIDATION_MESSAGE] + : intl.formatMessage({ id: "validation.greater_or_equal" }) + + minInclusive + + ".", + }; } } - return { isValid: true }; } + return { isValid: true }; +}; - static _intMaxInclusiveValidator(question, intl) { - const answerValue = FormUtils.getAnswerValue(question); - if (question[Constants.XSD.MAX_INCLUSIVE]) { - if (answerValue && answerValue.length > 0) { - const maxInclusive = question[Constants.XSD.MAX_INCLUSIVE]; +const _intMaxInclusiveValidator = (question, intl) => { + const answerValue = FormUtils.getAnswerValue(question); + if (question[Constants.XSD.MAX_INCLUSIVE]) { + if (answerValue && answerValue.length > 0) { + const maxInclusive = question[Constants.XSD.MAX_INCLUSIVE]; - const isValid = - Number.isInteger(parseInt(answerValue)) && - answerValue <= maxInclusive; + const isValid = + Number.isInteger(parseInt(answerValue)) && answerValue <= maxInclusive; - if (!isValid) { - return { - isValid: false, - validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, - message: question[Constants.HAS_VALIDATION_MESSAGE] - ? question[Constants.HAS_VALIDATION_MESSAGE] - : Constants.VALIDATION.DEFAULT_MESSAGE.LOWER_OR_EQUAL + - maxInclusive + - ".", - }; - } + if (!isValid) { + return { + isValid: false, + validationSeverity: Constants.VALIDATION.SEVERITY.ERROR, + message: question[Constants.HAS_VALIDATION_MESSAGE] + ? question[Constants.HAS_VALIDATION_MESSAGE] + : intl.formatMessage({ id: "validation.lower_or_equal" }) + + maxInclusive + + ".", + }; } } - return { isValid: true }; } -} + return { isValid: true }; +}; + +export { createValidator };