@originallyus/feedback-rn-sdk 4.0.0-beta.6 → 4.0.0-beta.7
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.
Potentially problematic release.
This version of @originallyus/feedback-rn-sdk might be problematic. Click here for more details.
- package/package.json +2 -3
- package/src/AIAContentUsefulness.tsx +0 -296
- package/src/AIAFeedback.tsx +0 -354
- package/src/AIAFeedbackForm.tsx +0 -267
- package/src/AIAFeedbackSplash.tsx +0 -49
- package/src/AIAFeedbackStyles.ts +0 -311
- package/src/AIAFeedbackSuccess.tsx +0 -67
- package/src/assets/CheckIcon.tsx +0 -18
- package/src/assets/CloseIcon.tsx +0 -18
- package/src/assets/ErrorIcon.tsx +0 -18
- package/src/assets/PlusIcon.tsx +0 -18
- package/src/assets/StarIcon.tsx +0 -18
- package/src/component/Button.tsx +0 -68
- package/src/component/ButtonSubmit.tsx +0 -335
- package/src/component/Input.tsx +0 -288
- package/src/component/MultiSelectButtons.tsx +0 -272
- package/src/component/README.md +0 -215
- package/src/component/READMEVI.md +0 -192
- package/src/component/Rating.tsx +0 -248
- package/src/component/RatingNumber.tsx +0 -421
- package/src/component/Textarea.tsx +0 -282
- package/src/component/YesNoButtons.tsx +0 -236
- package/src/index.tsx +0 -33
- package/src/service/feedbackService.ts +0 -108
- package/src/utils/common.ts +0 -241
- package/src/utils/constants.ts +0 -60
- package/src/utils/index.ts +0 -167
- package/src/utils/networking.ts +0 -134
package/src/component/Rating.tsx
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import {memo, useMemo, useRef} from 'react'
|
|
2
|
-
import {View, Text, StyleSheet, TouchableOpacity, Animated, type TextStyle, type ViewStyle} from 'react-native'
|
|
3
|
-
import * as Haptics from 'expo-haptics'
|
|
4
|
-
import * as f from '@utils/common'
|
|
5
|
-
import {COLOR_STAR_NORMAL, COLOR_STAR_SELECTED, ERROR_COLOR, TEXT_DARK} from '@utils/constants'
|
|
6
|
-
import StarIcon from '@/assets/StarIcon'
|
|
7
|
-
import ErrorIcon from '@/assets/ErrorIcon'
|
|
8
|
-
|
|
9
|
-
let pressRatingTimestamp: number | null = null
|
|
10
|
-
|
|
11
|
-
interface ButtonStarProps {
|
|
12
|
-
disabled: boolean
|
|
13
|
-
onRate: () => void
|
|
14
|
-
active?: boolean
|
|
15
|
-
normalStarColor: string
|
|
16
|
-
selectedStarColor: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Props for the star rating component.
|
|
21
|
-
*
|
|
22
|
-
* Renders a title, question and a row of tappable stars with optional error text.
|
|
23
|
-
*/
|
|
24
|
-
export interface RatingProps {
|
|
25
|
-
/**
|
|
26
|
-
* Main title shown above the question.
|
|
27
|
-
*
|
|
28
|
-
* @default 'Help us get better'
|
|
29
|
-
*/
|
|
30
|
-
title?: string
|
|
31
|
-
/**
|
|
32
|
-
* Question or subtitle shown above the stars.
|
|
33
|
-
*
|
|
34
|
-
* @default 'How was your experience today?'
|
|
35
|
-
*/
|
|
36
|
-
question?: string
|
|
37
|
-
/**
|
|
38
|
-
* Current star value (1..`rating_max`).
|
|
39
|
-
*/
|
|
40
|
-
value: number
|
|
41
|
-
/**
|
|
42
|
-
* Called when a star is selected.
|
|
43
|
-
*
|
|
44
|
-
* @param rating Selected value.
|
|
45
|
-
*/
|
|
46
|
-
onRate: (rating: number) => void
|
|
47
|
-
/**
|
|
48
|
-
* Minimum star value.
|
|
49
|
-
*
|
|
50
|
-
* @default 1
|
|
51
|
-
*/
|
|
52
|
-
rating_min?: number
|
|
53
|
-
/**
|
|
54
|
-
* Maximum star value.
|
|
55
|
-
*
|
|
56
|
-
* @default 5
|
|
57
|
-
*/
|
|
58
|
-
rating_max?: number
|
|
59
|
-
/**
|
|
60
|
-
* When true, disables all star presses.
|
|
61
|
-
*
|
|
62
|
-
* @default false
|
|
63
|
-
*/
|
|
64
|
-
disabled?: boolean
|
|
65
|
-
/**
|
|
66
|
-
* Error message; when present, shown below the stars.
|
|
67
|
-
*/
|
|
68
|
-
error?: string
|
|
69
|
-
/**
|
|
70
|
-
* Color for unselected stars.
|
|
71
|
-
*
|
|
72
|
-
* @default '#D0D0D0'
|
|
73
|
-
*/
|
|
74
|
-
normalStarColor?: string
|
|
75
|
-
/**
|
|
76
|
-
* Color for selected stars.
|
|
77
|
-
*
|
|
78
|
-
* @default '#F7C926'
|
|
79
|
-
*/
|
|
80
|
-
selectedStarColor?: string
|
|
81
|
-
/**
|
|
82
|
-
* Style for the title text.
|
|
83
|
-
*/
|
|
84
|
-
titleStyle?: TextStyle
|
|
85
|
-
/**
|
|
86
|
-
* Style for the question text.
|
|
87
|
-
*/
|
|
88
|
-
questionStyle?: TextStyle
|
|
89
|
-
/**
|
|
90
|
-
* Style for the error text.
|
|
91
|
-
*/
|
|
92
|
-
errorStyle?: TextStyle
|
|
93
|
-
/**
|
|
94
|
-
* Style for the outer wrapper.
|
|
95
|
-
*/
|
|
96
|
-
style?: ViewStyle
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const ButtonStar = memo((props: ButtonStarProps) => {
|
|
100
|
-
const {disabled, onRate, active = false, normalStarColor, selectedStarColor} = props
|
|
101
|
-
|
|
102
|
-
const springAnimated = useRef(new Animated.Value(0)).current
|
|
103
|
-
|
|
104
|
-
const onPressStar = () => {
|
|
105
|
-
const nowTimestamp = Date.now()
|
|
106
|
-
if (pressRatingTimestamp && nowTimestamp - pressRatingTimestamp < 200) {
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
pressRatingTimestamp = nowTimestamp
|
|
110
|
-
|
|
111
|
-
Animated.sequence([
|
|
112
|
-
Animated.timing(springAnimated, {
|
|
113
|
-
toValue: 1,
|
|
114
|
-
duration: 80,
|
|
115
|
-
useNativeDriver: true,
|
|
116
|
-
}),
|
|
117
|
-
Animated.timing(springAnimated, {
|
|
118
|
-
toValue: 0,
|
|
119
|
-
duration: 80,
|
|
120
|
-
useNativeDriver: true,
|
|
121
|
-
}),
|
|
122
|
-
]).start()
|
|
123
|
-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)
|
|
124
|
-
onRate()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const scaleStar = useMemo(
|
|
128
|
-
() =>
|
|
129
|
-
springAnimated.interpolate({
|
|
130
|
-
inputRange: [0, 1],
|
|
131
|
-
outputRange: [1, 1.5],
|
|
132
|
-
}),
|
|
133
|
-
[springAnimated],
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
const starColor = active ? selectedStarColor : normalStarColor
|
|
137
|
-
const size = f.isTablet ? 42 : 34
|
|
138
|
-
const marginH = f.isTablet ? 12 : 8
|
|
139
|
-
|
|
140
|
-
const starWrapStyle = useMemo(
|
|
141
|
-
() => [
|
|
142
|
-
styles.starWrap,
|
|
143
|
-
{
|
|
144
|
-
transform: [{scale: scaleStar}],
|
|
145
|
-
marginHorizontal: marginH,
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
[scaleStar, marginH],
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<Animated.View style={starWrapStyle}>
|
|
153
|
-
<TouchableOpacity disabled={disabled} onPress={onPressStar} activeOpacity={0.8}>
|
|
154
|
-
<StarIcon size={size} color={starColor} />
|
|
155
|
-
</TouchableOpacity>
|
|
156
|
-
</Animated.View>
|
|
157
|
-
)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
function Rating({
|
|
161
|
-
title = 'Help us get better',
|
|
162
|
-
question = 'How was your experience today?',
|
|
163
|
-
value,
|
|
164
|
-
onRate,
|
|
165
|
-
rating_min = 1,
|
|
166
|
-
rating_max = 5,
|
|
167
|
-
disabled = false,
|
|
168
|
-
error,
|
|
169
|
-
normalStarColor = COLOR_STAR_NORMAL,
|
|
170
|
-
selectedStarColor = COLOR_STAR_SELECTED,
|
|
171
|
-
titleStyle,
|
|
172
|
-
questionStyle,
|
|
173
|
-
errorStyle,
|
|
174
|
-
style,
|
|
175
|
-
}: RatingProps) {
|
|
176
|
-
const hasError = useMemo(() => error != null && error !== '', [error])
|
|
177
|
-
|
|
178
|
-
const stars = useMemo(() => {
|
|
179
|
-
const listStar = []
|
|
180
|
-
for (let i = rating_min; i <= rating_max; i++) {
|
|
181
|
-
listStar.push(
|
|
182
|
-
<ButtonStar
|
|
183
|
-
key={`ButtonStar-${i}`}
|
|
184
|
-
normalStarColor={normalStarColor}
|
|
185
|
-
selectedStarColor={selectedStarColor}
|
|
186
|
-
disabled={disabled || value === i}
|
|
187
|
-
onRate={() => onRate(i)}
|
|
188
|
-
active={i <= value}
|
|
189
|
-
/>,
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
return listStar
|
|
193
|
-
}, [rating_min, rating_max, disabled, value, normalStarColor, selectedStarColor, onRate])
|
|
194
|
-
|
|
195
|
-
const titleCombinedStyle = useMemo(() => [styles.title, {color: TEXT_DARK}, titleStyle], [titleStyle])
|
|
196
|
-
const questionCombinedStyle = useMemo(() => [styles.question, {color: TEXT_DARK}, questionStyle], [questionStyle])
|
|
197
|
-
const errorTextStyle = useMemo(() => [styles.error, {color: ERROR_COLOR}, errorStyle], [errorStyle])
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<View style={[styles.wrapper, style]}>
|
|
201
|
-
{title != null && title !== '' && <Text style={titleCombinedStyle}>{title}</Text>}
|
|
202
|
-
{question != null && question !== '' && <Text style={questionCombinedStyle}>{question}</Text>}
|
|
203
|
-
<View style={styles.starsWrap}>{stars}</View>
|
|
204
|
-
{hasError && (
|
|
205
|
-
<View style={styles.errorWrap}>
|
|
206
|
-
<ErrorIcon size={20} color={ERROR_COLOR} />
|
|
207
|
-
<Text style={errorTextStyle}>{error}</Text>
|
|
208
|
-
</View>
|
|
209
|
-
)}
|
|
210
|
-
</View>
|
|
211
|
-
)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export default Rating
|
|
215
|
-
|
|
216
|
-
const styles = StyleSheet.create({
|
|
217
|
-
wrapper: {
|
|
218
|
-
width: '100%',
|
|
219
|
-
},
|
|
220
|
-
title: {
|
|
221
|
-
fontSize: 18,
|
|
222
|
-
fontWeight: '700',
|
|
223
|
-
marginBottom: 8,
|
|
224
|
-
},
|
|
225
|
-
question: {
|
|
226
|
-
fontSize: 16,
|
|
227
|
-
marginBottom: 16,
|
|
228
|
-
},
|
|
229
|
-
starsWrap: {
|
|
230
|
-
flexDirection: 'row',
|
|
231
|
-
justifyContent: 'center',
|
|
232
|
-
alignItems: 'center',
|
|
233
|
-
width: '100%',
|
|
234
|
-
},
|
|
235
|
-
errorWrap: {
|
|
236
|
-
flexDirection: 'row',
|
|
237
|
-
alignItems: 'center',
|
|
238
|
-
marginTop: 8,
|
|
239
|
-
gap: 6,
|
|
240
|
-
},
|
|
241
|
-
error: {
|
|
242
|
-
fontSize: 14,
|
|
243
|
-
lineHeight: 20,
|
|
244
|
-
flex: 1,
|
|
245
|
-
fontWeight: '400',
|
|
246
|
-
},
|
|
247
|
-
starWrap: {},
|
|
248
|
-
})
|
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
import ErrorIcon from '@/assets/ErrorIcon'
|
|
2
|
-
import * as f from '@utils/common'
|
|
3
|
-
import * as Haptics from 'expo-haptics'
|
|
4
|
-
import {BG_DEFAULT, BG_SELECTED, BORDER_DEFAULT, BORDER_SELECTED, ERROR_COLOR, TEXT_DARK} from '@utils/constants'
|
|
5
|
-
import {useEffect, useMemo, useRef} from 'react'
|
|
6
|
-
import {Animated, StyleSheet, Text, TouchableOpacity, View, type TextStyle} from 'react-native'
|
|
7
|
-
|
|
8
|
-
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity)
|
|
9
|
-
|
|
10
|
-
const DEFAULT_SELECTED_COLOR = BG_SELECTED
|
|
11
|
-
const DEFAULT_SELECTED_BORDER_COLOR = BORDER_SELECTED
|
|
12
|
-
|
|
13
|
-
const DEFAULT_ERROR_COLOR = ERROR_COLOR
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Preset sizes for `RatingNumber` buttons.
|
|
17
|
-
*
|
|
18
|
-
* - `'small'` – compact height, small radius.
|
|
19
|
-
* - `'medium'` – default size.
|
|
20
|
-
* - `'large'` – larger height and radius.
|
|
21
|
-
*/
|
|
22
|
-
export type RatingNumberSize = 'small' | 'medium' | 'large'
|
|
23
|
-
|
|
24
|
-
const SIZE_PRESETS: Record<RatingNumberSize, {height: number; borderRadius: number; borderWidth: number; gap: number}> =
|
|
25
|
-
{
|
|
26
|
-
small: {height: 44, borderRadius: 6, borderWidth: 1, gap: 3},
|
|
27
|
-
medium: {height: 48, borderRadius: 8, borderWidth: 1, gap: 4},
|
|
28
|
-
large: {height: 60, borderRadius: 10, borderWidth: 1, gap: 5},
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Props for the numeric rating scale component.
|
|
33
|
-
*
|
|
34
|
-
* Renders a row of numbered buttons from `rating_min` to `rating_max`
|
|
35
|
-
* with optional left/right scale labels and error text.
|
|
36
|
-
*/
|
|
37
|
-
export interface RatingNumberProps {
|
|
38
|
-
/**
|
|
39
|
-
* Text color for the left and right scale labels.
|
|
40
|
-
*/
|
|
41
|
-
scale_label_color: string
|
|
42
|
-
/**
|
|
43
|
-
* Optional text for the left label (e.g. "Strongly disagree").
|
|
44
|
-
*
|
|
45
|
-
* @default 'Strongly disagree'
|
|
46
|
-
*/
|
|
47
|
-
scale_label_left?: string
|
|
48
|
-
/**
|
|
49
|
-
* Optional text for the right label (e.g. "Strongly agree").
|
|
50
|
-
*
|
|
51
|
-
* @default 'Strongly agree'
|
|
52
|
-
*/
|
|
53
|
-
scale_label_right?: string
|
|
54
|
-
/**
|
|
55
|
-
* Font family for the scale labels.
|
|
56
|
-
*/
|
|
57
|
-
scale_label_font?: string
|
|
58
|
-
/**
|
|
59
|
-
* Font size for the scale labels.
|
|
60
|
-
*/
|
|
61
|
-
scale_label_fontsize?: number
|
|
62
|
-
/**
|
|
63
|
-
* Called when a number is pressed.
|
|
64
|
-
*
|
|
65
|
-
* @param rating Selected value.
|
|
66
|
-
*/
|
|
67
|
-
handlePressRating: (rating: number) => void
|
|
68
|
-
/**
|
|
69
|
-
* Currently selected value.
|
|
70
|
-
*/
|
|
71
|
-
numStar: number
|
|
72
|
-
/**
|
|
73
|
-
* Minimum value of the scale (inclusive).
|
|
74
|
-
*/
|
|
75
|
-
rating_min: number
|
|
76
|
-
/**
|
|
77
|
-
* Maximum value of the scale (inclusive).
|
|
78
|
-
*/
|
|
79
|
-
rating_max: number
|
|
80
|
-
/**
|
|
81
|
-
* App width, used for layout spacing.
|
|
82
|
-
*/
|
|
83
|
-
appWidth: number
|
|
84
|
-
/**
|
|
85
|
-
* Preset for height, radius and gap between numbers.
|
|
86
|
-
*
|
|
87
|
-
* @default 'medium'
|
|
88
|
-
*/
|
|
89
|
-
size?: RatingNumberSize
|
|
90
|
-
/**
|
|
91
|
-
* When true, all numbers from min up to and including the selected value are shown as active.
|
|
92
|
-
* E.g. selecting 6 highlights 0–6. When false, only the selected number is active.
|
|
93
|
-
*
|
|
94
|
-
* @default true
|
|
95
|
-
*/
|
|
96
|
-
activeRange?: boolean
|
|
97
|
-
/**
|
|
98
|
-
* Whether to remove gaps between buttons (segmented control style).
|
|
99
|
-
*
|
|
100
|
-
* @default true
|
|
101
|
-
*/
|
|
102
|
-
compact?: boolean
|
|
103
|
-
/**
|
|
104
|
-
* Error message shown below the component.
|
|
105
|
-
*/
|
|
106
|
-
error?: string
|
|
107
|
-
/**
|
|
108
|
-
* Border color when an error is present.
|
|
109
|
-
*
|
|
110
|
-
* @default '#D40C74'
|
|
111
|
-
*/
|
|
112
|
-
errorBorderColor?: string
|
|
113
|
-
/**
|
|
114
|
-
* Font family for the number labels.
|
|
115
|
-
*/
|
|
116
|
-
rating_number_font?: string
|
|
117
|
-
/**
|
|
118
|
-
* Font size for the number labels.
|
|
119
|
-
*/
|
|
120
|
-
rating_number_fontsize?: number
|
|
121
|
-
/**
|
|
122
|
-
* Background color when a number is not selected.
|
|
123
|
-
*/
|
|
124
|
-
rating_number_bg_color?: string
|
|
125
|
-
/**
|
|
126
|
-
* Border color when a number is not selected.
|
|
127
|
-
*/
|
|
128
|
-
rating_number_border_color?: string
|
|
129
|
-
/**
|
|
130
|
-
* Background color when a number is selected.
|
|
131
|
-
*/
|
|
132
|
-
rating_number_selected_bg_color?: string
|
|
133
|
-
/**
|
|
134
|
-
* Border color when a number is selected.
|
|
135
|
-
*/
|
|
136
|
-
rating_number_selected_border_color?: string
|
|
137
|
-
/**
|
|
138
|
-
* Text color when a number is selected.
|
|
139
|
-
*/
|
|
140
|
-
rating_number_selected_text_color?: string
|
|
141
|
-
/**
|
|
142
|
-
* Text color when a number is not selected.
|
|
143
|
-
*/
|
|
144
|
-
rating_number_text_color?: string
|
|
145
|
-
/**
|
|
146
|
-
* Style override for the error text.
|
|
147
|
-
*/
|
|
148
|
-
errorStyle?: TextStyle
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Label for the component.
|
|
152
|
-
*/
|
|
153
|
-
label?: string
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
interface ButtonNumberProps extends RatingNumberProps {
|
|
157
|
-
handlePressRating: () => void
|
|
158
|
-
number: number
|
|
159
|
-
active: boolean
|
|
160
|
-
isStart: boolean
|
|
161
|
-
isEnd: boolean
|
|
162
|
-
/** Last button in the active range (needs right border in compact mode). */
|
|
163
|
-
isLastActive?: boolean
|
|
164
|
-
/** First inactive button after active block (hide left border to avoid double line). */
|
|
165
|
-
isFirstInactive?: boolean
|
|
166
|
-
hasError?: boolean
|
|
167
|
-
errorBorderColor?: string
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function RatingNumber(props: RatingNumberProps) {
|
|
171
|
-
const {
|
|
172
|
-
scale_label_color,
|
|
173
|
-
scale_label_left,
|
|
174
|
-
scale_label_right,
|
|
175
|
-
scale_label_font,
|
|
176
|
-
scale_label_fontsize,
|
|
177
|
-
handlePressRating,
|
|
178
|
-
numStar,
|
|
179
|
-
rating_min,
|
|
180
|
-
rating_max,
|
|
181
|
-
appWidth,
|
|
182
|
-
label,
|
|
183
|
-
} = props
|
|
184
|
-
|
|
185
|
-
const activeRange = props.activeRange !== false
|
|
186
|
-
const compact = props.compact !== false
|
|
187
|
-
const sizePreset = props.size ?? 'medium'
|
|
188
|
-
const preset = useMemo(() => SIZE_PRESETS[sizePreset], [sizePreset])
|
|
189
|
-
const gap = useMemo(() => (compact ? 0 : preset.gap), [compact, preset])
|
|
190
|
-
const hasError = useMemo(() => props.error != null && props.error !== '', [props.error])
|
|
191
|
-
const errorBorderColor = useMemo(() => props.errorBorderColor ?? DEFAULT_ERROR_COLOR, [props.errorBorderColor])
|
|
192
|
-
|
|
193
|
-
const renderRating = () => {
|
|
194
|
-
const listStar = []
|
|
195
|
-
for (let i = rating_min; i <= rating_max; i++) {
|
|
196
|
-
const active = activeRange ? i <= numStar : numStar === i
|
|
197
|
-
const nextActive = activeRange && i < rating_max && i + 1 <= numStar
|
|
198
|
-
const prevActive = activeRange && i > rating_min && i - 1 <= numStar
|
|
199
|
-
listStar.push(
|
|
200
|
-
<ButtonNumber
|
|
201
|
-
key={`rating-number-${i}`}
|
|
202
|
-
{...props}
|
|
203
|
-
hasError={hasError}
|
|
204
|
-
errorBorderColor={errorBorderColor}
|
|
205
|
-
handlePressRating={() => {
|
|
206
|
-
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)
|
|
207
|
-
handlePressRating(i)
|
|
208
|
-
}}
|
|
209
|
-
number={i}
|
|
210
|
-
active={active}
|
|
211
|
-
isStart={i === rating_min}
|
|
212
|
-
isEnd={i === rating_max}
|
|
213
|
-
isLastActive={active && !nextActive}
|
|
214
|
-
isFirstInactive={!active && prevActive}
|
|
215
|
-
/>,
|
|
216
|
-
)
|
|
217
|
-
}
|
|
218
|
-
return listStar
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const rowStyle = useMemo(() => ({width: '100%' as const}), [])
|
|
222
|
-
|
|
223
|
-
const containerStyle = useMemo(
|
|
224
|
-
() => [styles.ratingContainer, !compact && {gap}, rowStyle],
|
|
225
|
-
[compact, gap, rowStyle],
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
const labelContainerStyle = useMemo(
|
|
229
|
-
() => [styles.ratingLabelContainer, rowStyle, {marginTop: f.w_p(appWidth, 12)}],
|
|
230
|
-
[rowStyle, appWidth],
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
const leftLabelStyle = useMemo(
|
|
234
|
-
() => ({
|
|
235
|
-
color: scale_label_color,
|
|
236
|
-
fontSize: scale_label_fontsize,
|
|
237
|
-
fontFamily: scale_label_font,
|
|
238
|
-
}),
|
|
239
|
-
[scale_label_color, scale_label_fontsize, scale_label_font],
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
const rightLabelStyle = useMemo(
|
|
243
|
-
() => ({
|
|
244
|
-
color: scale_label_color,
|
|
245
|
-
fontSize: scale_label_fontsize,
|
|
246
|
-
fontFamily: scale_label_font,
|
|
247
|
-
}),
|
|
248
|
-
[scale_label_color, scale_label_fontsize, scale_label_font],
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
const errorTextStyle = useMemo(
|
|
252
|
-
() => [styles.error, {color: errorBorderColor}, props.errorStyle],
|
|
253
|
-
[errorBorderColor, props.errorStyle],
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
return (
|
|
257
|
-
<View style={styles.wrapper}>
|
|
258
|
-
<Text style={styles.question}>{label}</Text>
|
|
259
|
-
<View style={containerStyle}>{renderRating()}</View>
|
|
260
|
-
<View style={labelContainerStyle}>
|
|
261
|
-
<Text style={leftLabelStyle}>{scale_label_left || 'Strongly disagree'}</Text>
|
|
262
|
-
<Text style={rightLabelStyle}>{scale_label_right || 'Strongly agree'}</Text>
|
|
263
|
-
</View>
|
|
264
|
-
{hasError && (
|
|
265
|
-
<View style={styles.errorWrap}>
|
|
266
|
-
<ErrorIcon size={20} color={ERROR_COLOR} />
|
|
267
|
-
<Text style={errorTextStyle}>{props.error}</Text>
|
|
268
|
-
</View>
|
|
269
|
-
)}
|
|
270
|
-
</View>
|
|
271
|
-
)
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function ButtonNumber({
|
|
275
|
-
handlePressRating,
|
|
276
|
-
active,
|
|
277
|
-
isStart,
|
|
278
|
-
isEnd,
|
|
279
|
-
isLastActive = false,
|
|
280
|
-
isFirstInactive = false,
|
|
281
|
-
number,
|
|
282
|
-
size = 'medium',
|
|
283
|
-
compact = true,
|
|
284
|
-
hasError = false,
|
|
285
|
-
errorBorderColor,
|
|
286
|
-
rating_number_font,
|
|
287
|
-
rating_number_fontsize,
|
|
288
|
-
rating_number_bg_color,
|
|
289
|
-
rating_number_border_color,
|
|
290
|
-
rating_number_selected_bg_color,
|
|
291
|
-
rating_number_selected_border_color,
|
|
292
|
-
rating_number_selected_text_color,
|
|
293
|
-
rating_number_text_color,
|
|
294
|
-
}: ButtonNumberProps) {
|
|
295
|
-
const springAnimated = useRef(new Animated.Value(0)).current
|
|
296
|
-
const preset = useMemo(() => SIZE_PRESETS[size], [size])
|
|
297
|
-
|
|
298
|
-
const h = preset.height
|
|
299
|
-
const radius = preset.borderRadius
|
|
300
|
-
const borderW = preset.borderWidth
|
|
301
|
-
const selectedColor = rating_number_selected_bg_color ?? DEFAULT_SELECTED_COLOR
|
|
302
|
-
const selectedBorderColor = rating_number_selected_border_color ?? DEFAULT_SELECTED_BORDER_COLOR
|
|
303
|
-
const selectedTextColor = rating_number_selected_text_color ?? TEXT_DARK
|
|
304
|
-
const inactiveBorderColor = useMemo(
|
|
305
|
-
() => (hasError && errorBorderColor ? errorBorderColor : rating_number_border_color ?? BORDER_DEFAULT),
|
|
306
|
-
[hasError, errorBorderColor, rating_number_border_color],
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
useEffect(() => {
|
|
310
|
-
if (active) {
|
|
311
|
-
Animated.timing(springAnimated, {
|
|
312
|
-
toValue: 1,
|
|
313
|
-
useNativeDriver: false,
|
|
314
|
-
}).start()
|
|
315
|
-
} else {
|
|
316
|
-
Animated.timing(springAnimated, {
|
|
317
|
-
toValue: 0,
|
|
318
|
-
useNativeDriver: false,
|
|
319
|
-
}).start()
|
|
320
|
-
}
|
|
321
|
-
}, [active, springAnimated])
|
|
322
|
-
|
|
323
|
-
const backgroundColorAni = useMemo(
|
|
324
|
-
() =>
|
|
325
|
-
springAnimated.interpolate({
|
|
326
|
-
inputRange: [0, 1],
|
|
327
|
-
outputRange: [rating_number_bg_color ?? BG_DEFAULT, selectedColor],
|
|
328
|
-
}),
|
|
329
|
-
[springAnimated, rating_number_bg_color, selectedColor],
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
const compactStyle = useMemo(
|
|
333
|
-
() =>
|
|
334
|
-
compact
|
|
335
|
-
? {
|
|
336
|
-
borderRightWidth: isEnd || isLastActive ? borderW : 0,
|
|
337
|
-
borderLeftWidth: isFirstInactive ? 0 : undefined,
|
|
338
|
-
borderTopLeftRadius: isStart ? radius : 0,
|
|
339
|
-
borderBottomLeftRadius: isStart ? radius : 0,
|
|
340
|
-
borderTopRightRadius: isEnd ? radius : 0,
|
|
341
|
-
borderBottomRightRadius: isEnd ? radius : 0,
|
|
342
|
-
}
|
|
343
|
-
: {
|
|
344
|
-
borderRadius: radius,
|
|
345
|
-
},
|
|
346
|
-
[compact, isEnd, isLastActive, isFirstInactive, borderW, isStart, radius],
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
const buttonStyle = useMemo(
|
|
350
|
-
() => [
|
|
351
|
-
styles.buttonNumberContainer,
|
|
352
|
-
{
|
|
353
|
-
flex: 1,
|
|
354
|
-
height: h,
|
|
355
|
-
borderWidth: borderW,
|
|
356
|
-
borderColor: active ? selectedBorderColor : inactiveBorderColor,
|
|
357
|
-
backgroundColor: backgroundColorAni,
|
|
358
|
-
opacity: 1,
|
|
359
|
-
...compactStyle,
|
|
360
|
-
},
|
|
361
|
-
],
|
|
362
|
-
[h, borderW, active, selectedBorderColor, inactiveBorderColor, backgroundColorAni, compactStyle],
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
const labelStyle = useMemo(
|
|
366
|
-
() => ({
|
|
367
|
-
color: active ? selectedTextColor : rating_number_text_color,
|
|
368
|
-
fontSize: rating_number_fontsize,
|
|
369
|
-
fontFamily: rating_number_font,
|
|
370
|
-
}),
|
|
371
|
-
[active, selectedTextColor, rating_number_text_color, rating_number_fontsize, rating_number_font],
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
return (
|
|
375
|
-
<AnimatedTouchable style={buttonStyle} onPress={handlePressRating} activeOpacity={1}>
|
|
376
|
-
<Text style={labelStyle}>{number}</Text>
|
|
377
|
-
</AnimatedTouchable>
|
|
378
|
-
)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
export default RatingNumber
|
|
382
|
-
|
|
383
|
-
const styles = StyleSheet.create({
|
|
384
|
-
wrapper: {
|
|
385
|
-
flex: 1,
|
|
386
|
-
width: '100%',
|
|
387
|
-
},
|
|
388
|
-
question: {
|
|
389
|
-
fontSize: 16,
|
|
390
|
-
fontWeight: '600',
|
|
391
|
-
color: '#14181C',
|
|
392
|
-
marginBottom: 8,
|
|
393
|
-
},
|
|
394
|
-
ratingContainer: {
|
|
395
|
-
flexDirection: 'row',
|
|
396
|
-
alignItems: 'center',
|
|
397
|
-
width: '100%',
|
|
398
|
-
},
|
|
399
|
-
ratingLabelContainer: {
|
|
400
|
-
flexDirection: 'row',
|
|
401
|
-
justifyContent: 'space-between',
|
|
402
|
-
alignItems: 'center',
|
|
403
|
-
width: '100%',
|
|
404
|
-
},
|
|
405
|
-
errorWrap: {
|
|
406
|
-
flexDirection: 'row',
|
|
407
|
-
alignItems: 'center',
|
|
408
|
-
marginTop: 8,
|
|
409
|
-
gap: 6,
|
|
410
|
-
},
|
|
411
|
-
error: {
|
|
412
|
-
fontSize: 14,
|
|
413
|
-
lineHeight: 20,
|
|
414
|
-
flex: 1,
|
|
415
|
-
fontWeight: '400',
|
|
416
|
-
},
|
|
417
|
-
buttonNumberContainer: {
|
|
418
|
-
justifyContent: 'center',
|
|
419
|
-
alignItems: 'center',
|
|
420
|
-
},
|
|
421
|
-
})
|