From dcc024274d7ebf793cb4501361ed990d670e5a79 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Tue, 30 Apr 2024 15:37:59 +0200 Subject: [PATCH] Reorganize interview store, components and add read_only view --- .../js/interview/actions/interviewActions.js | 74 ++++++------------- .../js/interview/actions/projectActions.js | 38 ++++++++++ .../interview/components/main/Breadcrump.js | 10 +-- .../js/interview/components/main/page/Page.js | 5 +- .../components/main/question/Question.js | 4 +- .../main/question/QuestionAddValue.js | 5 +- .../main/question/QuestionDefault.js | 9 ++- .../main/question/QuestionEraseValue.js | 5 +- .../main/question/QuestionRemoveValue.js | 7 +- .../question/widgets/AutocompleteWidget.js | 28 +++---- .../main/question/widgets/DateWidget.js | 30 ++++---- .../main/question/widgets/FileWidget.js | 28 +++---- .../main/question/widgets/RadioWidget.js | 30 ++++---- .../main/question/widgets/RangeWidget.js | 35 ++++----- .../main/question/widgets/SelectWidget.js | 28 +++---- .../main/question/widgets/TextWidget.js | 28 +++---- .../main/question/widgets/TextareaWidget.js | 28 +++---- .../main/question/widgets/YesNoWidget.js | 31 ++++---- .../main/questionset/QuestionSet.js | 6 +- .../interview/components/sidebar/Overview.js | 35 +++++---- .../assets/js/interview/containers/Main.js | 17 +++-- .../assets/js/interview/containers/Sidebar.js | 14 ++-- .../js/interview/reducers/interviewReducer.js | 23 ++---- .../js/interview/reducers/projectReducer.js | 26 +++++++ .../js/interview/store/configureStore.js | 9 ++- .../assets/js/interview/utils/interview.js | 8 +- .../assets/js/interview/utils/page.js | 20 +++-- .../assets/js/interview/utils/value.js | 4 +- rdmo/projects/assets/scss/interview.scss | 32 ++++---- .../projects/project_detail_sidebar.html | 4 +- 30 files changed, 351 insertions(+), 270 deletions(-) create mode 100644 rdmo/projects/assets/js/interview/actions/projectActions.js create mode 100644 rdmo/projects/assets/js/interview/reducers/projectReducer.js diff --git a/rdmo/projects/assets/js/interview/actions/interviewActions.js b/rdmo/projects/assets/js/interview/actions/interviewActions.js index cb3c3851c9..bc93cfe3ad 100644 --- a/rdmo/projects/assets/js/interview/actions/interviewActions.js +++ b/rdmo/projects/assets/js/interview/actions/interviewActions.js @@ -18,12 +18,8 @@ import { NOOP, FETCH_NAVIGATION_ERROR, FETCH_NAVIGATION_SUCCESS, - FETCH_OVERVIEW_ERROR, - FETCH_OVERVIEW_SUCCESS, FETCH_PAGE_ERROR, FETCH_PAGE_SUCCESS, - FETCH_PROGRESS_ERROR, - FETCH_PROGRESS_SUCCESS, FETCH_VALUES_SUCCESS, FETCH_VALUES_ERROR, CREATE_VALUE, @@ -38,73 +34,47 @@ import { import { updateConfig } from 'rdmo/core/assets/js/actions/configActions' -export function fetchOverview() { - return (dispatch) => ProjectApi.fetchOverview(projectId) - .then((overview) => dispatch(fetchOverviewSuccess(overview))) - .catch((errors) => dispatch(fetchOverviewError(errors))) -} - -export function fetchOverviewSuccess(overview) { - return {type: FETCH_OVERVIEW_SUCCESS, overview} -} - -export function fetchOverviewError(errors) { - return {type: FETCH_OVERVIEW_ERROR, errors} -} - -export function fetchProgress() { - return (dispatch) => ProjectApi.fetchProgress(projectId) - .then((progress) => dispatch(fetchProgressSuccess(progress))) - .catch((errors) => dispatch(fetchProgressError(errors))) -} - -export function fetchProgressSuccess(progress) { - return {type: FETCH_PROGRESS_SUCCESS, progress} -} - -export function fetchProgressError(errors) { - return {type: FETCH_PROGRESS_ERROR, errors} -} - -export function fetchNavigation(sectionId) { - return (dispatch) => ProjectApi.fetchNavigation(projectId, sectionId) - .then((navigation) => dispatch(fetchNavigationSuccess(navigation))) - .catch((errors) => dispatch(fetchNavigationError(errors))) -} - -export function fetchNavigationSuccess(navigation) { - return {type: FETCH_NAVIGATION_SUCCESS, navigation} -} - -export function fetchNavigationError(errors) { - return {type: FETCH_NAVIGATION_ERROR, errors} -} - export function fetchPage(pageId) { return (dispatch) => { const promise = isNil(pageId) ? PageApi.fetchContinue(projectId) : PageApi.fetchPage(projectId, pageId) return promise.then((page) => { updateLocation(page.id) - dispatch(fetchNavigation(page.section.id)) + initPage(page) + dispatch(fetchNavigation(page)) + dispatch(fetchValues(page)) dispatch(fetchPageSuccess(page)) - dispatch(fetchValues()) }) } } export function fetchPageSuccess(page) { - return {type: FETCH_PAGE_SUCCESS, page: initPage(page)} + return {type: FETCH_PAGE_SUCCESS, page} } export function fetchPageError(errors) { return {type: FETCH_PAGE_ERROR, errors} } -export function fetchValues() { - return (dispatch, getStore) => { - const page = getStore().interview.page +export function fetchNavigation(page) { + return (dispatch) => { + return ProjectApi.fetchNavigation(projectId, page.section.id) + .then((navigation) => dispatch(fetchNavigationSuccess(navigation))) + .catch((errors) => dispatch(fetchNavigationError(errors))) + + } +} +export function fetchNavigationSuccess(navigation) { + return {type: FETCH_NAVIGATION_SUCCESS, navigation} +} + +export function fetchNavigationError(errors) { + return {type: FETCH_NAVIGATION_ERROR, errors} +} + +export function fetchValues(page) { + return (dispatch) => { return ValueApi.fetchValues(projectId, { attribute: page.attributes }) .then((values) => dispatch(fetchValuesSuccess(values, page))) .catch((errors) => dispatch(fetchValuesError(errors))) diff --git a/rdmo/projects/assets/js/interview/actions/projectActions.js b/rdmo/projects/assets/js/interview/actions/projectActions.js new file mode 100644 index 0000000000..bc011549cd --- /dev/null +++ b/rdmo/projects/assets/js/interview/actions/projectActions.js @@ -0,0 +1,38 @@ +import ProjectApi from '../api/ProjectApi' + +import projectId from '../utils/projectId' + +import { + FETCH_OVERVIEW_ERROR, + FETCH_OVERVIEW_SUCCESS, + FETCH_PROGRESS_ERROR, + FETCH_PROGRESS_SUCCESS, +} from './actionTypes' + +export function fetchOverview() { + return (dispatch) => ProjectApi.fetchOverview(projectId) + .then((overview) => dispatch(fetchOverviewSuccess(overview))) + .catch((errors) => dispatch(fetchOverviewError(errors))) +} + +export function fetchOverviewSuccess(overview) { + return {type: FETCH_OVERVIEW_SUCCESS, overview} +} + +export function fetchOverviewError(errors) { + return {type: FETCH_OVERVIEW_ERROR, errors} +} + +export function fetchProgress() { + return (dispatch) => ProjectApi.fetchProgress(projectId) + .then((progress) => dispatch(fetchProgressSuccess(progress))) + .catch((errors) => dispatch(fetchProgressError(errors))) +} + +export function fetchProgressSuccess(progress) { + return {type: FETCH_PROGRESS_SUCCESS, progress} +} + +export function fetchProgressError(errors) { + return {type: FETCH_PROGRESS_ERROR, errors} +} diff --git a/rdmo/projects/assets/js/interview/components/main/Breadcrump.js b/rdmo/projects/assets/js/interview/components/main/Breadcrump.js index 2db7a2cd17..2ba76ab429 100644 --- a/rdmo/projects/assets/js/interview/components/main/Breadcrump.js +++ b/rdmo/projects/assets/js/interview/components/main/Breadcrump.js @@ -3,11 +3,11 @@ import PropTypes from 'prop-types' import baseUrl from 'rdmo/core/assets/js/utils/baseUrl' -const Breadcrump = ({ overview, currentPage, fetchPage }) => { +const Breadcrump = ({ overview, page, fetchPage }) => { const handleClick = (event) => { event.preventDefault() - fetchPage(currentPage.section.first) + fetchPage(page.section.first) } return ( @@ -23,8 +23,8 @@ const Breadcrump = ({ overview, currentPage, fetchPage }) => {
  • - - {currentPage.section.title} + + {page.section.title}
  • @@ -33,7 +33,7 @@ const Breadcrump = ({ overview, currentPage, fetchPage }) => { Breadcrump.propTypes = { overview: PropTypes.object.isRequired, - currentPage: PropTypes.object.isRequired, + page: PropTypes.object.isRequired, fetchPage: PropTypes.func.isRequired } diff --git a/rdmo/projects/assets/js/interview/components/main/page/Page.js b/rdmo/projects/assets/js/interview/components/main/page/Page.js index 2cd32b2be3..75c2f04fa3 100644 --- a/rdmo/projects/assets/js/interview/components/main/page/Page.js +++ b/rdmo/projects/assets/js/interview/components/main/page/Page.js @@ -10,7 +10,7 @@ import PageButtons from './PageButtons' import PageHead from './PageHead' import PageHelp from './PageHelp' -const Page = ({ config, templates, page, sets, values, fetchPage, +const Page = ({ config, templates, project, page, sets, values, fetchPage, createValue, updateValue, deleteValue, activateSet, createSet, updateSet, deleteSet }) => { @@ -50,6 +50,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage, questionset={element} sets={sets} values={values.filter((value) => element.attributes.includes(value.attribute))} + disabled={project.overview.read_only} focus={elementIndex == 0} parentSet={currentSet} createSet={createSet} @@ -71,6 +72,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage, value.set_prefix == currentSetPrefix && value.set_index == currentSetIndex ))} + disabled={project.overview.read_only} focus={elementIndex == 0} currentSet={currentSet} createValue={createValue} @@ -92,6 +94,7 @@ const Page = ({ config, templates, page, sets, values, fetchPage, Page.propTypes = { config: PropTypes.object.isRequired, templates: PropTypes.object.isRequired, + project: PropTypes.object.isRequired, page: PropTypes.object.isRequired, sets: PropTypes.array.isRequired, values: PropTypes.array.isRequired, diff --git a/rdmo/projects/assets/js/interview/components/main/question/Question.js b/rdmo/projects/assets/js/interview/components/main/question/Question.js index dc3572a431..ae8c94a6b2 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/Question.js +++ b/rdmo/projects/assets/js/interview/components/main/question/Question.js @@ -9,7 +9,7 @@ import QuestionText from './QuestionText' import QuestionWidget from './QuestionWidget' import QuestionOptional from './QuestionOptional' -const Question = ({ templates, question, values, focus, currentSet, createValue, updateValue, deleteValue }) => { +const Question = ({ templates, question, values, disabled, focus, currentSet, createValue, updateValue, deleteValue }) => { return (
    { @@ -33,6 +33,7 @@ const Question = ({ templates, question, values, focus, currentSet, createValue, { +const AddValue = ({ question, values, currentSet, disabled, createValue }) => { const handleClick = () => { const lastValue = maxBy(values, (v) => v.collection_index) const collectionIndex = lastValue ? lastValue.collection_index + 1 : 0 @@ -15,7 +15,7 @@ const AddValue = ({ question, values, currentSet, createValue }) => { }) } - return ( + return !disabled && question.is_collection && ( @@ -26,6 +26,7 @@ AddValue.propTypes = { question: PropTypes.object.isRequired, values: PropTypes.array.isRequired, currentSet: PropTypes.object.isRequired, + disabled: PropTypes.bool.isRequired, createValue: PropTypes.func.isRequired } diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js index 8d70ac94aa..30632f2e28 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js +++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionDefault.js @@ -1,11 +1,16 @@ import React from 'react' +import PropTypes from 'prop-types' -const QuestionDefault = () => { - return ( +const QuestionDefault = ({ isDefault }) => { + return isDefault && (
    {gettext('Default')}
    ) } +QuestionDefault.propTypes = { + isDefault: PropTypes.bool.isRequired +} + export default QuestionDefault diff --git a/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js b/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js index 7648af5bc3..720e30d8ec 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js +++ b/rdmo/projects/assets/js/interview/components/main/question/QuestionEraseValue.js @@ -1,12 +1,12 @@ import React from 'react' import PropTypes from 'prop-types' -const QuestionEraseValue = ({ value, updateValue }) => { +const QuestionEraseValue = ({ value, disabled, updateValue }) => { const handleEraseValue = () => { updateValue(value, {}) } - return ( + return !disabled && ( @@ -10,7 +10,10 @@ const QuestionRemoveValue = ({ value, deleteValue }) => { } QuestionRemoveValue.propTypes = { + question: PropTypes.object.isRequired, + values: PropTypes.array.isRequired, value: PropTypes.object.isRequired, + disabled: PropTypes.bool.isRequired, deleteValue: PropTypes.func.isRequired } 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 b914dde681..bfcd6929c3 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 @@ -19,14 +19,14 @@ const AutocompleteWidget = ({ question, values, currentSet, disabled, createValu return (
    - { - isDefault && - } - { - (question.is_collection || values.length > 1) && ( - - ) - } + +
    - ) - } +
    ) } 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 86564c78f0..34ec1ae048 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 @@ -20,15 +20,15 @@ const DateWidget = ({ question, values, currentSet, disabled, createValue, updat return (
    - { - isDefault && - } - - { - (question.is_collection || values.length > 1) && ( - - ) - } + + +
    - ) - } +
    ) } 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 61f18bf36e..ef39e33b9e 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 @@ -19,14 +19,14 @@ const FileWidget = ({ question, values, currentSet, disabled, createValue, updat return (
    - { - isDefault && - } - { - (question.is_collection || values.length > 1) && ( - - ) - } + +
    - ) - } +
    ) } 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 2955fc9091..a74178fe8e 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 @@ -20,15 +20,15 @@ const RadioWidget = ({ question, values, currentSet, disabled, createValue, upda return (
    - { - isDefault && - } - - { - (question.is_collection || values.length > 1) && ( - - ) - } + + +
    - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/RangeWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/RangeWidget.js index 8137389308..2d6f7b4159 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/RangeWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/RangeWidget.js @@ -1,8 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' -import { isNil } from 'lodash' -import { isDefaultValue } from '../../../../utils/value' +import { isDefaultValue, initRange } from '../../../../utils/value' import QuestionAddValue from '../QuestionAddValue' import QuestionDefault from '../QuestionDefault' @@ -14,7 +13,7 @@ import RangeInput from './RangeInput' const RangeWidget = ({ question, values, currentSet, disabled, createValue, updateValue, deleteValue }) => { const handleCreateValue = (value) => { - value.text = isNil(question.minimum) ? 0 : question.minimum + initRange(question, value) createValue(value) } @@ -27,15 +26,15 @@ const RangeWidget = ({ question, values, currentSet, disabled, createValue, upda return (
    - { - isDefault && - } - - { - (question.is_collection || values.length > 1) && ( - - ) - } + + +
    - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/SelectWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/SelectWidget.js index 81731076d7..64132939f0 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/SelectWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/SelectWidget.js @@ -19,14 +19,14 @@ const SelectWidget = ({ question, values, currentSet, disabled, createValue, upd return (
    - { - isDefault && - } - { - (question.is_collection || values.length > 1) && ( - - ) - } + +
    - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/TextWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/TextWidget.js index 1fc4d09c6c..1b624b08df 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/TextWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/TextWidget.js @@ -19,14 +19,14 @@ const TextWidget = ({ question, values, currentSet, disabled, focus, createValue return (
    - { - isDefault && - } - { - (question.is_collection || values.length > 1) && ( - - ) - } + +
    - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/TextareaWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/TextareaWidget.js index 244ade55f1..5fb74f291d 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/TextareaWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/TextareaWidget.js @@ -19,14 +19,14 @@ const TextareaWidget = ({ question, values, currentSet, disabled, focus, createV return (
    - { - isDefault && - } - { - (question.is_collection || values.length > 1) && ( - - ) - } + +
    - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/question/widgets/YesNoWidget.js b/rdmo/projects/assets/js/interview/components/main/question/widgets/YesNoWidget.js index 4234ddef2b..c45ec2c557 100644 --- a/rdmo/projects/assets/js/interview/components/main/question/widgets/YesNoWidget.js +++ b/rdmo/projects/assets/js/interview/components/main/question/widgets/YesNoWidget.js @@ -20,15 +20,15 @@ const YesNoWidget = ({ question, values, currentSet, disabled, createValue, upda return (
    - { - isDefault && - } - - { - (question.is_collection || values.length > 1) && ( - - ) - } + + +
    - ) }) } - { - question.is_collection && ( - - ) - } +
    ) } diff --git a/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js b/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js index c31536368a..df94fa0fc8 100644 --- a/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js +++ b/rdmo/projects/assets/js/interview/components/main/questionset/QuestionSet.js @@ -11,7 +11,8 @@ import QuestionSetHelp from './QuestionSetHelp' import QuestionSetAddSet from './QuestionSetAddSet' import QuestionSetRemoveSet from './QuestionSetRemoveSet' -const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, createSet, updateSet, deleteSet, +const QuestionSet = ({ templates, questionset, sets, values, disabled, focus, + parentSet, createSet, updateSet, deleteSet, createValue, updateValue, deleteValue }) => { const setPrefix = getChildPrefix(parentSet) @@ -52,6 +53,7 @@ const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, c questionset={element} sets={sets} values={values.filter((value) => element.attributes.includes(value.attribute))} + disabled={disabled} focus={focus && (setIndex === 0 && elementIndex === 0)} parentSet={set} createSet={createSet} @@ -73,6 +75,7 @@ const QuestionSet = ({ templates, questionset, sets, values, focus, parentSet, c value.set_prefix == set.set_prefix && value.set_index == set.set_index ))} + disabled={disabled} focus={focus && (setIndex === 0 && elementIndex === 0)} currentSet={set} createValue={createValue} @@ -103,6 +106,7 @@ QuestionSet.propTypes = { questionset: PropTypes.object.isRequired, sets: PropTypes.array.isRequired, values: PropTypes.array.isRequired, + disabled: PropTypes.bool.isRequired, focus: PropTypes.bool.isRequired, parentSet: PropTypes.object.isRequired, createSet: PropTypes.func.isRequired, diff --git a/rdmo/projects/assets/js/interview/components/sidebar/Overview.js b/rdmo/projects/assets/js/interview/components/sidebar/Overview.js index 57eb814812..1b3211238c 100644 --- a/rdmo/projects/assets/js/interview/components/sidebar/Overview.js +++ b/rdmo/projects/assets/js/interview/components/sidebar/Overview.js @@ -17,22 +17,31 @@ const Overview = ({ overview, help }) => {
    + { + overview.read_only && ( +

    + + {gettext('read only')} + +

    + ) + } +
    diff --git a/rdmo/projects/assets/js/interview/containers/Main.js b/rdmo/projects/assets/js/interview/containers/Main.js index 6f4f885b07..da38aefff5 100644 --- a/rdmo/projects/assets/js/interview/containers/Main.js +++ b/rdmo/projects/assets/js/interview/containers/Main.js @@ -3,28 +3,29 @@ import PropTypes from 'prop-types' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' +import { isReady } from '../utils/interview' + import Breadcrump from '../components/main/Breadcrump' import Page from '../components/main/page/Page' -import { showInterview } from '../utils/interview' - import * as configActions from 'rdmo/core/assets/js/actions/configActions' import * as interviewActions from '../actions/interviewActions' // eslint-disable-next-line no-unused-vars -const Main = ({ config, settings, templates, user, interview, configActions, interviewActions }) => { - if (showInterview(interview)) { +const Main = ({ config, settings, templates, user, project, interview, configActions, interviewActions }) => { + if (isReady(interview)) { return (
    { - if (showInterview(interview)) { +const Sidebar = ({ config, settings, templates, user, project, interview, configActions, interviewActions }) => { + if (isReady(interview)) { return (
    !action.values.includes(value)), sets: state.sets.filter((set) => !action.sets.includes(set)) } - case FETCH_OVERVIEW_ERROR: - case FETCH_PROGRESS_ERROR: case FETCH_NAVIGATION_ERROR: case FETCH_PAGE_ERROR: case FETCH_VALUES_ERROR: diff --git a/rdmo/projects/assets/js/interview/reducers/projectReducer.js b/rdmo/projects/assets/js/interview/reducers/projectReducer.js new file mode 100644 index 0000000000..dfd7f90636 --- /dev/null +++ b/rdmo/projects/assets/js/interview/reducers/projectReducer.js @@ -0,0 +1,26 @@ +import { + FETCH_OVERVIEW_ERROR, + FETCH_OVERVIEW_SUCCESS, + FETCH_PROGRESS_ERROR, + FETCH_PROGRESS_SUCCESS, + +} from '../actions/actionTypes' + +const initialState = { + overview: null, + progress: null +} + +export default function interviewReducer(state = initialState, action) { + switch(action.type) { + case FETCH_OVERVIEW_SUCCESS: + return { ...state, overview: action.overview } + case FETCH_PROGRESS_SUCCESS: + return { ...state, progress: action.progress } + case FETCH_OVERVIEW_ERROR: + case FETCH_PROGRESS_ERROR: + return { errors: action.errors } + default: + return state + } +} diff --git a/rdmo/projects/assets/js/interview/store/configureStore.js b/rdmo/projects/assets/js/interview/store/configureStore.js index 799bb35c3e..6646da1552 100644 --- a/rdmo/projects/assets/js/interview/store/configureStore.js +++ b/rdmo/projects/assets/js/interview/store/configureStore.js @@ -10,6 +10,7 @@ import templateReducer from 'rdmo/core/assets/js/reducers/templateReducer' import userReducer from 'rdmo/core/assets/js/reducers/userReducer' import interviewReducer from '../reducers/interviewReducer' +import projectReducer from '../reducers/projectReducer' import * as configActions from 'rdmo/core/assets/js/actions/configActions' import * as settingsActions from 'rdmo/core/assets/js/actions/settingsActions' @@ -17,6 +18,7 @@ import * as templateActions from 'rdmo/core/assets/js/actions/templateActions' import * as userActions from 'rdmo/core/assets/js/actions/userActions' import * as interviewActions from '../actions/interviewActions' +import * as projectActions from '../actions/projectActions' import { parseLocation } from '../utils/location' @@ -34,9 +36,10 @@ export default function configureStore() { const rootReducer = combineReducers({ config: configReducer, interview: interviewReducer, + project: projectReducer, settings: settingsReducer, templates: templateReducer, - user: userReducer + user: userReducer, }) const store = createStore( @@ -59,8 +62,8 @@ export default function configureStore() { store.dispatch(settingsActions.fetchSettings()), store.dispatch(templateActions.fetchTemplates()), store.dispatch(userActions.fetchCurrentUser()), - store.dispatch(interviewActions.fetchOverview()), - store.dispatch(interviewActions.fetchProgress()) + store.dispatch(projectActions.fetchOverview()), + store.dispatch(projectActions.fetchProgress()) ]).then(() => fetchPageFromLocation()) }) diff --git a/rdmo/projects/assets/js/interview/utils/interview.js b/rdmo/projects/assets/js/interview/utils/interview.js index 945ba9cb15..2396067bc5 100644 --- a/rdmo/projects/assets/js/interview/utils/interview.js +++ b/rdmo/projects/assets/js/interview/utils/interview.js @@ -1,7 +1,7 @@ -import isUndefined from 'lodash/isUndefined' +import { isNil } from 'lodash' -const showInterview = (interview) => { - return !isUndefined(interview.page) && !isUndefined(interview.navigation) && !isUndefined(interview.values) +const isReady = (interview) => { + return !(isNil(interview.page) || isNil(interview.navigation) || isNil(interview.values)) } -export { showInterview } +export { isReady } diff --git a/rdmo/projects/assets/js/interview/utils/page.js b/rdmo/projects/assets/js/interview/utils/page.js index 0dd3c93481..48dfb67af5 100644 --- a/rdmo/projects/assets/js/interview/utils/page.js +++ b/rdmo/projects/assets/js/interview/utils/page.js @@ -1,26 +1,26 @@ import { isNil } from 'lodash' const initQuestionSet = (questionset) => { - questionset.elements = questionset.elements.map((element) => { + questionset.elements.forEach((element) => { if (element.model == 'questions.questionset') { - return initQuestionSet(element) + initQuestionSet(element) } else { - return initQuestion(element) + initQuestion(element) } }) - questionset.attributes = questionset.elements.reduce((agg, cur) => { - if (cur.model == 'questions.questionset') { - return agg.concat(cur.attributes) + // aggregate attributes from decendant questionsets and questions + questionset.attributes = questionset.elements.reduce((attributes, element) => { + if (element.model == 'questions.questionset') { + return attributes.concat(element.attributes) } else { - return [...agg, cur.attribute] + return [...attributes, element.attribute] } }, [questionset.attribute]).filter((a) => !isNil(a)) - - return questionset } const initQuestion = (question) => { + // aggregate options from optionsets question.options = question.optionsets.reduce((acc, cur) => { acc = acc.concat(cur.options.map((option) => { option.optionset = cur.id @@ -29,8 +29,6 @@ const initQuestion = (question) => { return acc }, []) - - return question } const initPage = (page) => initQuestionSet(page) diff --git a/rdmo/projects/assets/js/interview/utils/value.js b/rdmo/projects/assets/js/interview/utils/value.js index 06cf2e9730..1cb5055aab 100644 --- a/rdmo/projects/assets/js/interview/utils/value.js +++ b/rdmo/projects/assets/js/interview/utils/value.js @@ -13,9 +13,9 @@ const isDefaultValue = (question, value) => { } else if (question.default_external_id) { return question.default_external_id == value.external_id } - } else { - return false } + + return false } const initValues = (sets, values, element, setPrefix) => { diff --git a/rdmo/projects/assets/scss/interview.scss b/rdmo/projects/assets/scss/interview.scss index ecd9b5ce1b..c5a9ba01d5 100644 --- a/rdmo/projects/assets/scss/interview.scss +++ b/rdmo/projects/assets/scss/interview.scss @@ -214,14 +214,6 @@ .btn-remove-value:focus { outline: 0; } - - .badge-default { - cursor: help; - color: #999; - border: 1px solid #999; - background-color: white; - margin: 7px 0 7px 0; - } } .default { @@ -233,11 +225,6 @@ opacity: 0.5; } } - - .badge-optional { - float: right; - margin-top: 1px; - } } .interview-question { @@ -318,3 +305,22 @@ .btn-add-set { margin-bottom: 20px; } + +.badge-default { + cursor: help; + color: #999; + border: 1px solid #999; + background-color: white; + margin: 7px 0 7px 0; +} + +.badge-optional { + cursor: help; + float: right; + margin-top: 1px; +} + +.badge-read-only { + cursor: help; + background-color: black; +} diff --git a/rdmo/projects/templates/projects/project_detail_sidebar.html b/rdmo/projects/templates/projects/project_detail_sidebar.html index b3be4c74bd..ac8dedf720 100644 --- a/rdmo/projects/templates/projects/project_detail_sidebar.html +++ b/rdmo/projects/templates/projects/project_detail_sidebar.html @@ -20,13 +20,11 @@

    {% trans 'Options' %}

    {% endif %} - {% if can_change_value %}
  • - {% trans 'Answer questions (new)' %} + {% trans 'Interview (new)' %}
  • - {% endif %}