From 4f0b87cda4ca7212708d51a8a063752c9199640e Mon Sep 17 00:00:00 2001 From: Maximiliano forlenza Date: Tue, 31 Jan 2023 17:23:57 -0300 Subject: [PATCH] feat(date): add date component --- package-lock.json | 219 +++++++++++++++++- package.json | 2 + src/components/DatePicker/DatePicker.js | 72 ++++++ .../DatePicker/DatePicker.stories.js | 146 ++++++++++++ .../DatePicker/DatePickerSelector.js | 22 ++ src/components/DatePicker/index.js | 3 + .../QuestionBuilder/QuestionBuilder.js | 15 ++ src/components/Radio/Radio.stories.js | 2 +- src/components/TextField/TextField.js | 9 +- src/constants/dateTypes.js | 6 + src/utils/buildQuestions.js | 9 + src/utils/buildYupSchema.js | 20 +- src/utils/propTypes/formikField.js | 5 +- 13 files changed, 522 insertions(+), 8 deletions(-) create mode 100644 src/components/DatePicker/DatePicker.js create mode 100644 src/components/DatePicker/DatePicker.stories.js create mode 100644 src/components/DatePicker/DatePickerSelector.js create mode 100644 src/components/DatePicker/index.js create mode 100644 src/constants/dateTypes.js diff --git a/package-lock.json b/package-lock.json index 3a51b8c..0b96412 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,20 @@ { "name": "@indec/form-builder", - "version": "1.0.0", + "version": "1.2.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@indec/form-builder", - "version": "1.0.0", + "version": "1.2.2", "license": "ISC", "dependencies": { "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", "@mui/icons-material": "^5.11.0", "@mui/material": "^5.11.3", + "@mui/x-date-pickers": "^5.0.16", + "date-fns": "^2.29.3", "formik": "^2.2.9", "framer-motion": "^8.1.9", "prop-types": "^15.8.1", @@ -2548,6 +2550,75 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@date-io/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.16.0.tgz", + "integrity": "sha512-DYmSzkr+jToahwWrsiRA2/pzMEtz9Bq1euJwoOuYwuwIYXnZFtHajY2E6a1VNVDc9jP8YUXK1BvnZH9mmT19Zg==" + }, + "node_modules/@date-io/date-fns": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.16.0.tgz", + "integrity": "sha512-bfm5FJjucqlrnQcXDVU5RD+nlGmL3iWgkHTq3uAZWVIuBu6dDmGa3m8a6zo2VQQpu8ambq9H22UyUpn7590joA==", + "dependencies": { + "@date-io/core": "^2.16.0" + }, + "peerDependencies": { + "date-fns": "^2.0.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + } + } + }, + "node_modules/@date-io/dayjs": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.16.0.tgz", + "integrity": "sha512-y5qKyX2j/HG3zMvIxTobYZRGnd1FUW2olZLS0vTj7bEkBQkjd2RO7/FEwDY03Z1geVGlXKnzIATEVBVaGzV4Iw==", + "dependencies": { + "@date-io/core": "^2.16.0" + }, + "peerDependencies": { + "dayjs": "^1.8.17" + }, + "peerDependenciesMeta": { + "dayjs": { + "optional": true + } + } + }, + "node_modules/@date-io/luxon": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.16.1.tgz", + "integrity": "sha512-aeYp5K9PSHV28946pC+9UKUi/xMMYoaGelrpDibZSgHu2VWHXrr7zWLEr+pMPThSs5vt8Ei365PO+84pCm37WQ==", + "dependencies": { + "@date-io/core": "^2.16.0" + }, + "peerDependencies": { + "luxon": "^1.21.3 || ^2.x || ^3.x" + }, + "peerDependenciesMeta": { + "luxon": { + "optional": true + } + } + }, + "node_modules/@date-io/moment": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.16.1.tgz", + "integrity": "sha512-JkxldQxUqZBfZtsaCcCMkm/dmytdyq5pS1RxshCQ4fHhsvP5A7gSqPD22QbVXMcJydi3d3v1Y8BQdUKEuGACZQ==", + "dependencies": { + "@date-io/core": "^2.16.0" + }, + "peerDependencies": { + "moment": "^2.24.0" + }, + "peerDependenciesMeta": { + "moment": { + "optional": true + } + } + }, "node_modules/@design-systems/utils": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/@design-systems/utils/-/utils-2.12.0.tgz", @@ -5151,6 +5222,64 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@mui/x-date-pickers": { + "version": "5.0.16", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.16.tgz", + "integrity": "sha512-dfnz9e/zyYXMFH08PKhYHatBLzCt3hnEmbReaKTW+9FXLeZ8hTm4wM3IZi5kplEZuV5aVBJGzynwQ1o3EBoxoA==", + "dependencies": { + "@babel/runtime": "^7.18.9", + "@date-io/core": "^2.15.0", + "@date-io/date-fns": "^2.15.0", + "@date-io/dayjs": "^2.15.0", + "@date-io/luxon": "^2.15.0", + "@date-io/moment": "^2.15.0", + "@mui/utils": "^5.10.3", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "prop-types": "^15.7.2", + "react-transition-group": "^4.4.5", + "rifm": "^0.12.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.4.1", + "@mui/system": "^5.4.1", + "date-fns": "^2.25.0", + "dayjs": "^1.10.7", + "luxon": "^1.28.0 || ^2.0.0 || ^3.0.0", + "moment": "^2.29.1", + "react": "^17.0.2 || ^18.0.0", + "react-dom": "^17.0.2 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -17152,6 +17281,18 @@ "node": ">=12" } }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -29660,6 +29801,14 @@ "node": ">=0.10.0" } }, + "node_modules/rifm": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz", + "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==", + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -35224,6 +35373,43 @@ } } }, + "@date-io/core": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.16.0.tgz", + "integrity": "sha512-DYmSzkr+jToahwWrsiRA2/pzMEtz9Bq1euJwoOuYwuwIYXnZFtHajY2E6a1VNVDc9jP8YUXK1BvnZH9mmT19Zg==" + }, + "@date-io/date-fns": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.16.0.tgz", + "integrity": "sha512-bfm5FJjucqlrnQcXDVU5RD+nlGmL3iWgkHTq3uAZWVIuBu6dDmGa3m8a6zo2VQQpu8ambq9H22UyUpn7590joA==", + "requires": { + "@date-io/core": "^2.16.0" + } + }, + "@date-io/dayjs": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.16.0.tgz", + "integrity": "sha512-y5qKyX2j/HG3zMvIxTobYZRGnd1FUW2olZLS0vTj7bEkBQkjd2RO7/FEwDY03Z1geVGlXKnzIATEVBVaGzV4Iw==", + "requires": { + "@date-io/core": "^2.16.0" + } + }, + "@date-io/luxon": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.16.1.tgz", + "integrity": "sha512-aeYp5K9PSHV28946pC+9UKUi/xMMYoaGelrpDibZSgHu2VWHXrr7zWLEr+pMPThSs5vt8Ei365PO+84pCm37WQ==", + "requires": { + "@date-io/core": "^2.16.0" + } + }, + "@date-io/moment": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.16.1.tgz", + "integrity": "sha512-JkxldQxUqZBfZtsaCcCMkm/dmytdyq5pS1RxshCQ4fHhsvP5A7gSqPD22QbVXMcJydi3d3v1Y8BQdUKEuGACZQ==", + "requires": { + "@date-io/core": "^2.16.0" + } + }, "@design-systems/utils": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/@design-systems/utils/-/utils-2.12.0.tgz", @@ -37188,6 +37374,25 @@ "react-is": "^18.2.0" } }, + "@mui/x-date-pickers": { + "version": "5.0.16", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.16.tgz", + "integrity": "sha512-dfnz9e/zyYXMFH08PKhYHatBLzCt3hnEmbReaKTW+9FXLeZ8hTm4wM3IZi5kplEZuV5aVBJGzynwQ1o3EBoxoA==", + "requires": { + "@babel/runtime": "^7.18.9", + "@date-io/core": "^2.15.0", + "@date-io/date-fns": "^2.15.0", + "@date-io/dayjs": "^2.15.0", + "@date-io/luxon": "^2.15.0", + "@date-io/moment": "^2.15.0", + "@mui/utils": "^5.10.3", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "prop-types": "^15.7.2", + "react-transition-group": "^4.4.5", + "rifm": "^0.12.1" + } + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -46565,6 +46770,11 @@ "whatwg-url": "^11.0.0" } }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -56194,6 +56404,11 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rifm": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz", + "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/package.json b/package.json index 3d11047..49cbafa 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,8 @@ "@emotion/styled": "^11.10.5", "@mui/icons-material": "^5.11.0", "@mui/material": "^5.11.3", + "@mui/x-date-pickers": "^5.0.16", + "date-fns": "^2.29.3", "formik": "^2.2.9", "framer-motion": "^8.1.9", "prop-types": "^15.8.1", diff --git a/src/components/DatePicker/DatePicker.js b/src/components/DatePicker/DatePicker.js new file mode 100644 index 0000000..8b92bc5 --- /dev/null +++ b/src/components/DatePicker/DatePicker.js @@ -0,0 +1,72 @@ +import PropTypes from 'prop-types'; +import {es} from 'date-fns/locale'; +import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns'; +import {LocalizationProvider} from '@mui/x-date-pickers/LocalizationProvider'; +import MuiInputLabel from '@mui/material/InputLabel'; +import Stack from '@mui/material/Stack'; + +import dateTypes from '@/constants/dateTypes'; +import formikField from '@/utils/propTypes/formikField'; +import formikForm from '@/utils/propTypes/formikForm'; + +import TextField from '../TextField'; +import DateTimePickerSelector from './DatePickerSelector'; + +function DatePicker({ + metadata: {dateType}, field, label, required, form, ...props +}) { + const isRange = [dateTypes.RANGE_WITHOUT_HOUR, dateTypes.RANGE_WITH_HOUR].includes(dateType); + return ( + + {label} + + form.setFieldValue(isRange ? `${field.name}.start` : field.name, newValue)} + renderInput={params => ( + + )} + /> + {isRange && ( + form.setFieldValue(`${field.name}.end`, newValue)} + renderInput={params => ( + + )} + minDateTime={new Date(field.value.start)} + disabled={!field.value.start} + /> + )} + + + ); +} + +DatePicker.propTypes = { + label: PropTypes.string.isRequired, + field: formikField.isRequired, + form: formikForm.isRequired, + required: PropTypes.bool.isRequired, + metadata: PropTypes.shape({ + dateType: PropTypes.oneOf(Object.values(dateTypes)).isRequired + }).isRequired +}; + +export default DatePicker; diff --git a/src/components/DatePicker/DatePicker.stories.js b/src/components/DatePicker/DatePicker.stories.js new file mode 100644 index 0000000..9e2e534 --- /dev/null +++ b/src/components/DatePicker/DatePicker.stories.js @@ -0,0 +1,146 @@ +import React from 'react'; +import {Formik, Field} from 'formik'; +import Button from '@mui/material/Button'; + +import getWarnings from '@/utils/getWarnings'; +import getSchemas from '@/utils/getSchemas'; + +import DatePicker from './DatePicker'; + +export default { + title: 'Date', + component: DatePicker, + argTypes: { + backgroundColor: {control: 'color'} + } +}; + +function Template(args) { + const { + withErrors, withWarnings, initialValues, section, ...props + } = args; + const {errorSchema: validateSchema, warningSchema} = getSchemas(section); + return ( + + {({values, submitForm}) => { + const warnings = withWarnings ? getWarnings(warningSchema, values) || {} : {}; + return ( + <> + + { + withErrors + ? + : null + } + + ); + }} + + ); +} + +const section = dateType => ({ + id: 1, + name: 'S1', + label: 'Sección 1', + questions: [ + { + id: 1, + label: 'Select a date', + name: 'S1P1', + number: '1', + type: 6, + metadata: {dateType}, + validations: [ + { + id: 1, + type: 'required', + params: [ + { + id: 1, + message: 'Must select a date' + } + ], + messageType: 'error' + } + ], + userVarName: 's1p1' + } + ], + userVarName: 's1' +}); + +export const Basic = Template.bind({}); +Basic.args = { + readOnlyMode: false, + label: 'Select dates', + required: false, + name: 'S1.0.S1P1.answer', + warnings: {}, + metadata: { + dateType: 'dateWithoutHour' + }, + initialValues: {S1: [{S1P1: {id: 1, answer: ''}}]}, + section: section('dateWithoutHour') +}; + +export const DateWithHour = Template.bind({}); +DateWithHour.args = { + readOnlyMode: false, + label: 'Select dates', + required: false, + name: 'S1.0.S1P1.answer', + warnings: {}, + metadata: { + dateType: 'dateWithHour' + }, + initialValues: {S1: [{S1P1: {id: 1, answer: ''}}]}, + section: section('dateWithHour') +}; + +export const RangeWithoutHour = Template.bind({}); +RangeWithoutHour.args = { + readOnlyMode: false, + label: 'Select dates', + required: false, + name: 'S1.0.S1P1.answer', + warnings: {}, + metadata: { + dateType: 'rangeWithoutHour' + }, + initialValues: {S1: [{S1P1: {id: 1, answer: {start: '', end: ''}}}]}, + section: section('rangeWithoutHour') +}; + +export const RangeWithHour = Template.bind({}); +RangeWithHour.args = { + readOnlyMode: false, + label: 'Select dates', + required: false, + name: 'S1.0.S1P1.answer', + warnings: {}, + metadata: { + dateType: 'rangeWithHour' + }, + initialValues: {S1: [{S1P1: {id: 1, answer: {start: '', end: ''}}}]}, + section: section('rangeWithHour') +}; + +export const WithErrors = Template.bind({}); +WithErrors.args = { + readOnlyMode: false, + label: 'Select dates', + required: false, + name: 'S1.0.S1P1.answer', + warnings: {}, + metadata: { + dateType: 'rangeWithHour' + }, + initialValues: {S1: [{S1P1: {id: 1, answer: {start: '', end: ''}}}]}, + withErrors: true, + section: section('rangeWithHour') +}; diff --git a/src/components/DatePicker/DatePickerSelector.js b/src/components/DatePicker/DatePickerSelector.js new file mode 100644 index 0000000..715a81f --- /dev/null +++ b/src/components/DatePicker/DatePickerSelector.js @@ -0,0 +1,22 @@ +import PropTypes from 'prop-types'; +import {DatePicker as MuiDatePicker} from '@mui/x-date-pickers/DatePicker'; +import {DateTimePicker as MuiDateTimePicker} from '@mui/x-date-pickers/DateTimePicker'; + +import dateTypes from '@/constants/dateTypes'; + +function DateTimePickerSelector({type, ...props}) { + if ([dateTypes.DATE_WITH_HOUR, dateTypes.RANGE_WITH_HOUR].includes(type)) { + return ( + + ); + } + return ( + + ); +} + +DateTimePickerSelector.propTypes = { + type: PropTypes.oneOf(Object.values(dateTypes)).isRequired +}; + +export default DateTimePickerSelector; diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js new file mode 100644 index 0000000..949a924 --- /dev/null +++ b/src/components/DatePicker/index.js @@ -0,0 +1,3 @@ +import DatePicker from './DatePicker'; + +export default DatePicker; diff --git a/src/components/QuestionBuilder/QuestionBuilder.js b/src/components/QuestionBuilder/QuestionBuilder.js index 390081c..6aea1b1 100644 --- a/src/components/QuestionBuilder/QuestionBuilder.js +++ b/src/components/QuestionBuilder/QuestionBuilder.js @@ -4,6 +4,7 @@ import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; import Checkbox from '@/components/Checkbox'; +import DatePicker from '@/components/DatePicker'; import Radio from '@/components/Radio'; import RadioTable from '@/components/RadioTable'; import Select from '@/components/Select'; @@ -89,6 +90,20 @@ const getComponent = (section, sectionIndex, questionIndex, readOnlyMode, warnin /> ); break; + case questionTypes.DATE: + QuestionComponent = ( + + ); + break; default: QuestionComponent = Invalid component.; } diff --git a/src/components/Radio/Radio.stories.js b/src/components/Radio/Radio.stories.js index 9da351a..9e23f16 100644 --- a/src/components/Radio/Radio.stories.js +++ b/src/components/Radio/Radio.stories.js @@ -1,6 +1,6 @@ import React from 'react'; import {Formik, Field} from 'formik'; -import {Button} from '@mui/material'; +import Button from '@mui/material/Button'; import getWarnings from '@/utils/getWarnings'; import getSchemas from '@/utils/getSchemas'; diff --git a/src/components/TextField/TextField.js b/src/components/TextField/TextField.js index 80f70cd..717e3ea 100644 --- a/src/components/TextField/TextField.js +++ b/src/components/TextField/TextField.js @@ -17,7 +17,14 @@ function TextField({ }) { return ( - + {readOnlyMode ? ( {field.value || defaultMessages.UNANSWERED} ) : ( diff --git a/src/constants/dateTypes.js b/src/constants/dateTypes.js new file mode 100644 index 0000000..dec4877 --- /dev/null +++ b/src/constants/dateTypes.js @@ -0,0 +1,6 @@ +export default { + DATE_WITH_HOUR: 'dateWithHour', + DATE_WITHOUT_HOUR: 'dateWithoutHour', + RANGE_WITH_HOUR: 'rangeWithHour', + RANGE_WITHOUT_HOUR: 'rangeWithoutHour' +}; diff --git a/src/utils/buildQuestions.js b/src/utils/buildQuestions.js index 12cb460..48a633d 100644 --- a/src/utils/buildQuestions.js +++ b/src/utils/buildQuestions.js @@ -1,4 +1,5 @@ import questionTypes from '@/constants/questionTypes'; +import dateTypes from '@/constants/dateTypes'; const buildQuestions = section => { const values = {[section.name]: {id: 1}}; @@ -24,6 +25,14 @@ const buildQuestions = section => { values[section.name][question.name].answer = opts; return; } + if (question.type === questionTypes.DATE) { + if ([dateTypes.RANGE_WITHOUT_HOUR, dateTypes.RANGE_WITH_HOUR].includes(question.metadata.dateType)) { + values[section.name][question.name].answer = {start: '', end: ''}; + } else { + values[section.name][question.name].answer = ''; + } + return; + } values[section.name][question.name].answer = ''; }); values[section.name] = [values[section.name]]; diff --git a/src/utils/buildYupSchema.js b/src/utils/buildYupSchema.js index b9f5f95..cbb5669 100644 --- a/src/utils/buildYupSchema.js +++ b/src/utils/buildYupSchema.js @@ -1,8 +1,9 @@ import * as Yup from 'yup'; +import dateTypes from '@/constants/dateTypes'; import questionTypes from '@/constants/questionTypes'; -const getValidatorType = (type, options, {isRequired, message}) => { +const getValidatorType = (type, options, {isRequired, message, metadata}) => { let validator; switch (type) { case questionTypes.TEXT_FIELD: @@ -25,6 +26,15 @@ const getValidatorType = (type, options, {isRequired, message}) => { validator = Yup.object(opts); break; } + case questionTypes.DATE: { + const field = isRequired ? Yup.string().required(message) : Yup.string(); + if ([dateTypes.RANGE_WITHOUT_HOUR, dateTypes.RANGE_WITH_HOUR].includes(metadata.dateType)) { + validator = Yup.object({start: field, end: field}); + } else { + validator = Yup.string(); + } + break; + } default: return validator; } @@ -34,13 +44,17 @@ const getValidatorType = (type, options, {isRequired, message}) => { export default function buildYupSchema(schema, config, opts = {}) { const schemaWithValidations = schema; const { - name, type, validations, options + name, type, validations, options, metadata } = config; const requiredField = validations.find(validation => validation.type === 'required'); let validator = getValidatorType( type, options, - {isRequired: !!requiredField, message: requiredField?.params?.[0]?.message} + { + isRequired: !!requiredField, + message: requiredField?.params?.[0]?.message, + metadata + } ); if (!validator) { return schemaWithValidations; diff --git a/src/utils/propTypes/formikField.js b/src/utils/propTypes/formikField.js index bd6751f..f60c9b1 100644 --- a/src/utils/propTypes/formikField.js +++ b/src/utils/propTypes/formikField.js @@ -1,5 +1,8 @@ import PropTypes from 'prop-types'; export default PropTypes.shape({ - name: PropTypes.string.isRequired + name: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.shape({start: PropTypes.string, end: PropTypes.string}) + ]).isRequired });