-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBasic.js
204 lines (190 loc) · 5.4 KB
/
Basic.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//
// Basic.js
// RNSurvey
//
// Created by Rogier van der Sluijs on 23/03/2019.
// Copyright © 2019 Rogier van der Sluijs. All rights reserved.
//
// React
import React from 'react';
import { ScrollView, Text, View } from 'react-native';
// Third-party
import PropTypes from 'prop-types';
import * as Animatable from 'react-native-animatable';
// Components
import Slider from '../../IO/Slider/Slider';
import Numeric from '../../IO/Numeric/Numeric';
import List from '../../IO/Lists/Basic/Basic';
// Layout
import styles from './styles';
/**
* Render a Slider component. This corresponds to TYPE 1.
* @param {number} minValue Minimally allowed value.
* @param {Number} value Starting value.
* @param {number} maxValue Maximally allowed value.
* @param {Function} cb Callback on slideEnd.
*/
function renderSlider(
minValue,
value,
maxValue,
cb,
) {
return (
<Slider
minValue={minValue}
value={value}
maxValue={maxValue}
onSlideComplete={cb}
/>
);
}
// Type: 3,4 or 9 (Questions that render a list - single, and multiple choice)
function renderList(
questionId,
options,
cb,
selected,
single,
) {
// List expects an array for selected, but single option questions supply a
// default_option that is an integer, so we need to convert it.
const s = Array.isArray(selected) ? selected : [selected];
return (
<List
questionId={questionId}
options={options}
toggleAnswer={cb}
selected={s}
single={single}
/>
);
}
/**
* Render a Numeric Input component. This corresponds to TYPE 5.
* @param {bool} obligatory Is the question obligatory or not.
* @param {number} minValue Minimally allowed value.
* @param {Number} value Default value.
* @param {Number} maxValue Maximally allowed value.
* @param {number} placeholder Placeholder.
* @param {Function} cb Callback onEndEditing.
*/
function renderNumericInput(
obligatory,
minValue,
value,
maxValue,
placeholder,
cb,
) {
return (
<Numeric
obligatory={obligatory}
minValue={minValue}
value={value}
maxValue={maxValue}
placeholder={placeholder}
setAnswer={cb}
/>
);
}
/**
* BasicQuestion layouts a basic question consisting of a description and an
* "answer" area.
* @param {number} questionIndex The current question index.
* @param {Object} questionnaire The current questionnaire.
* @param {Object} answers Answers from the store.
* @param {Object} actions Actions to interact with Redux.
*/
const BasicQuestion = ({
questionIndex,
questionnaire,
answers,
actions,
}) => {
// Retrieve the question and its answers
const q = questionnaire.questions[questionIndex];
const a = answers.filter(answer => answer.questionId === q.question_id);
// Retrieve question information, needed in the upper part of the layout
const {
description,
type,
question_id: questionId,
obligatory,
} = q;
return (
<View style={styles.container}>
<View>
<ScrollView
contentContainerStyle={styles.description}
alwaysBounceVertical={false}
>
<Animatable.Text animation="slideInLeft" duration={350} style={styles.text}>
{description}
</Animatable.Text>
</ScrollView>
</View>
<Animatable.View animation="slideInRight" duration={350} style={styles.io}>
{[1].includes(type) && renderSlider(
q.min_value, // minValue
a[0] ? a[0].value : q.default_value, // value
q.max_value, // maxValue
val => actions.setAnswer(questionId, val), // cb
)}
{[3, 9].includes(type) && renderList(
questionId,
q.options,
// If single choice, toggle click
(qid, val) => {
actions.clearQuestion(qid);
actions.toggleAnswer(qid, val);
},
a.map(i => i.value), // supply array with selected answers
true, // single choice question
)}
{[4].includes(type) && renderList(
questionId,
q.options,
actions.toggleAnswer,
a.map(i => i.value), // supply array with selected answers
)}
{[5].includes(type) && renderNumericInput(
obligatory, // obligatory
q.min_value, // minValue
a[0] ? a[0].value : q.default_value, // value
q.max_value, // maxValue
q.placeholder, // placeholder
val => actions.setAnswer(questionId, val), // cb
)}
</Animatable.View>
</View>
);
};
// Props
BasicQuestion.propTypes = {
questionIndex: PropTypes.number.isRequired,
questionnaire: PropTypes.shape({
questionnaire_id: PropTypes.number.isRequired,
questions: PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
obligatory: PropTypes.bool.isRequired,
}),
).isRequired,
}).isRequired,
answers: PropTypes.arrayOf(
PropTypes.shape({
questionId: PropTypes.number.isRequired,
value: PropTypes.number,
timestamp: PropTypes.string.isRequired,
}),
).isRequired,
actions: PropTypes.shape({
setAnswer: PropTypes.func.isRequired,
toggleAnswer: PropTypes.func.isRequired,
clearQuestion: PropTypes.func.isRequired,
}).isRequired,
};
export default BasicQuestion;