Skip to content

Commit

Permalink
Add option providers into new react front end and add markdown
Browse files Browse the repository at this point in the history
functionality for option title and help (#441, #976)
  • Loading branch information
jochenklar committed Dec 5, 2024
1 parent 97148f9 commit 5e277b1
Show file tree
Hide file tree
Showing 20 changed files with 247 additions and 76 deletions.
3 changes: 3 additions & 0 deletions rdmo/projects/assets/js/interview/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const FETCH_PROGRESS_SUCCESS = 'FETCH_PROGRESS_SUCCESS'
export const FETCH_VALUES_SUCCESS = 'FETCH_VALUES_SUCCESS'
export const FETCH_VALUES_ERROR = 'FETCH_VALUES_ERROR'

export const FETCH_OPTIONS_SUCCESS = 'FETCH_OPTIONS_SUCCESS'
export const FETCH_OPTIONS_ERROR = 'FETCH_OPTIONS_ERROR'

export const CREATE_VALUE = 'CREATE_VALUE'

export const STORE_VALUE_SUCCESS = 'STORE_VALUE_SUCCESS'
Expand Down
33 changes: 32 additions & 1 deletion rdmo/projects/assets/js/interview/actions/interviewActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
FETCH_PAGE_SUCCESS,
FETCH_VALUES_SUCCESS,
FETCH_VALUES_ERROR,
FETCH_OPTIONS_SUCCESS,
FETCH_OPTIONS_ERROR,
CREATE_VALUE,
STORE_VALUE_SUCCESS,
STORE_VALUE_ERROR,
Expand All @@ -47,9 +49,15 @@ export function fetchPage(pageId) {
: PageApi.fetchPage(projectId, pageId)
return promise.then((page) => {
updateLocation(page.id)

initPage(page)

dispatch(fetchNavigation(page))
dispatch(fetchValues(page))

page.optionsets.filter((optionset) => optionset.has_provider)
.forEach((optionset) => dispatch(fetchOptions(optionset)))

dispatch(fetchPageSuccess(page, false))
})
}
Expand All @@ -69,7 +77,6 @@ export function fetchNavigation(page) {
return ProjectApi.fetchNavigation(projectId, page && page.section.id)
.then((navigation) => dispatch(fetchNavigationSuccess(navigation)))
.catch((errors) => dispatch(fetchNavigationError(errors)))

}
}

Expand All @@ -81,6 +88,30 @@ export function fetchNavigationError(errors) {
return {type: FETCH_NAVIGATION_ERROR, errors}
}

export function fetchOptions(optionset) {
return (dispatch) => {
return ProjectApi.fetchOptions(projectId, optionset.id)
.then((options) => dispatch(fetchOptionsSuccess(optionset, options)))
.catch((errors) => dispatch(fetchOptionsError(errors)))
}
}

export function fetchOptionsSuccess(optionset, options) {
return (dispatch, getStore) => {
const page = getStore().interview.page
page.optionsets.forEach((pageOptionset) => {
if (pageOptionset.id == optionset.id) {
optionset.options = options
}
})
return {type: FETCH_OPTIONS_SUCCESS, page}
}
}

export function fetchOptionsError(errors) {
return {type: FETCH_OPTIONS_ERROR, errors}
}

export function fetchValues(page) {
return (dispatch) => {
return ValueApi.fetchValues(projectId, { attribute: page.attributes })
Expand Down
4 changes: 3 additions & 1 deletion rdmo/projects/assets/js/interview/api/ProjectApi.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { isNil } from 'lodash'

import { encodeParams } from 'rdmo/core/assets/js/utils/api'

import BaseApi from 'rdmo/core/assets/js/api/BaseApi'

class ProjectsApi extends BaseApi {
Expand All @@ -21,7 +23,7 @@ class ProjectsApi extends BaseApi {
}

static fetchOptions(projectId, optionsetId) {
return this.get(`/api/v1/projects/projects/${projectId}/options/${optionsetId}`)
return this.get(`/api/v1/projects/projects/${projectId}/options/?${encodeParams({ optionset: optionsetId })}`)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,33 @@ import PropTypes from 'prop-types'
import classNames from 'classnames'
import { isNil } from 'lodash'

import OptionHelp from './common/OptionHelp'
import OptionText from './common/OptionText'

const AutocompleteInput = ({ value, options, disabled, isDefault, updateValue }) => {
const selectOptions = options.map(option => ({
value: option.id,
value: option,
label: option.text
}))

const [inputValue, setInputValue] = useState('')
useEffect(() => {
setInputValue(selectOptions.find((selectOption) => selectOption.value == value.option))
}, [value.id, value.option])
setInputValue(selectOptions.find((selectOption) => (
selectOption.value.has_provider ? (value.external_id === selectOption.value.id)
: (value.option === selectOption.value.id)
)))
}, [value.id, value.option, value.external_id])

const handleChange = (selectedOption) => {
updateValue(value, {
option: isNil(selectedOption) ? null : selectedOption.value
})
if (isNil(selectedOption)) {
updateValue(value, {})
} else {
if (selectedOption.value.has_provider) {
updateValue(value, { external_id: selectedOption.value.id, text: selectedOption.value.text })
} else {
updateValue(value, { option: selectedOption.value.id })
}
}
}

const classnames = classNames({
Expand All @@ -38,6 +50,12 @@ const AutocompleteInput = ({ value, options, disabled, isDefault, updateValue })
handleChange(option)
}}
isDisabled={disabled}
formatOptionLabel={({ value }) => (
<span>
<OptionText option={value} />
<OptionHelp className="ml-10" option={value} />
</span>
)}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'

import { isDefaultValue } from '../../../../utils/value'
import { gatherOptions } from '../../../../utils/options'

import QuestionAddValue from '../QuestionAddValue'
import QuestionDefault from '../QuestionDefault'
Expand Down Expand Up @@ -30,7 +31,7 @@ const AutocompleteWidget = ({ question, values, currentSet, disabled, createValu
</div>
<AutocompleteInput
value={value}
options={question.options}
options={gatherOptions(question)}
disabled={disabled}
isDefault={isDefault}
updateValue={updateValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { isEmpty, isNil } from 'lodash'

import AdditionalTextInput from './common/AdditionalTextInput'
import AdditionalTextareaInput from './common/AdditionalTextareaInput'
import OptionHelp from './common/OptionHelp'
import OptionText from './common/OptionText'

const CheckboxInput = ({ value, option, disabled, onCreate, onUpdate, onDelete }) => {

Expand All @@ -18,11 +20,15 @@ const CheckboxInput = ({ value, option, disabled, onCreate, onUpdate, onDelete }
}
}

const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => {
const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalInput) => {
if (checked) {
onUpdate(value, { text: additionalValue, option: option.id })
if (option.has_provider) {
onUpdate(value, { text: option.text, external_id: option.id })
} else {
onUpdate(value, { option: option.id })
}
} else {
onCreate(option, additionalValue)
onCreate(option, additionalInput)
}
}, 500)

Expand All @@ -35,31 +41,29 @@ const CheckboxInput = ({ value, option, disabled, onCreate, onUpdate, onDelete }
disabled={disabled}
onChange={() => handleChange()}
/>
<span>{option.text}</span>
<OptionText option={option} />
{
isEmpty(option.additional_input) && (
<span className="text-muted">{option.help}</span>
<OptionHelp className="ml-10" option={option} />
)
}
{
option.additional_input == 'text' && (
<>
<span>:</span>
{' '}
<AdditionalTextInput value={value} option={option} disabled={disabled} onChange={handleAdditionalValueChange} />
{' '}
<span className="text-muted">{option.help}</span>
<AdditionalTextInput className="ml-10" value={value} option={option} disabled={disabled} onChange={handleAdditionalValueChange} />
<OptionHelp className="ml-10" option={option} />
</>
)
}
{
option.additional_input == 'textarea' && (
<>
<span>:</span>
{' '}
<AdditionalTextareaInput value={value} option={option} disabled={disabled} onChange={handleAdditionalValueChange} />
{' '}
<div className="text-muted">{option.help}</div>
<div>
<OptionHelp option={option} />
</div>
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
import React from 'react'
import PropTypes from 'prop-types'
import { isNil, maxBy } from 'lodash'
import { maxBy } from 'lodash'

import { gatherOptions } from '../../../../utils/options'

import CheckboxInput from './CheckboxInput'

const CheckboxWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => {

const handleCreateValue = (option, text) => {
const handleCreateValue = (option, additionalInput) => {
const lastValue = maxBy(values, (v) => v.collection_index)
const collectionIndex = lastValue ? lastValue.collection_index + 1 : 0

createValue({
const value = {
attribute: question.attribute,
set_prefix: currentSet.set_prefix,
set_index: currentSet.set_index,
collection_index: collectionIndex,
option: option.id,
text: isNil(text) ? '' : text
}, true)
}

if (option.has_provider) {
value.external_id = option.id
value.text = option.text
} else {
value.option = option.id
value.text = additionalInput
}

createValue(value, true)
}

return (
<div className="interview-collection">
<div className="interview-input">
<div className="checkbox-control">
{
question.options.map((option, optionIndex) => (
gatherOptions(question).map((option, optionIndex) => (
<CheckboxInput
key={optionIndex}
value={values.find((value) => value.option == option.id)}
value={values.find((value) => (
option.has_provider ? (value.external_id === option.id) : (value.option === option.id)
))}
option={option}
disabled={disabled}
onCreate={handleCreateValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@ import { isEmpty } from 'lodash'

import AdditionalTextInput from './common/AdditionalTextInput'
import AdditionalTextareaInput from './common/AdditionalTextareaInput'
import OptionHelp from './common/OptionHelp'
import OptionText from './common/OptionText'

const RadioInput = ({ value, options, disabled, isDefault, updateValue }) => {
console.log(value.text)

const handleChange = (option) => {
if (isEmpty(option.additional_input)) {
updateValue(value, { option: option.id, text: '' })
if (option.has_provider) {
updateValue(value, { text: option.text, external_id: option.id })
} else {
updateValue(value, { option: option.id })
}
}

const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalValue) => {
const handleAdditionalValueChange = useDebouncedCallback((value, option, additionalInput) => {
updateValue(value, {
option: option.id,
text: additionalValue
text: additionalInput
})
}, 500)

Expand All @@ -40,35 +43,44 @@ const RadioInput = ({ value, options, disabled, isDefault, updateValue }) => {
<label>
<input
type="radio"
checked={value.option == option.id}
checked={option.has_provider ? (value.external_id === option.id) : (value.option === option.id)}
disabled={disabled}
onChange={() => handleChange(option)}
/>
<span>{option.text}</span>
<OptionText option={option} />
{
isEmpty(option.additional_input) && (
<span className="text-muted">{option.help}</span>
<OptionHelp className="ml-10" option={option} />
)
}
{
option.additional_input == 'text' && (
<>
<span>:</span>
{' '}
<AdditionalTextInput value={value} option={option} disabled={disabled} onChange={handleAdditionalValueChange} />
{' '}
<span className="text-muted">{option.help}</span>
<AdditionalTextInput
className="ml-10"
value={value}
option={option}
disabled={disabled}
onChange={handleAdditionalValueChange}
/>
<OptionHelp className="ml-10" option={option} />
</>
)
}
{
option.additional_input == 'textarea' && (
<>
<span>:</span>
{' '}
<AdditionalTextareaInput value={value} option={option} disabled={disabled} onChange={handleAdditionalValueChange} />
{' '}
<div className="text-muted">{option.help}</div>
<AdditionalTextareaInput
value={value}
option={option}
disabled={disabled}
onChange={handleAdditionalValueChange}
/>
<div>
<OptionHelp option={option} />
</div>
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'

import { isDefaultValue } from '../../../../utils/value'
import { gatherOptions } from '../../../../utils/options'

import QuestionAddValue from '../QuestionAddValue'
import QuestionDefault from '../QuestionDefault'
Expand Down Expand Up @@ -32,7 +33,7 @@ const RadioWidget = ({ question, values, currentSet, disabled, createValue, upda
</div>
<RadioInput
value={value}
options={question.options}
options={gatherOptions(question)}
disabled={disabled}
isDefault={isDefault}
updateValue={updateValue}
Expand Down
Loading

0 comments on commit 5e277b1

Please sign in to comment.