diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteInput.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteInput.js new file mode 100644 index 0000000000..e46db7622b --- /dev/null +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteInput.js @@ -0,0 +1,53 @@ +import React, { useState, useEffect } from 'react' +import ReactSelect from 'react-select' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import { isNil } from 'lodash' + +const AutocompleteInput = ({ value, options, disabled, isDefault, updateValue }) => { + const selectOptions = options.map(option => ({ + value: option.id, + label: option.text + })) + + const [inputValue, setInputValue] = useState('') + useEffect(() => { + setInputValue(selectOptions.find((selectOption) => selectOption.value == value.option)) + }, [value.id, value.option]) + + const handleChange = (selectedOption) => { + updateValue(value, { + option: isNil(selectedOption) ? null : selectedOption.value + }) + } + + const classnames = classNames({ + 'react-select': true, + 'default': isDefault + }) + + return ( + { + setInputValue(option) + handleChange(option) + }} + isDisabled={disabled} + /> + ) +} + +AutocompleteInput.propTypes = { + value: PropTypes.object.isRequired, + options: PropTypes.array.isRequired, + disabled: PropTypes.bool, + isDefault: PropTypes.bool, + updateValue: PropTypes.func.isRequired +} + +export default AutocompleteInput diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteWidget.js index d8726be2e6..026ab2eace 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/AutocompleteWidget.js @@ -1,72 +1,44 @@ -import React, { useState, useEffect } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import ReactSelect from 'react-select' -import { isNil } from 'lodash' + +import { isDefaultValue } from '../../../../utils/value' import QuestionAddValue from '../QuestionAddValue' import QuestionRemoveValue from '../QuestionRemoveValue' -const AutocompleteInput = ({ value, options, disabled, updateValue }) => { - const selectOptions = options.map(option => ({ - value: option.id, - label: option.text - })) - - const [inputValue, setInputValue] = useState('') - useEffect(() => { - setInputValue(selectOptions.find((selectOption) => selectOption.value == value.option)) - }, [value.id, value.option]) - - const handleChange = (selectedOption) => { - updateValue(value, { - option: isNil(selectedOption) ? null : selectedOption.value - }) - } +import DefaultBadge from './common/DefaultBadge' - return ( - { - setInputValue(option) - handleChange(option) - }} - isDisabled={disabled} - /> - ) -} - -AutocompleteInput.propTypes = { - value: PropTypes.object.isRequired, - options: PropTypes.array.isRequired, - disabled: PropTypes.bool, - updateValue: PropTypes.func.isRequired -} +import AutocompleteInput from './AutocompleteInput' const AutocompleteWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { return (
{ - values.map((value, valueIndex) => ( -
-
- { - (question.is_collection || values.length > 1) && ( - - ) - } + values.map((value, valueIndex) => { + const isDefault = isDefaultValue(question, value) + + return ( +
+
+ { + isDefault && + } + { + (question.is_collection || values.length > 1) && ( + + ) + } +
+
- -
- )) + ) + }) } { question.is_collection && ( diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxInput.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxInput.js new file mode 100644 index 0000000000..c829679442 --- /dev/null +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxInput.js @@ -0,0 +1,80 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { useDebouncedCallback } from 'use-debounce' +import { isEmpty, isNil } from 'lodash' + +import AdditionalTextInput from './common/AdditionalTextInput' +import AdditionalTextareaInput from './common/AdditionalTextareaInput' + +const CheckboxInput = ({ value, option, disabled, onCreate, onUpdate, onDelete }) => { + + const checked = !isNil(value) + + const handleChange = () => { + if (checked) { + onDelete(value) + } else { + onCreate(option) + } + } + + const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => { + if (checked) { + onUpdate(value, { text: additionalValue, option: option.id }) + } else { + onCreate(option, additionalValue) + } + }, 500) + + return ( +
+ +
+ ) +} + +CheckboxInput.propTypes = { + value: PropTypes.object, + option: PropTypes.object, + disabled: PropTypes.bool, + onCreate: PropTypes.func.isRequired, + onUpdate: PropTypes.func.isRequired, + onDelete: PropTypes.func.isRequired +} + +export default CheckboxInput diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxWidget.js index f32470ed4d..7e9ae0e1c5 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/CheckboxWidget.js @@ -1,81 +1,8 @@ import React from 'react' import PropTypes from 'prop-types' -import { useDebouncedCallback } from 'use-debounce' -import { isEmpty, isNil, maxBy } from 'lodash' +import { isNil, maxBy } from 'lodash' -import AdditionalTextInput from './common/AdditionalTextInput' -import AdditionalTextareaInput from './common/AdditionalTextareaInput' - -const CheckboxInput = ({ value, option, disabled, onCreate, onUpdate, onDelete }) => { - - const checked = !isNil(value) - - const handleChange = () => { - if (checked) { - onDelete(value) - } else { - onCreate(option) - } - } - - const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => { - if (checked) { - onUpdate(value, { text: additionalValue, option: option.id }) - } else { - onCreate(option, additionalValue) - } - }, 500) - - return ( -
- -
- ) -} - -CheckboxInput.propTypes = { - value: PropTypes.object, - option: PropTypes.object, - disabled: PropTypes.bool, - onCreate: PropTypes.func.isRequired, - onUpdate: PropTypes.func.isRequired, - onDelete: PropTypes.func.isRequired -} +import CheckboxInput from './CheckboxInput' const CheckboxWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/DateInput.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/DateInput.js new file mode 100644 index 0000000000..ce3c495c7b --- /dev/null +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/DateInput.js @@ -0,0 +1,71 @@ +import React from 'react' +import PropTypes from 'prop-types' +import DatePicker from 'react-datepicker' +import classNames from 'classnames' +import { enGB, de, it, es, fr } from 'date-fns/locale' + +import lang from 'rdmo/core/assets/js/utils/lang' + +const DateInput = ({ value, disabled, isDefault, updateValue }) => { + + const getLocale = () => { + switch (lang) { + case 'de': + return de + case 'it': + return it + case 'es': + return es + case 'fr': + return fr + default: + return enGB + } + } + + const getDateFormat = () => { + switch (lang) { + case 'de': + return 'dd.MM.yyyy' + case 'it': + return 'dd/MM/yyyy' + case 'es': + return 'dd/MM/yyyy' + case 'fr': + return 'dd/MM/yyyy' + default: + return 'dd/MM/yyyy' + } + } + + const handleChange = (date) => { + const text = date.toISOString().slice(0,10) + updateValue(value, { text }) + } + + const classnames = classNames({ + 'form-control': true, + 'date-control': true, + 'default': isDefault + }) + + return ( + handleChange(date)} + locale={getLocale()} + dateFormat={getDateFormat()} + disabled={disabled} + /> + ) +} + +DateInput.propTypes = { + value: PropTypes.object.isRequired, + disabled: PropTypes.bool, + isDefault: PropTypes.bool, + updateValue: PropTypes.func.isRequired +} + +export default DateInput diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/DateWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/DateWidget.js index e456e946d0..3d8b7b5608 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/DateWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/DateWidget.js @@ -1,88 +1,43 @@ import React from 'react' import PropTypes from 'prop-types' -import DatePicker from 'react-datepicker' -import { enGB, de, it, es, fr } from 'date-fns/locale' -import lang from 'rdmo/core/assets/js/utils/lang' +import { isDefaultValue } from '../../../../utils/value' import QuestionAddValue from '../QuestionAddValue' import QuestionRemoveValue from '../QuestionRemoveValue' -const DateInput = ({ value, disabled, updateValue }) => { +import DefaultBadge from './common/DefaultBadge' - const getLocale = () => { - switch (lang) { - case 'de': - return de - case 'it': - return it - case 'es': - return es - case 'fr': - return fr - default: - return enGB - } - } - - const getDateFormat = () => { - switch (lang) { - case 'de': - return 'dd.MM.yyyy' - case 'it': - return 'dd/MM/yyyy' - case 'es': - return 'dd/MM/yyyy' - case 'fr': - return 'dd/MM/yyyy' - default: - return 'dd/MM/yyyy' - } - } - - const handleChange = (date) => { - const text = date.toISOString().slice(0,10) - updateValue(value, { text }) - } - - return ( - handleChange(date)} - locale={getLocale()} - dateFormat={getDateFormat()} - disabled={disabled} - /> - ) -} - -DateInput.propTypes = { - value: PropTypes.object.isRequired, - disabled: PropTypes.bool, - updateValue: PropTypes.func.isRequired -} +import DateInput from './DateInput' const DateWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { return (
{ - values.map((value, valueIndex) => ( -
-
- { - (question.is_collection || values.length > 1) && ( - - ) - } + values.map((value, valueIndex) => { + const isDefault = isDefaultValue(question, value) + + return ( +
+
+ { + isDefault && + } + { + (question.is_collection || values.length > 1) && ( + + ) + } +
+
- -
- )) + ) + }) } { question.is_collection && ( diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/FileInput.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/FileInput.js new file mode 100644 index 0000000000..9495021ef3 --- /dev/null +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/FileInput.js @@ -0,0 +1,49 @@ +import React, { useCallback } from 'react' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import { useDropzone } from 'react-dropzone' + +const FileInput = ({ value, disabled, updateValue }) => { + const onDrop = useCallback(acceptedFiles => { + if (acceptedFiles.length == 1) { + updateValue(value, { file: acceptedFiles[0] }) + } + }, []) + const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, disabled }) + + const classnames = classNames({ + 'dropzone': true, + 'disabled': disabled + }) + + return ( +
+
+ +

+ { + isDragActive ? ( + {gettext('Drop the files here ...')} + ) : ( + {gettext('Drag \'n drop some files here, or click to select files.')} + ) + } +

+

+ {gettext('Current file: ')} + event.stopPropagation()}> + {value.file_name} + +

+
+
+ ) +} + +FileInput.propTypes = { + value: PropTypes.object.isRequired, + disabled: PropTypes.bool, + updateValue: PropTypes.func.isRequired +} + +export default FileInput diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/FileWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/FileWidget.js index eceef37f48..b76e51869a 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/FileWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/FileWidget.js @@ -1,74 +1,42 @@ -import React, { useCallback } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import classNames from 'classnames' -import { useDropzone } from 'react-dropzone' + +import { isDefaultValue } from '../../../../utils/value' import QuestionAddValue from '../QuestionAddValue' import QuestionRemoveValue from '../QuestionRemoveValue' -const FileInput = ({ value, disabled, updateValue }) => { - const onDrop = useCallback(acceptedFiles => { - if (acceptedFiles.length == 1) { - updateValue(value, { file: acceptedFiles[0] }) - } - }, []) - const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, disabled }) - - const classnames = classNames({ - 'dropzone': true, - 'disabled': disabled - }) +import DefaultBadge from './common/DefaultBadge' - return ( -
-
- -

- { - isDragActive ? ( - {gettext('Drop the files here ...')} - ) : ( - {gettext('Drag \'n drop some files here, or click to select files.')} - ) - } -

-

- {gettext('Current file: ')} - event.stopPropagation()}> - {value.file_name} - -

-
-
- ) -} - -FileInput.propTypes = { - value: PropTypes.object.isRequired, - disabled: PropTypes.bool, - updateValue: PropTypes.func.isRequired -} +import FileInput from './FileInput' const FileWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { return (
{ - values.map((value, valueIndex) => ( -
-
- { - (question.is_collection || values.length > 1) && ( - - ) - } + values.map((value, valueIndex) => { + const isDefault = isDefaultValue(question, value) + + return ( +
+
+ { + isDefault && + } + { + (question.is_collection || values.length > 1) && ( + + ) + } +
+
- -
- )) + ) + }) } { question.is_collection && ( diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioInput.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioInput.js new file mode 100644 index 0000000000..2fca85aa62 --- /dev/null +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioInput.js @@ -0,0 +1,92 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import { useDebouncedCallback } from 'use-debounce' +import { isEmpty } from 'lodash' + +import AdditionalTextInput from './common/AdditionalTextInput' +import AdditionalTextareaInput from './common/AdditionalTextareaInput' + +const RadioInput = ({ value, options, disabled, isDefault, updateValue }) => { + + const handleChange = (option) => { + if (isEmpty(option.additional_input)) { + updateValue(value, { option: option.id, text: '' }) + } else { + updateValue(value, { option: option.id }) + } + } + + const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => { + updateValue(value, { + option: option.id, + text: additionalValue + }) + }, 500) + + const classnames = classNames({ + 'radio-control': true, + 'default': isDefault + }) + + return ( +
+ { + isEmpty(options) ? ( +
{gettext('No options are available.')}
+ ) : ( + options.map((option, optionIndex) => ( +
+ +
+ )) + ) + } +
+ ) +} + +RadioInput.propTypes = { + value: PropTypes.object.isRequired, + options: PropTypes.array.isRequired, + disabled: PropTypes.bool, + isDefault: PropTypes.bool, + updateValue: PropTypes.func.isRequired +} + +export default RadioInput diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioWidget.js index 64c4152405..9926d0d1f8 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/RadioWidget.js @@ -1,111 +1,45 @@ import React from 'react' import PropTypes from 'prop-types' -import { useDebouncedCallback } from 'use-debounce' -import { isEmpty } from 'lodash' + +import { isDefaultValue } from '../../../../utils/value' import QuestionAddValue from '../QuestionAddValue' import QuestionRemoveValue from '../QuestionRemoveValue' -import AdditionalTextInput from './common/AdditionalTextInput' -import AdditionalTextareaInput from './common/AdditionalTextareaInput' - -const RadioInput = ({ value, options, disabled, updateValue }) => { +import DefaultBadge from './common/DefaultBadge' - const handleChange = (option) => { - if (isEmpty(option.additional_input)) { - updateValue(value, { option: option.id, text: '' }) - } else { - updateValue(value, { option: option.id }) - } - } - const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => { - updateValue(value, { - option: option.id, - text: additionalValue - }) - }, 500) +import RadioInput from './RadioInput' +const RadioWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { return ( -
+
{ - isEmpty(options) ? ( -
{gettext('No options are available.')}
- ) : ( - options.map((option, optionIndex) => ( -
-