@planning-inspectorate/dynamic-forms 3.20.5 → 3.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/docs/Dynamic Sections.md +47 -0
- package/docs/Getting Started.md +8 -2
- package/package.json +1 -1
- package/src/components/boolean/question.d.ts +1 -1
- package/src/components/boolean/question.js +1 -1
- package/src/components/date/question.d.ts +1 -1
- package/src/components/date/question.js +1 -1
- package/src/components/date-period/question.d.ts +1 -1
- package/src/components/date-period/question.js +1 -1
- package/src/components/date-time/question.d.ts +1 -1
- package/src/components/date-time/question.js +1 -1
- package/src/components/manage-list/question.d.ts.map +1 -1
- package/src/components/manage-list/question.js +5 -0
- package/src/components/manage-list/question.test.js +3 -1
- package/src/components/multi-field-input/question.d.ts.map +1 -1
- package/src/components/multi-field-input/question.js +8 -6
- package/src/components/multi-field-input/question.test.js +126 -213
- package/src/components/single-line-input/index.njk +4 -0
- package/src/components/single-line-input/question.d.ts +2 -0
- package/src/components/single-line-input/question.d.ts.map +1 -1
- package/src/components/single-line-input/question.js +4 -0
- package/src/components/single-line-input/question.test.js +6 -0
- package/src/components/text-entry-redact/question.d.ts.map +1 -1
- package/src/components/text-entry-redact/question.js +3 -1
- package/src/components/text-entry-redact/question.test.js +9 -0
- package/src/components/unit-option-entry/question.d.ts +1 -1
- package/src/components/unit-option-entry/question.d.ts.map +1 -1
- package/src/components/unit-option-entry/question.js +4 -2
- package/src/components/unit-option-entry/question.test.js +9 -0
- package/src/controller.d.ts +15 -3
- package/src/controller.d.ts.map +1 -1
- package/src/controller.js +19 -11
- package/src/controller.test.js +182 -153
- package/src/dynamic-section.d.ts +40 -0
- package/src/dynamic-section.d.ts.map +1 -0
- package/src/dynamic-section.js +51 -0
- package/src/dynamic-section.test.js +113 -0
- package/src/index.d.ts +2 -1
- package/src/index.js +2 -1
- package/src/index.test.js +3 -0
- package/src/journey/journey.d.ts +10 -0
- package/src/journey/journey.d.ts.map +1 -1
- package/src/journey/journey.js +15 -0
- package/src/lib/answer-utils.d.ts +22 -0
- package/src/lib/answer-utils.d.ts.map +1 -0
- package/src/lib/answer-utils.js +34 -0
- package/src/{components/manage-list/utils.test.js → lib/answer-utils.test.js} +9 -11
- package/src/lib/session-answer-store.d.ts.map +1 -1
- package/src/lib/session-answer-store.js +14 -6
- package/src/lib/session-answer-store.test.js +43 -0
- package/src/middleware/redirect-to-unanswered-question.d.ts.map +1 -1
- package/src/middleware/redirect-to-unanswered-question.js +4 -3
- package/src/middleware/redirect-to-unanswered-question.test.js +32 -0
- package/src/questions/options-question.js +1 -1
- package/src/questions/question.d.ts +8 -3
- package/src/questions/question.d.ts.map +1 -1
- package/src/questions/question.js +16 -6
- package/src/questions/question.test.js +19 -0
- package/src/section.d.ts +19 -0
- package/src/section.d.ts.map +1 -1
- package/src/section.js +50 -9
- package/src/section.test.js +9 -0
- package/test/dynamic-journey.test.js +372 -0
- package/typedefs/question-props.d.ts +3 -1
- package/typedefs/question-types.d.ts +3 -0
- package/src/components/manage-list/utils.d.ts +0 -18
- package/src/components/manage-list/utils.d.ts.map +0 -1
- package/src/components/manage-list/utils.js +0 -35
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use a dynamic section for sections which are generated from an array of objects
|
|
3
|
+
*
|
|
4
|
+
* This can be useful for adding a section for each entry in a ManageList, or each row in a database
|
|
5
|
+
* The controller logic, when encountering a DynamicSection, will check for an answer object within
|
|
6
|
+
* `journeyResponse.answers[fieldName]`, matching by the `id` property
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* answers = {
|
|
10
|
+
* myField: 'some answer',
|
|
11
|
+
* list: [
|
|
12
|
+
* { id: 'person-id-1', name: 'Grogu' },
|
|
13
|
+
* { id: 'person-id-2', name: 'Mando' }
|
|
14
|
+
* ]
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* In this example, create a DynamicSection for each list entry:
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* function createPersonSection(person) {
|
|
22
|
+
* return new DynamicSection(person.name, person.id, 'list')
|
|
23
|
+
* .addQuestion(questions.name)
|
|
24
|
+
* // ... add questions
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* When using with buildSave, be sure to handle the parameters: `isDynamicSection`, `dynamicSectionId`,`dynamicSectionFieldName`
|
|
29
|
+
*/
|
|
30
|
+
export class DynamicSection extends Section {
|
|
31
|
+
/**
|
|
32
|
+
* @param name
|
|
33
|
+
* @param segment
|
|
34
|
+
* @param fieldName the key used in the answers object, which will be an array of answers for this section
|
|
35
|
+
*/
|
|
36
|
+
constructor(name: any, segment: any, fieldName: any);
|
|
37
|
+
fieldName: any;
|
|
38
|
+
}
|
|
39
|
+
import { Section } from '#section';
|
|
40
|
+
//# sourceMappingURL=dynamic-section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-section.d.ts","sourceRoot":"","sources":["dynamic-section.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;IACC;;;;OAIG;IACH,qDAIC;IADA,eAA0B;CAU3B;wBAlDuB,UAAU"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Section } from '#section';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Use a dynamic section for sections which are generated from an array of objects
|
|
5
|
+
*
|
|
6
|
+
* This can be useful for adding a section for each entry in a ManageList, or each row in a database
|
|
7
|
+
* The controller logic, when encountering a DynamicSection, will check for an answer object within
|
|
8
|
+
* `journeyResponse.answers[fieldName]`, matching by the `id` property
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* answers = {
|
|
12
|
+
* myField: 'some answer',
|
|
13
|
+
* list: [
|
|
14
|
+
* { id: 'person-id-1', name: 'Grogu' },
|
|
15
|
+
* { id: 'person-id-2', name: 'Mando' }
|
|
16
|
+
* ]
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* In this example, create a DynamicSection for each list entry:
|
|
21
|
+
*
|
|
22
|
+
* ```
|
|
23
|
+
* function createPersonSection(person) {
|
|
24
|
+
* return new DynamicSection(person.name, person.id, 'list')
|
|
25
|
+
* .addQuestion(questions.name)
|
|
26
|
+
* // ... add questions
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* When using with buildSave, be sure to handle the parameters: `isDynamicSection`, `dynamicSectionId`,`dynamicSectionFieldName`
|
|
31
|
+
*/
|
|
32
|
+
export class DynamicSection extends Section {
|
|
33
|
+
/**
|
|
34
|
+
* @param name
|
|
35
|
+
* @param segment
|
|
36
|
+
* @param fieldName the key used in the answers object, which will be an array of answers for this section
|
|
37
|
+
*/
|
|
38
|
+
constructor(name, segment, fieldName) {
|
|
39
|
+
super(name, segment);
|
|
40
|
+
|
|
41
|
+
this.fieldName = fieldName;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Indicate that this section is dynamic, and answers should be pulled from an array
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
get isDynamicSection() {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, it, mock } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { DynamicSection } from '#src/dynamic-section.js';
|
|
4
|
+
import { SECTION_STATUS } from '#section';
|
|
5
|
+
import { Question } from '#question';
|
|
6
|
+
|
|
7
|
+
// use a real question to avoid mocking lots of logic
|
|
8
|
+
const mockQuestion = (fieldName = 'fieldName', required = true) =>
|
|
9
|
+
new Question({
|
|
10
|
+
fieldName: fieldName,
|
|
11
|
+
title: 'question',
|
|
12
|
+
question: 'question',
|
|
13
|
+
viewFolder: 'folder',
|
|
14
|
+
validators: [
|
|
15
|
+
{
|
|
16
|
+
isRequired() {
|
|
17
|
+
return required;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('dynamic-section', () => {
|
|
24
|
+
describe('responseForSection', () => {
|
|
25
|
+
it('should return inner object for dynamic section', () => {
|
|
26
|
+
const section = new DynamicSection('s1', 'id-1', 'myList');
|
|
27
|
+
const answers = { id: 'id-1', myField: 'answer' };
|
|
28
|
+
const res = {
|
|
29
|
+
answers: {
|
|
30
|
+
myList: [{ id: 'id-2' }, { id: 'id-3' }, answers]
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const got = section.getResponse(res);
|
|
34
|
+
assert.strictEqual(got?.answers, answers);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('getStatus', () => {
|
|
39
|
+
it('should use section answers for status', () => {
|
|
40
|
+
const s1Answers = { id: 'S', fieldOne: 'answer' };
|
|
41
|
+
const mockJourneyResponse = {
|
|
42
|
+
answers: {
|
|
43
|
+
visitFrequently: 'Answer 1',
|
|
44
|
+
anotherFieldName: 'Answer 2',
|
|
45
|
+
myList: [s1Answers]
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const requiredQuestion = mockQuestion('visitFrequently');
|
|
50
|
+
|
|
51
|
+
const section = new DynamicSection('s1', 'S', 'myList');
|
|
52
|
+
section.addQuestion(requiredQuestion);
|
|
53
|
+
|
|
54
|
+
mock.method(requiredQuestion, 'shouldDisplay');
|
|
55
|
+
mock.method(requiredQuestion, 'isAnswered');
|
|
56
|
+
|
|
57
|
+
section.getStatus(mockJourneyResponse);
|
|
58
|
+
|
|
59
|
+
assert.strictEqual(requiredQuestion.shouldDisplay.mock.callCount(), 1);
|
|
60
|
+
assert.strictEqual(requiredQuestion.isAnswered.mock.callCount(), 2);
|
|
61
|
+
assert.strictEqual(requiredQuestion.shouldDisplay.mock.calls[0].arguments[0].answers, s1Answers);
|
|
62
|
+
assert.strictEqual(requiredQuestion.isAnswered.mock.calls[0].arguments[0].answers, s1Answers);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should return NOT_STARTED when no answers are given', () => {
|
|
66
|
+
const mockJourneyResponse = {
|
|
67
|
+
answers: {}
|
|
68
|
+
};
|
|
69
|
+
const section = new DynamicSection('s1', 'S', 'myList');
|
|
70
|
+
section.addQuestion(mockQuestion());
|
|
71
|
+
const result = section.getStatus(mockJourneyResponse);
|
|
72
|
+
assert.strictEqual(result, SECTION_STATUS.NOT_STARTED);
|
|
73
|
+
const isComplete = section.isComplete(mockJourneyResponse);
|
|
74
|
+
assert.strictEqual(isComplete, false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return IN_PROGRESS when at least one answer is given', () => {
|
|
78
|
+
const mockJourneyResponse = {
|
|
79
|
+
answers: {
|
|
80
|
+
myList: [{ id: 'S', visitFrequently: 'Answer 1' }]
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const section = new DynamicSection('s1', 'S', 'myList');
|
|
85
|
+
section.addQuestion(mockQuestion());
|
|
86
|
+
section.addQuestion(mockQuestion('visitFrequently'));
|
|
87
|
+
const result = section.getStatus(mockJourneyResponse);
|
|
88
|
+
assert.strictEqual(result, SECTION_STATUS.IN_PROGRESS);
|
|
89
|
+
const isComplete = section.isComplete(mockJourneyResponse);
|
|
90
|
+
assert.strictEqual(isComplete, false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return COMPLETE when all required answers are given', () => {
|
|
94
|
+
const s1Answers = { id: 'S', visitFrequently: 'answer', anotherFieldName: true };
|
|
95
|
+
const mockJourneyResponse = {
|
|
96
|
+
answers: {
|
|
97
|
+
myList: [s1Answers]
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const section = new DynamicSection('s1', 'S', 'myList');
|
|
102
|
+
section.addQuestion(mockQuestion('visitFrequently'));
|
|
103
|
+
section.addQuestion(mockQuestion('anotherFieldName'));
|
|
104
|
+
section.addQuestion(mockQuestion('someQuestion', false));
|
|
105
|
+
|
|
106
|
+
const result = section.getStatus(mockJourneyResponse);
|
|
107
|
+
assert.strictEqual(result, SECTION_STATUS.COMPLETE);
|
|
108
|
+
|
|
109
|
+
const isComplete = section.isComplete(mockJourneyResponse);
|
|
110
|
+
assert.strictEqual(isComplete, true);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
package/src/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export * from "./lib/utils.js";
|
|
|
32
32
|
export * from "./middleware/build-get-journey.js";
|
|
33
33
|
export * from "./middleware/redirect-to-unanswered-question.js";
|
|
34
34
|
export * from "./questions/options-question.js";
|
|
35
|
+
export * from "./dynamic-section.js";
|
|
36
|
+
export * from "./section.js";
|
|
35
37
|
export * from "./validator/address-validator.js";
|
|
36
38
|
export * from "./validator/base-validator.js";
|
|
37
39
|
export * from "./validator/conditional-required-validator.js";
|
|
@@ -58,6 +60,5 @@ export { JourneyResponse } from "./journey/journey-response.js";
|
|
|
58
60
|
export { Question } from "./questions/question.js";
|
|
59
61
|
export { createQuestions } from "./questions/create-questions.js";
|
|
60
62
|
export { questionClasses } from "./questions/questions.js";
|
|
61
|
-
export { Section } from "./section.js";
|
|
62
63
|
export { default as validate } from "./validator/validator.js";
|
|
63
64
|
//# sourceMappingURL=index.d.ts.map
|
package/src/index.js
CHANGED
|
@@ -55,7 +55,8 @@ export * from './questions/options-question.js';
|
|
|
55
55
|
export { questionClasses } from './questions/questions.js';
|
|
56
56
|
|
|
57
57
|
// Section
|
|
58
|
-
export
|
|
58
|
+
export * from './dynamic-section.js';
|
|
59
|
+
export * from './section.js';
|
|
59
60
|
|
|
60
61
|
// Validators
|
|
61
62
|
export * from './validator/address-validator.js';
|
package/src/index.test.js
CHANGED
|
@@ -52,6 +52,7 @@ describe('public API', () => {
|
|
|
52
52
|
assert.equal(typeof api.Question, 'function');
|
|
53
53
|
assert.equal(typeof api.createQuestions, 'function');
|
|
54
54
|
assert.equal(typeof api.questionClasses, 'object');
|
|
55
|
+
assert.equal(typeof api.DynamicSection, 'function');
|
|
55
56
|
assert.equal(typeof api.Section, 'function');
|
|
56
57
|
assert.equal(typeof api.Journey, 'function');
|
|
57
58
|
assert.equal(typeof api.JourneyResponse, 'function');
|
|
@@ -84,5 +85,7 @@ describe('public API', () => {
|
|
|
84
85
|
assert.equal(typeof api.booleanToYesNoOrNull, 'function');
|
|
85
86
|
assert.equal(typeof api.REDACT_CHARACTER, 'string');
|
|
86
87
|
assert.equal(typeof api.TRUNCATED_MAX_LENGTH, 'number');
|
|
88
|
+
assert.equal(typeof api.END_OF_SECTION, 'symbol');
|
|
89
|
+
assert.equal(typeof api.SECTION_STATUS, 'object');
|
|
87
90
|
});
|
|
88
91
|
});
|
package/src/journey/journey.d.ts
CHANGED
|
@@ -60,6 +60,16 @@ export class Journey {
|
|
|
60
60
|
* @returns {import('../section.js').Section | undefined}
|
|
61
61
|
*/
|
|
62
62
|
getSection(sectionSegment: string): import("../section.js").Section | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Get the response for the given section, required to support dynamic sections
|
|
65
|
+
*
|
|
66
|
+
* Often used in formatAnswerForSummary to get other answer fields.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} sectionSegment
|
|
69
|
+
*/
|
|
70
|
+
responseForSection(sectionSegment: string): import("./journey-response.js").JourneyResponse<import("#typedefs/journey-types.d.ts").JourneyAnswers> | {
|
|
71
|
+
answers: Record<string, unknown>;
|
|
72
|
+
};
|
|
63
73
|
/**
|
|
64
74
|
* gets a question from the object's sections based on a section + question names
|
|
65
75
|
* @param {import('#typedefs/journey-types.d.ts').RouteParams} params
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journey.d.ts","sourceRoot":"","sources":["journey.js"],"names":[],"mappings":"AAQA;;;GAGG;AACH;IAwBC;;;;;;;;;;;;;;OAcG;IACH,qLAZG;QAAwB,SAAS,EAAzB,MAAM;QACyE,WAAW,EAA1F,CAAC,QAAQ,EAAE,OAAO,uBAAuB,EAAE,eAAe,KAAK,MAAM;QACpD,WAAW;QAC6B,QAAQ,EAAjE,OAAO,uBAAuB,EAAE,eAAe;QAC/B,eAAe,EAA/B,MAAM;QACU,gBAAgB,EAAhC,MAAM;QACW,uBAAuB;QACxB,YAAY,EAA5B,MAAM;QACY,eAAe;QACU,QAAQ,EAAnD,OAAO,eAAe,EAAE,OAAO,EAAE;QAChB,eAAe;KAC1C,EAoDA;IAzFD,8EAA8E;IAC9E,WADW,MAAM,CACP;IACV,6FAA6F;IAC7F,UADW,KAAK,CAAE,OAAO,eAAe,EAAE,OAAO,CAAC,CACpC;IACd,mHAAmH;IACnH,UADW,OAAO,uBAAuB,EAAE,eAAe,CACjD;IACT,wFAAwF;IACxF,SADW,MAAM,CACJ;IACb,sJAAsJ;IACtJ,aADW,CAAC,eAAe,EAAE,OAAO,uBAAuB,EAAE,eAAe,KAAK,MAAM,CAChE;IACvB,kEAAkE;IAClE,aADW,MAAM,CACA;IACjB,uEAAuE;IACvE,iBADW,MAAM,CACI;IACrB,qFAAqF;IACrF,kBADW,MAAM,CACK;IACtB,4GAA4G;IAC5G,yBADW,MAAM,CACY;IAC7B,qFAAqF;IACrF,iBADW,OAAO,CACM;IACxB,2DAA2D;IAC3D,cADU,MAAM,CACH;IAmEZ,+BAA8C;IA2C/C;;;;OAIG;IACH,2BAHW,MAAM,GACJ,OAAO,eAAe,EAAE,OAAO,GAAG,SAAS,CAMvD;IA8BD;;;;OAIG;IACH,4BAHW,OAAO,8BAA8B,EAAE,WAAW,GAChD,OAAO,0BAA0B,EAAE,QAAQ,GAAG,SAAS,CAiBnE;IAED;;;;;;;OAOG;IACH,4CAJG;QAAoE,MAAM,EAAlE,OAAO,8BAA8B,EAAE,WAAW;QACU,kBAAkB;KACtF,GAAU,MAAM,GAAC,IAAI,CAWvB;IAED;;;;;;;;OAQG;IACH,4BALW,OAAO,SAAS,EAAE,QAAQ,UAC1B,OAAO,8BAA8B,EAAE,WAAW,kFAEhD,IAAI,CAKhB;IAED;;;;;;;;OAQG;IACH,2BANW,OAAO,8BAA8B,EAAE,WAAW,oCAE1D;QAA0B,OAAO;QACmC,kBAAkB;KACtF,GAAU,MAAM,GAAC,IAAI,CAyEvB;IAED;;;;;OAKG;IACH,wBAAyB,gBAJd,MAI4B,EAAE,iBAH9B,MAG6C,KAF3C,MAAM,CAqBjB;IAEF;;;;OAIG;IACH,sCAAuC,iBAH5B,MAG2C,KAFzC,MAAM,CAIjB;IAEF;;;;;;OAMG;IACH,0BAA2B,gBALhB,MAK8B,EAAE,iBAJhC,MAI+C,EAAE,UAHjD,MAGyD,KAFvD,MAAM,CAuBjB;IAEF;;;OAGG;IACH,cAFa,OAAO,CAInB;IAED;;OAEG;IACH,6BAFW,OAAO,uBAAuB,EAAE,eAAe,QAKzD;;CACD"}
|
|
1
|
+
{"version":3,"file":"journey.d.ts","sourceRoot":"","sources":["journey.js"],"names":[],"mappings":"AAQA;;;GAGG;AACH;IAwBC;;;;;;;;;;;;;;OAcG;IACH,qLAZG;QAAwB,SAAS,EAAzB,MAAM;QACyE,WAAW,EAA1F,CAAC,QAAQ,EAAE,OAAO,uBAAuB,EAAE,eAAe,KAAK,MAAM;QACpD,WAAW;QAC6B,QAAQ,EAAjE,OAAO,uBAAuB,EAAE,eAAe;QAC/B,eAAe,EAA/B,MAAM;QACU,gBAAgB,EAAhC,MAAM;QACW,uBAAuB;QACxB,YAAY,EAA5B,MAAM;QACY,eAAe;QACU,QAAQ,EAAnD,OAAO,eAAe,EAAE,OAAO,EAAE;QAChB,eAAe;KAC1C,EAoDA;IAzFD,8EAA8E;IAC9E,WADW,MAAM,CACP;IACV,6FAA6F;IAC7F,UADW,KAAK,CAAE,OAAO,eAAe,EAAE,OAAO,CAAC,CACpC;IACd,mHAAmH;IACnH,UADW,OAAO,uBAAuB,EAAE,eAAe,CACjD;IACT,wFAAwF;IACxF,SADW,MAAM,CACJ;IACb,sJAAsJ;IACtJ,aADW,CAAC,eAAe,EAAE,OAAO,uBAAuB,EAAE,eAAe,KAAK,MAAM,CAChE;IACvB,kEAAkE;IAClE,aADW,MAAM,CACA;IACjB,uEAAuE;IACvE,iBADW,MAAM,CACI;IACrB,qFAAqF;IACrF,kBADW,MAAM,CACK;IACtB,4GAA4G;IAC5G,yBADW,MAAM,CACY;IAC7B,qFAAqF;IACrF,iBADW,OAAO,CACM;IACxB,2DAA2D;IAC3D,cADU,MAAM,CACH;IAmEZ,+BAA8C;IA2C/C;;;;OAIG;IACH,2BAHW,MAAM,GACJ,OAAO,eAAe,EAAE,OAAO,GAAG,SAAS,CAMvD;IAED;;;;;;OAMG;IACH,mCAFW,MAAM;;MAQhB;IA8BD;;;;OAIG;IACH,4BAHW,OAAO,8BAA8B,EAAE,WAAW,GAChD,OAAO,0BAA0B,EAAE,QAAQ,GAAG,SAAS,CAiBnE;IAED;;;;;;;OAOG;IACH,4CAJG;QAAoE,MAAM,EAAlE,OAAO,8BAA8B,EAAE,WAAW;QACU,kBAAkB;KACtF,GAAU,MAAM,GAAC,IAAI,CAWvB;IAED;;;;;;;;OAQG;IACH,4BALW,OAAO,SAAS,EAAE,QAAQ,UAC1B,OAAO,8BAA8B,EAAE,WAAW,kFAEhD,IAAI,CAKhB;IAED;;;;;;;;OAQG;IACH,2BANW,OAAO,8BAA8B,EAAE,WAAW,oCAE1D;QAA0B,OAAO;QACmC,kBAAkB;KACtF,GAAU,MAAM,GAAC,IAAI,CAyEvB;IAED;;;;;OAKG;IACH,wBAAyB,gBAJd,MAI4B,EAAE,iBAH9B,MAG6C,KAF3C,MAAM,CAqBjB;IAEF;;;;OAIG;IACH,sCAAuC,iBAH5B,MAG2C,KAFzC,MAAM,CAIjB;IAEF;;;;;;OAMG;IACH,0BAA2B,gBALhB,MAK8B,EAAE,iBAJhC,MAI+C,EAAE,UAHjD,MAGyD,KAFvD,MAAM,CAuBjB;IAEF;;;OAGG;IACH,cAFa,OAAO,CAInB;IAED;;OAEG;IACH,6BAFW,OAAO,uBAAuB,EAAE,eAAe,QAKzD;;CACD"}
|
package/src/journey/journey.js
CHANGED
|
@@ -153,6 +153,21 @@ export class Journey {
|
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Get the response for the given section, required to support dynamic sections
|
|
158
|
+
*
|
|
159
|
+
* Often used in formatAnswerForSummary to get other answer fields.
|
|
160
|
+
*
|
|
161
|
+
* @param {string} sectionSegment
|
|
162
|
+
*/
|
|
163
|
+
responseForSection(sectionSegment) {
|
|
164
|
+
const section = this.getSection(sectionSegment);
|
|
165
|
+
if (!section) {
|
|
166
|
+
throw new Error(`No section found for section segment: '${sectionSegment}'`);
|
|
167
|
+
}
|
|
168
|
+
return section.getResponse(this.response);
|
|
169
|
+
}
|
|
170
|
+
|
|
156
171
|
/**
|
|
157
172
|
* Get question within a section
|
|
158
173
|
* @param {import('../section.js').Section} section
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {import('#journey-response').JourneyResponse} response
|
|
4
|
+
* @param {{fieldName: string}} withFieldName
|
|
5
|
+
* @param {string} itemId
|
|
6
|
+
* @returns {Record<string, unknown>}
|
|
7
|
+
*/
|
|
8
|
+
export function answerObjectForListItem(response: import("#journey-response").JourneyResponse, withFieldName: {
|
|
9
|
+
fieldName: string;
|
|
10
|
+
}, itemId: string): Record<string, unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Similar to answerObjectForListItem but will edit response and add a new array entry if not found
|
|
13
|
+
*
|
|
14
|
+
* @param {import('#journey-response').JourneyResponse} response
|
|
15
|
+
* @param {{fieldName: string}} withFieldName
|
|
16
|
+
* @param {string} itemId
|
|
17
|
+
* @returns {import('#typedefs/journey-types.d.ts').ManageListAnswers}
|
|
18
|
+
*/
|
|
19
|
+
export function answerObjectForListItemSaving(response: import("#journey-response").JourneyResponse, withFieldName: {
|
|
20
|
+
fieldName: string;
|
|
21
|
+
}, itemId: string): import("#typedefs/journey-types.d.ts").ManageListAnswers;
|
|
22
|
+
//# sourceMappingURL=answer-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-utils.d.ts","sourceRoot":"","sources":["answer-utils.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,kDALW,OAAO,mBAAmB,EAAE,eAAe,iBAC3C;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,UACnB,MAAM,GACJ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQnC;AAED;;;;;;;GAOG;AACH,wDALW,OAAO,mBAAmB,EAAE,eAAe,iBAC3C;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,UACnB,MAAM,GACJ,OAAO,8BAA8B,EAAE,iBAAiB,CAYpE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {import('#journey-response').JourneyResponse} response
|
|
4
|
+
* @param {{fieldName: string}} withFieldName
|
|
5
|
+
* @param {string} itemId
|
|
6
|
+
* @returns {Record<string, unknown>}
|
|
7
|
+
*/
|
|
8
|
+
export function answerObjectForListItem(response, withFieldName, itemId) {
|
|
9
|
+
const answers = response.answers[withFieldName.fieldName];
|
|
10
|
+
if (!Array.isArray(answers)) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
return answers.find((a) => a.id === itemId) || {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Similar to answerObjectForListItem but will edit response and add a new array entry if not found
|
|
18
|
+
*
|
|
19
|
+
* @param {import('#journey-response').JourneyResponse} response
|
|
20
|
+
* @param {{fieldName: string}} withFieldName
|
|
21
|
+
* @param {string} itemId
|
|
22
|
+
* @returns {import('#typedefs/journey-types.d.ts').ManageListAnswers}
|
|
23
|
+
*/
|
|
24
|
+
export function answerObjectForListItemSaving(response, withFieldName, itemId) {
|
|
25
|
+
const answersList = response.answers[withFieldName?.fieldName] || (response.answers[withFieldName?.fieldName] = []);
|
|
26
|
+
let answers = answersList.find((item) => item.id === itemId);
|
|
27
|
+
if (!answers) {
|
|
28
|
+
answers = {
|
|
29
|
+
id: itemId
|
|
30
|
+
};
|
|
31
|
+
answersList.push(answers);
|
|
32
|
+
}
|
|
33
|
+
return answers;
|
|
34
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
|
-
import {
|
|
3
|
+
import { answerObjectForListItem, answerObjectForListItemSaving } from '#src/lib/answer-utils.js';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
6
|
-
describe('
|
|
5
|
+
describe('answer-utils', () => {
|
|
6
|
+
describe('answerObjectForListItem', () => {
|
|
7
7
|
it('should return the manage list item object for manage list questions', () => {
|
|
8
8
|
const manageListQuestion = {
|
|
9
9
|
fieldName: 'manageListQuestion'
|
|
@@ -18,7 +18,7 @@ describe('manage-list-utils', () => {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
const manageListItemId = '1';
|
|
21
|
-
const got =
|
|
21
|
+
const got = answerObjectForListItem(journeyResponse, manageListQuestion, manageListItemId);
|
|
22
22
|
assert.strictEqual(got, answers);
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -36,16 +36,16 @@ describe('manage-list-utils', () => {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
const manageListItemId = '1';
|
|
39
|
-
let got =
|
|
39
|
+
let got = answerObjectForListItem(journeyResponse, manageListQuestion, manageListItemId);
|
|
40
40
|
assert.deepStrictEqual(got, {});
|
|
41
41
|
// also fallback to {} if there is no manageListQuestion answer
|
|
42
42
|
delete journeyResponse.answers.manageListQuestion;
|
|
43
|
-
got =
|
|
43
|
+
got = answerObjectForListItem(journeyResponse, manageListQuestion, manageListItemId);
|
|
44
44
|
assert.deepStrictEqual(got, {});
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
describe('
|
|
48
|
+
describe('answerObjectForListItemSaving', () => {
|
|
49
49
|
it('should add an array with a new object if not found', () => {
|
|
50
50
|
const manageListQuestion = {
|
|
51
51
|
fieldName: 'manageListQuestion'
|
|
@@ -53,8 +53,7 @@ describe('manage-list-utils', () => {
|
|
|
53
53
|
const journeyResponse = {
|
|
54
54
|
answers: {}
|
|
55
55
|
};
|
|
56
|
-
const
|
|
57
|
-
const got = answerObjectForManageListSaving(journeyResponse, manageListQuestion, params);
|
|
56
|
+
const got = answerObjectForListItemSaving(journeyResponse, manageListQuestion, '1');
|
|
58
57
|
assert.deepStrictEqual(got, { id: '1' });
|
|
59
58
|
assert.ok(Array.isArray(journeyResponse.answers.manageListQuestion));
|
|
60
59
|
assert.ok(journeyResponse.answers.manageListQuestion[0]?.id, '1');
|
|
@@ -72,8 +71,7 @@ describe('manage-list-utils', () => {
|
|
|
72
71
|
manageListQuestion: [answers]
|
|
73
72
|
}
|
|
74
73
|
};
|
|
75
|
-
const
|
|
76
|
-
const got = answerObjectForManageListSaving(journeyResponse, manageListQuestion, params);
|
|
74
|
+
const got = answerObjectForListItemSaving(journeyResponse, manageListQuestion, '1');
|
|
77
75
|
assert.strictEqual(got, answers);
|
|
78
76
|
});
|
|
79
77
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-answer-store.d.ts","sourceRoot":"","sources":["session-answer-store.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,sDAJG;IAAsB,QAAQ;CAE9B,GAAU,OAAO,kBAAkB,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"session-answer-store.d.ts","sourceRoot":"","sources":["session-answer-store.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,sDAJG;IAAsB,QAAQ;CAE9B,GAAU,OAAO,kBAAkB,EAAE,UAAU,CAsDjD;AASD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,gFANG;IAA0C,GAAG,EAArC,OAAO,SAAS,EAAE,OAAO;IACV,SAAS,EAAxB,MAAM;IACuB,WAAW;;;IACxB,QAAQ;CAChC,GAAU,IAAI,CAkBhB;AAED;;;;;;GAMG;AACH,8DAJW,MAAM,aACN,MAAM,GACJ,OAAO,SAAS,EAAE,OAAO,CA2BrC;AA/ED;;;;GAIG;AACH,gCAFU,OAAO,kBAAkB,EAAE,UAAU,CAEW"}
|
|
@@ -50,7 +50,10 @@ export function buildSaveDataToSession({ reqParam } = {}) {
|
|
|
50
50
|
data,
|
|
51
51
|
isManageListItem,
|
|
52
52
|
manageListQuestionFieldName,
|
|
53
|
-
manageListItemRemove = false
|
|
53
|
+
manageListItemRemove = false,
|
|
54
|
+
isDynamicSection,
|
|
55
|
+
dynamicSectionFieldName,
|
|
56
|
+
dynamicSectionId
|
|
54
57
|
}) => {
|
|
55
58
|
if (!req.session) {
|
|
56
59
|
throw new Error('request session required');
|
|
@@ -64,12 +67,17 @@ export function buildSaveDataToSession({ reqParam } = {}) {
|
|
|
64
67
|
}
|
|
65
68
|
let answers = forms[journeyId] || (forms[journeyId] = {});
|
|
66
69
|
|
|
67
|
-
if (isManageListItem) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
if (isManageListItem || isDynamicSection) {
|
|
71
|
+
// manage list and dynamic sections can be handled the same, just with different properties
|
|
72
|
+
// for the fieldName and item id
|
|
73
|
+
const fieldName = isManageListItem ? manageListQuestionFieldName : dynamicSectionFieldName;
|
|
74
|
+
const itemId = isManageListItem ? req.params.manageListItemId : dynamicSectionId;
|
|
75
|
+
|
|
76
|
+
const answersList = answers[fieldName] || (answers[fieldName] = []);
|
|
77
|
+
answers = answersList.find((item) => item.id === itemId);
|
|
70
78
|
if (!answers) {
|
|
71
|
-
answers = { id:
|
|
72
|
-
answersList.push(answers);
|
|
79
|
+
answers = { id: itemId }; // answers object to manipulate and add other answers to
|
|
80
|
+
answersList.push(answers); // add the answers object to the array
|
|
73
81
|
}
|
|
74
82
|
} else if (manageListItemRemove && manageListQuestionFieldName && req.params.manageListItemId) {
|
|
75
83
|
const answersList = answers[manageListQuestionFieldName];
|
|
@@ -123,6 +123,49 @@ describe('session-answer-store', () => {
|
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
+
it('should add a new dynamic section when not present in the session', async () => {
|
|
127
|
+
const req = mockReq();
|
|
128
|
+
req.session = {};
|
|
129
|
+
const journeyId = 'j-1';
|
|
130
|
+
const data = { answers: { q1: 'a1' } };
|
|
131
|
+
const isDynamicSection = true;
|
|
132
|
+
const dynamicSectionFieldName = 'myList';
|
|
133
|
+
const dynamicSectionId = 'section-1';
|
|
134
|
+
const saveDataToSession = buildSaveDataToSession();
|
|
135
|
+
await saveDataToSession({ req, journeyId, data, isDynamicSection, dynamicSectionFieldName, dynamicSectionId });
|
|
136
|
+
assert.deepStrictEqual(req.session, {
|
|
137
|
+
forms: {
|
|
138
|
+
'j-1': {
|
|
139
|
+
myList: [{ id: 'section-1', q1: 'a1' }]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
it('should add to an existing dynamic section using the id when present in the session', async () => {
|
|
145
|
+
const req = mockReq();
|
|
146
|
+
req.session = {
|
|
147
|
+
forms: {
|
|
148
|
+
'j-1': {
|
|
149
|
+
myList: [{ id: 'section-1', q1: 'old value' }]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const journeyId = 'j-1';
|
|
154
|
+
const data = { answers: { q2: 'a1' } };
|
|
155
|
+
const isDynamicSection = true;
|
|
156
|
+
const dynamicSectionFieldName = 'myList';
|
|
157
|
+
const dynamicSectionId = 'section-1';
|
|
158
|
+
const saveDataToSession = buildSaveDataToSession();
|
|
159
|
+
await saveDataToSession({ req, journeyId, data, isDynamicSection, dynamicSectionFieldName, dynamicSectionId });
|
|
160
|
+
assert.deepStrictEqual(req.session, {
|
|
161
|
+
forms: {
|
|
162
|
+
'j-1': {
|
|
163
|
+
myList: [{ id: 'section-1', q1: 'old value', q2: 'a1' }]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
126
169
|
it('should remove a managed list item using the id when present in the session', async () => {
|
|
127
170
|
const req = mockReq();
|
|
128
171
|
req.params = { manageListItemId: '56789' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect-to-unanswered-question.d.ts","sourceRoot":"","sources":["redirect-to-unanswered-question.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,0DAHW,sBAAsB,EAAE,GACtB,OAAO,SAAS,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"redirect-to-unanswered-question.d.ts","sourceRoot":"","sources":["redirect-to-unanswered-question.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,0DAHW,sBAAsB,EAAE,GACtB,OAAO,SAAS,EAAE,OAAO,CA+BrC;qCAtCY,CAAS,IAA2C,EAA3C,OAAO,0BAA0B,EAAE,QAAQ,EAAE,IAA2C,EAA3C,OAAO,mBAAmB,EAAE,eAAe,KAAG,OAAO"}
|
|
@@ -13,11 +13,12 @@ export function redirectToUnansweredQuestion(conditions = []) {
|
|
|
13
13
|
const { journeyResponse, journey } = res.locals;
|
|
14
14
|
|
|
15
15
|
for (const section of journey.sections) {
|
|
16
|
+
const response = section.getResponse(journeyResponse);
|
|
16
17
|
for (const question of section.questions) {
|
|
17
|
-
const answer =
|
|
18
|
+
const answer = response?.answers[question.fieldName];
|
|
18
19
|
|
|
19
|
-
const shouldSkip = conditions.some((condition) => condition(question,
|
|
20
|
-
const shouldDisplay = !question.shouldDisplay || question.shouldDisplay(
|
|
20
|
+
const shouldSkip = conditions.some((condition) => condition(question, response));
|
|
21
|
+
const shouldDisplay = !question.shouldDisplay || question.shouldDisplay(response);
|
|
21
22
|
|
|
22
23
|
if (shouldSkip || !shouldDisplay) {
|
|
23
24
|
continue;
|
|
@@ -7,6 +7,7 @@ import { Journey } from '../journey/journey.js';
|
|
|
7
7
|
import { Section } from '../section.js';
|
|
8
8
|
import { COMPONENT_TYPES } from '../components/utils/component-types.js';
|
|
9
9
|
import { questionHasAnswer } from '../components/utils/question-has-answer.js';
|
|
10
|
+
import { DynamicSection } from '#src/dynamic-section.js';
|
|
10
11
|
|
|
11
12
|
describe('redirectToUnansweredQuestion Middleware', () => {
|
|
12
13
|
const questions = {
|
|
@@ -145,4 +146,35 @@ describe('redirectToUnansweredQuestion Middleware', () => {
|
|
|
145
146
|
assert.deepStrictEqual(res.redirect.mock.calls[0].arguments, ['base/url/task-list/page']);
|
|
146
147
|
assert.strictEqual(next.mock.callCount(), 0);
|
|
147
148
|
});
|
|
149
|
+
|
|
150
|
+
it('should support dynamic sections', () => {
|
|
151
|
+
const journeyResponse = new JourneyResponse(
|
|
152
|
+
'id-1',
|
|
153
|
+
'0000003',
|
|
154
|
+
{
|
|
155
|
+
questionOne: true,
|
|
156
|
+
questionTwo: false,
|
|
157
|
+
items: [
|
|
158
|
+
{ id: 'item-1', questionThree: true, questionFour: true },
|
|
159
|
+
{ id: 'item-2', questionThree: true }
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
'Q9999'
|
|
163
|
+
);
|
|
164
|
+
res.locals.journeyResponse = journeyResponse;
|
|
165
|
+
const sections = [
|
|
166
|
+
new Section('S1', 's1').addQuestion(questions.q1).addQuestion(questions.q2),
|
|
167
|
+
new DynamicSection('S2', 'item-1', 'items').addQuestion(questions.q3).addQuestion(questions.q4),
|
|
168
|
+
new DynamicSection('S3', 'item-2', 'items').addQuestion(questions.q3).addQuestion(questions.q4)
|
|
169
|
+
];
|
|
170
|
+
const journey = new Journey({ response: journeyResponse, ...params, sections });
|
|
171
|
+
res.locals.journey = journey;
|
|
172
|
+
|
|
173
|
+
redirectToUnansweredQuestion([])(req, res, next);
|
|
174
|
+
|
|
175
|
+
assert.strictEqual(res.redirect.mock.callCount(), 1);
|
|
176
|
+
// all questions answered apart from the last dynamic section question
|
|
177
|
+
assert.deepStrictEqual(res.redirect.mock.calls[0].arguments, ['base/url/item-2/question-4']);
|
|
178
|
+
assert.strictEqual(next.mock.callCount(), 0);
|
|
179
|
+
});
|
|
148
180
|
});
|
|
@@ -147,7 +147,7 @@ export class OptionsQuestion extends Question {
|
|
|
147
147
|
/**
|
|
148
148
|
* Get the data to save from the request, returns an object of answers
|
|
149
149
|
* @param {import('express').Request} req
|
|
150
|
-
* @param {import('../journey/journey-response.js').JourneyResponse} journeyResponse - current journey response
|
|
150
|
+
* @param {import('../journey/journey-response.js').JourneyResponse} journeyResponse - current journey response
|
|
151
151
|
* @returns {Promise<{ answers: Record<string, unknown> }>}
|
|
152
152
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
153
153
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -127,7 +127,7 @@ export class Question {
|
|
|
127
127
|
* @param {import('../journey/journey.js').Journey} journey - the journey we are in
|
|
128
128
|
* @param {Record<string, unknown>} [customViewData] additional data to send to view
|
|
129
129
|
* @param {unknown} [payload]
|
|
130
|
-
* @param {import('#typedefs/question-types.d.ts').PrepQuestionForRenderingOptions} [options] - required to support manage list question
|
|
130
|
+
* @param {import('#typedefs/question-types.d.ts').PrepQuestionForRenderingOptions} [options] - required to support manage list question and dynamic sections
|
|
131
131
|
* @returns {import('#typedefs/question-types.d.ts').QuestionViewModel}
|
|
132
132
|
*/
|
|
133
133
|
prepQuestionForRendering(section: import("../section.js").Section, journey: import("../journey/journey.js").Journey, customViewData?: Record<string, unknown>, payload?: unknown, options?: import("#typedefs/question-types.d.ts").PrepQuestionForRenderingOptions): import("#typedefs/question-types.d.ts").QuestionViewModel;
|
|
@@ -148,13 +148,13 @@ export class Question {
|
|
|
148
148
|
* @param {import('#typedefs/question-types.d.ts').QuestionViewModel} viewModel
|
|
149
149
|
*/ addCustomDataToViewModel(viewModel: import("#typedefs/question-types.d.ts").QuestionViewModel): void;
|
|
150
150
|
/**
|
|
151
|
-
* Get the answers object from the journey response, which may be nested in an array for manage list questions
|
|
151
|
+
* Get the answers object from the journey response, which may be nested in an array for manage list questions or dynamic sections
|
|
152
152
|
*
|
|
153
153
|
* @param {import('../journey/journey-response.js').JourneyResponse} response
|
|
154
154
|
* @param {import('#typedefs/question-types.d.ts').PrepQuestionForRenderingOptions} [options]
|
|
155
155
|
* @returns {Record<string, any>}
|
|
156
156
|
*/
|
|
157
|
-
answerObjectFromJourneyResponse(response: import("../journey/journey-response.js").JourneyResponse, { params, manageListQuestion }?: import("#typedefs/question-types.d.ts").PrepQuestionForRenderingOptions): Record<string, any>;
|
|
157
|
+
answerObjectFromJourneyResponse(response: import("../journey/journey-response.js").JourneyResponse, { params, manageListQuestion, dynamicSection }?: import("#typedefs/question-types.d.ts").PrepQuestionForRenderingOptions): Record<string, any>;
|
|
158
158
|
/**
|
|
159
159
|
* renders the question
|
|
160
160
|
* @param {import('express').Response} res - the express response
|
|
@@ -200,6 +200,11 @@ export class Question {
|
|
|
200
200
|
handleNextQuestion(res: import("express").Response, journey: import("../journey/journey.js").Journey, sectionSegment: string, questionSegment: string): void;
|
|
201
201
|
/**
|
|
202
202
|
* returns the formatted answers values to be used to build task list elements
|
|
203
|
+
*
|
|
204
|
+
* If overriding this method and access answers on the journey, use journey.responseForSection
|
|
205
|
+
* to get the answers, instead of `journey.response` directly. This is to support DynamicSections
|
|
206
|
+
* where answers are in an array. See `MultiFieldInputQuestion` for an example.
|
|
207
|
+
*
|
|
203
208
|
* @param {string} sectionSegment
|
|
204
209
|
* @param {import('../journey/journey.js').Journey} journey
|
|
205
210
|
* @param {unknown} answer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH;IAiEC;;;OAGG;IACH,+NAHW,OAAO,+BAA+B,EAAE,kBAAkB,oBAC1D,MAAM,CAAC,MAAM,WAAW,EA0DlC;IA5HD,6EAA6E;IAC7E,WADW,MAAM,CACP;IACV,sDAAsD;IACtD,OADW,MAAM,CACX;IACN,+DAA+D;IAC/D,UADW,MAAM,CACR;IACT,mFAAmF;IACnF,aADW,MAAM,GAAC,SAAS,CACf;IACZ,iDAAiD;IACjD,YADW,MAAM,CACN;IACX,qHAAqH;IACrH,WADW,MAAM,CACP;IACV,6FAA6F;IAC7F,UADW,OAAO,CACF;IAChB,0IAA0I;IAC1I,YADW,KAAK,CAAE,OAAO,gCAAgC,EAAE,aAAa,CAAC,CACzD;IAChB,2DAA2D;IAC3D,MADW,MAAM,GAAC,SAAS,CACtB;IACL,sEAAsE;IACtE,oBADW,OAAO,CACQ;IAC1B,oDAAoD;IACpD,KADW,MAAM,GAAC,SAAS,CACvB;IACJ,qDAAqD;IACrD,MADW,MAAM,GAAC,SAAS,CACtB;IACL,sDAAsD;IACtD,eADW,MAAM,GAAC,SAAS,CACb;IACd,gGAAgG;IAChG,YADW,OAAO,+BAA+B,EAAE,UAAU,GAAC,SAAS,CAC5D;IAEX,iFAAiF;IACjF,gBADW,MAAM,CACc;IAC/B,sFAAsF;IACtF,kBADW,OAAO,CACM;IACxB,4CAA4C;IAC5C,oBADW,MAAM,CACe;IAChC,uDAAuD;IACvD,kBADW,MAAM,CACW;IAC5B,uDAAuD;IACvD,kBADW,MAAM,CACW;IAC5B,oDAAoD;IACpD,eADW,MAAM,CACK;IACtB,0IAA0I;IAC1I,oBADW,OAAO,+BAA+B,EAAE,qBAAqB,GAAC,SAAS,CAC/D;IAEnB;;;OAGG;IAEH,gBAAiB,WAJN,OAAO,gCAAgC,EAAE,eAI3B,KAHZ,OAAO,CAGe;IAEnC;;;MAGE;IACF;;;;;;OAMG;IACH,wBAFU,OAAO,CAEc;IA2C9B,iCAAgC;IAChC,kBAAwB;IAExB;;;;MAAwB;IAkBzB;;;;;;OAMG;IACH,4BAFa,OAAO,CAInB;IAWD,iCANa,OAAO,EAWnB;IAdD;;;;OAIG;IACH,6BAFa,OAAO,CAInB;IAqBD;;;;;;OAMG;IACH,sBAFa,MAAM,EAAE,CAIpB;IAED;;;;;;;;;;;;;;OAcG;IACH,uFARG;QAAoE,MAAM,EAAlE,OAAO,8BAA8B,EAAE,WAAW;QAC2B,kBAAkB;QACtD,OAAO,EAAhD,OAAO,eAAe,EAAE,OAAO;QACkB,OAAO,EAAxD,OAAO,uBAAuB,EAAE,OAAO;QACL,cAAc;QAC9B,OAAO,GAAzB,OAAO;KACf,GAAU,OAAO,+BAA+B,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"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"}
|