Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow arbitrary response for suggester #900

Open
wants to merge 6 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/constants/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,10 @@ const dictionary: Dictionary = {
fr: 'Retrouver dans le questionnaire',
en: 'Retrieve in the questionnaire',
},
allowArbitraryResponse: {
fr: 'Autoriser une réponse libre',
en: 'Allow arbitrary response',
QRuhier marked this conversation as resolved.
Show resolved Hide resolved
},
list: {
fr: 'Liste',
en: 'List',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function formToState(form) {
y,
z,
mesureLevel,
arbitraryOfVariable,
codeListReference,
codeListReferenceLabel,
isCollected,
Expand All @@ -61,6 +62,7 @@ export function formToState(form) {
x,
y,
z,
arbitraryOfVariable,
isCollected,
alternativeLabel,
mesureLevel,
Expand Down Expand Up @@ -94,6 +96,7 @@ export function storeToForm(currentStore) {
x,
y,
z,
arbitraryOfVariable,
isCollected = '1',
alternativeLabel,
mesureLevel,
Expand All @@ -107,6 +110,7 @@ export function storeToForm(currentStore) {
x,
y,
z,
arbitraryOfVariable,
isCollected,
alternativeLabel,
mesureLevel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
const { RADIO } = DATATYPE_VIS_HINT;

export const defaultState = {
allowArbitrary: false,
QRuhier marked this conversation as resolved.
Show resolved Hide resolved
mandatory: false,
visHint: RADIO,
// [DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultState),
};

export const defaultForm = {
allowArbitrary: false,
mandatory: false,
visHint: RADIO,
// [DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultForm),
Expand All @@ -24,13 +26,15 @@ export const defaultForm = {
export function formToState(form, transformers) {
const {
id,
allowArbitrary,
mandatory,
visHint,
[DEFAULT_CODES_LIST_SELECTOR_PATH]: codesListForm,
} = form;

return {
id,
allowArbitrary,
mandatory,
visHint,
[DEFAULT_CODES_LIST_SELECTOR_PATH]:
Expand All @@ -39,10 +43,11 @@ export function formToState(form, transformers) {
}

export function stateToForm(currentState, transformers) {
const { id, visHint, mandatory } = currentState;
const { id, allowArbitrary, visHint, mandatory } = currentState;

return {
id,
allowArbitrary,
mandatory,
visHint,
[DEFAULT_CODES_LIST_SELECTOR_PATH]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const defaultMeasureForm = {
type: SIMPLE,
[SIMPLE]: defaultMeasureSimpleState,
[SINGLE_CHOICE]: {
allowArbitrary: false,
[DEFAULT_CODES_LIST_SELECTOR_PATH]: cloneDeep(CodesListDefaultForm),
visHint: RADIO,
},
Expand Down
7 changes: 7 additions & 0 deletions src/model/remote-to-stores.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export function questionnaireRemoteToStores(remote, currentStores = {}) {
remote.Child,
collectedVariables,
);

const arbitraryVariables = Component.getArbitraryResponsesFromRemote(
remote.Child,
collectedVariables,
);

const codesListsStore = CodesList.remoteToStore(
codesLists,
variableclarification,
Expand All @@ -56,6 +62,7 @@ export function questionnaireRemoteToStores(remote, currentStores = {}) {
responsesByVariable,
codesListsStore,
variableclarification,
arbitraryVariables,
),
};
// Components store
Expand Down
21 changes: 20 additions & 1 deletion src/model/transformations/collected-variable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function remoteToStore(
responsesByVariable,
codesListsStore,
variableclarification,
arbitraryVariables,
) {
remote.forEach((variable) => {
if (variableclarification) {
Expand All @@ -45,9 +46,26 @@ export function remoteToStore(
}
}
}
if (arbitraryVariables) {
const extendedArbitraryVariable = arbitraryVariables.find(
(arbitraryVariable) =>
arbitraryVariable.CollectedVariableReference === variable.id,
);
if (extendedArbitraryVariable) {
variable.arbitraryOfVariable =
extendedArbitraryVariable.arbitraryOfVariable;
}
}
});
return remote.reduce((acc, ev) => {
const { Name: name, Label: label, CodeListReference, z, mesureLevel } = ev;
const {
Name: name,
Label: label,
CodeListReference,
z,
mesureLevel,
arbitraryOfVariable,
} = ev;
const id = ev.id || uuid();

const formatSingleRemote = remoteToStateFormatSimple({
Expand All @@ -69,6 +87,7 @@ export function remoteToStore(
...responsesByVariable[id],
z,
mesureLevel,
arbitraryOfVariable,
},
};
}, {});
Expand Down
80 changes: 80 additions & 0 deletions src/model/transformations/collected-variable.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,86 @@ describe('collected variable tranformations', () => {
output,
);
});

test('should add the arbitrary variables to the collected', () => {
const input = [
{
id: 'm6aty8by',
Name: 'SUGGESTER',
type: 'CollectedVariableType',
Label: 'SUGGESTER label',
Datatype: {
type: 'TextDatatypeType',
Pattern: '',
typeName: 'TEXT',
MaxLength: 1,
},
CodeListReference: 'id',
},
{
id: 'm6atzjnb',
Name: 'SUGGESTER_ARBITRARY',
type: 'CollectedVariableType',
Label: 'SUGGESTER_ARBITRARY label',
Datatype: {
type: 'TextDatatypeType',
typeName: 'TEXT',
MaxLength: 249,
},
arbitraryOfVariable: 'm6aty8by',
},
];
const arbitraryVariables = [
{
Datatype: {
type: 'TextDatatypeType',
typeName: 'TEXT',
MaxLength: 249,
},
mandatory: false,
CollectedVariableReference: 'm6atzjnb',
arbitraryOfVariable: 'm6aty8by',
},
];
const responsesByVariable = { m6aty8by: {} };
const codesListStore = { id: { label: 'label' } };
const variableclarification = [];
const output = {
m6aty8by: {
id: 'm6aty8by',
name: 'SUGGESTER',
label: 'SUGGESTER label',
type: TEXT,
codeListReference: 'id',
codeListReferenceLabel: 'label',
TEXT: {
maxLength: 1,
pattern: '',
},
},
m6atzjnb: {
id: 'm6atzjnb',
name: 'SUGGESTER_ARBITRARY',
label: 'SUGGESTER_ARBITRARY label',
type: TEXT,
codeListReferenceLabel: '',
TEXT: {
maxLength: 249,
},
arbitraryOfVariable: 'm6aty8by',
},
};

expect(
remoteToStore(
input,
responsesByVariable,
codesListStore,
variableclarification,
arbitraryVariables,
),
).toEqual(output);
});
});
describe('remoteToComponentState', () => {
test('should return the state representation of a collected variable', () => {
Expand Down
97 changes: 97 additions & 0 deletions src/model/transformations/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,61 @@ export const getClarificarionfromremote = (Children, collectedVariables) => {
return variableClarification;
};

/*
* Get the list of questions containing an attribute "ArbitraryResponse".
* Currently we only look at single response questions.
*/
const getArbitraryQuestions = (Children) => {
const arbitraryQuestions = [];
const childr = Children.filter((children) => children.Child?.length !== 0);
childr.forEach((item) => {
item.Child?.forEach((component) => {
// component is a subsequence
if (component.type === 'SequenceType') {
component.Child.forEach((question) => {
if (
// single choice question
question.questionType === SINGLE_CHOICE &&
question.ArbitraryResponse !== undefined
) {
arbitraryQuestions.push(question);
}
});
} else if (
// component is a single choice question
component.questionType === SINGLE_CHOICE &&
component.ArbitraryResponse !== undefined
) {
arbitraryQuestions.push(component);
}
});
});
return arbitraryQuestions;
};

/*
* Get the list of arbitrary variables.
* An arbitrary variable is the "ArbitraryResponse" object of a question,
* adding "arbitraryOfVariable" which is the corresponding Response variable.
QRuhier marked this conversation as resolved.
Show resolved Hide resolved
*/
export const getArbitraryResponsesFromRemote = (Children) => {
const arbitraryVariables = [];
const arbitraryQuestions = getArbitraryQuestions(Children);

arbitraryQuestions.forEach((question) => {
// a question with arbitrary is a singleReponse question so it has only one Response
const responseVariableId = question.Response[0].CollectedVariableReference;

const arbitraryVariable = {
...question.ArbitraryResponse,
arbitraryOfVariable: responseVariableId,
};
arbitraryVariables.push(arbitraryVariable);
});

return arbitraryVariables;
};

function remoteToVariableResponseNested(children = [], acc = {}) {
children.forEach((child) => {
const {
Expand Down Expand Up @@ -226,6 +281,7 @@ function remoteToState(remote, componentGroup, codesListsStore) {
Control: controls,
Response: responses,
ClarificationQuestion: responsesClarification,
ArbitraryResponse: arbitraryResponse,
ResponseStructure: responseStructure,
Child: children,
parent,
Expand All @@ -250,6 +306,10 @@ function remoteToState(remote, componentGroup, codesListsStore) {
responseFinal = responseFinal.concat(clar.Response);
});
}
if (arbitraryResponse !== undefined) {
responseFinal.push(arbitraryResponse);
}

const state = {
id,
name,
Expand Down Expand Up @@ -629,6 +689,36 @@ function getClarificationResponseTableQuestion(
};
}

function getArbitraryResponse(collectedVariablesStore, collectedVariables) {
const collectedvariablequestion = [];
QRuhier marked this conversation as resolved.
Show resolved Hide resolved
Object.values(collectedVariablesStore).forEach((collec) => {
if (collectedVariables !== undefined) {
collectedVariables.forEach((variables) => {
if (collec.id === variables) {
collectedvariablequestion.push(collec);
}
});
}
});

for (const collected of collectedvariablequestion) {
const isArbitraryVariable = collected.arbitraryOfVariable !== undefined;
// we can have only one collected variable that is an arbitrary variable
if (isArbitraryVariable) {
const responseModel = {
mandatory: false,
typeName: collected.type,
maxLength: collected.TEXT.maxLength,
collectedVariable: collected.id,
};
const arbitraryResponse = Response.stateToRemote(responseModel);
return arbitraryResponse;
}
}

return undefined;
}

function storeToRemoteNested(
state,
store,
Expand Down Expand Up @@ -686,8 +776,15 @@ function storeToRemoteNested(
responsesClarification,
flowControl,
);

remote.FlowControl = remoteclarification.flowcontrolefinal;
remote.ClarificationQuestion = remoteclarification.ClarificationQuestion;

const remoteArbitrary = getArbitraryResponse(
collectedVariablesStore,
collectedVariables,
);
remote.ArbitraryResponse = remoteArbitrary;
}
if (
responseFormat.type === MULTIPLE_CHOICE &&
Expand Down
Loading
Loading