ordering-ui-react-native 0.14.86 → 0.14.87

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.
@@ -1,202 +1,341 @@
1
1
  import React, { useState, useEffect } from 'react'
2
- import { OrderReview as ReviewOrderController, useLanguage, ToastType, useToast } from 'ordering-components/native'
3
- import { useTheme } from 'styled-components/native';
4
- import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons'
2
+ import { OrderReview as ReviewOrderController, useLanguage, useToast, ToastType } from 'ordering-components/native'
5
3
  import { useForm, Controller } from 'react-hook-form'
4
+ import LinearGradient from 'react-native-linear-gradient'
6
5
 
7
6
  import {
8
- ReviewOrderContainer,
9
- BusinessLogo,
10
- FormReviews,
11
- Category,
12
- Stars
7
+ ReviewOrderContainer,
8
+ BusinessLogo,
9
+ FormReviews,
10
+ CommentsButtonGroup,
11
+ ActionContainer,
12
+ SkipButton,
13
+ RatingBarContainer,
14
+ RatingTextContainer
13
15
  } from './styles'
14
16
  import { OButton, OIcon, OInput, OText } from '../shared'
15
- import { TouchableOpacity, StyleSheet, View } from 'react-native';
17
+ import { TouchableOpacity, StyleSheet, View, I18nManager } from 'react-native';
16
18
  import NavBar from '../NavBar'
19
+ import { FloatingBottomContainer } from '../../layouts/FloatingBottomContainer'
17
20
  import Spinner from 'react-native-loading-spinner-overlay'
18
21
 
19
22
  import { ReviewOrderParams } from '../../types'
23
+ import { useTheme } from 'styled-components/native'
20
24
 
21
25
  export const ReviewOrderUI = (props: ReviewOrderParams) => {
22
- const {
23
- order,
24
- stars,
25
- handleChangeInput,
26
- handleChangeRating,
27
- handleSendReview,
28
- formState,
29
- navigation
30
- } = props
31
-
32
- const theme = useTheme();
33
-
34
-
35
- const styles = StyleSheet.create({
36
- inputTextArea: {
37
- borderColor: theme.colors.secundaryContrast,
38
- borderRadius: 10,
39
- marginVertical: 20,
40
- height: 100,
41
- alignItems: 'flex-start'
42
- }
43
- })
44
-
45
- const [, t] = useLanguage()
46
- const [, { showToast }] = useToast()
47
- const { handleSubmit, control, errors } = useForm()
48
-
49
- const [alertState, setAlertState] = useState<{ open: boolean, content: Array<any>, success?: boolean }>({ open: false, content: [], success: false })
50
-
51
- const categories = {
52
- quality: { name: 'quality', show: t('QUALITY', 'Quality of Product') },
53
- punctuality: { name: 'punctiality', show: t('PUNCTUALITY', 'Punctuality') },
54
- service: { name: 'service', show: t('SERVICE', 'Service') },
55
- packaging: { name: 'packaging', show: t('PRODUCT_PACKAGING', 'Product Packaging') }
56
- }
57
-
58
- const onSubmit = () => {
59
- if (Object.values(stars).some(value => value === 0)) {
60
- setAlertState({
61
- open: true,
62
- content: Object.values(categories).map((category, i) => stars[category.name] === 0 ? `- ${t('CATEGORY_ATLEAST_ONE', `${category.show} must be at least one point`).replace('CATEGORY', category.name.toUpperCase())} ${i !== 3 && '\n'}` : ' ')
63
- })
64
- return
65
- }
66
- handleSendReview()
67
- setAlertState({ ...alertState, success: true })
68
- }
69
-
70
- const getStarArr = (rating: number) => {
71
- switch (rating) {
72
- case 0:
73
- return [0, 0, 0, 0, 0];
74
- case 1:
75
- return [1, 0, 0, 0, 0];
76
- case 2:
77
- return [1, 1, 0, 0, 0];
78
- case 3:
79
- return [1, 1, 1, 0, 0];
80
- case 4:
81
- return [1, 1, 1, 1, 0];
82
- case 5:
83
- return [1, 1, 1, 1, 1];
84
- default:
85
- return [0, 0, 0, 0, 0];
86
- }
87
- }
88
-
89
- useEffect(() => {
90
- if (formState.error && !formState?.loading) {
91
- showToast(ToastType.Error, formState.result)
92
- }
93
- if (!formState.loading && !formState.error && alertState.success) {
94
- showToast(ToastType.Success, t('REVIEW_SUCCESS_CONTENT', 'Thank you, Review successfully submitted!'))
95
- navigation?.canGoBack() && navigation.goBack()
96
- }
97
- }, [formState.result])
98
-
99
- useEffect(() => {
100
- if (Object.keys(errors).length > 0) {
101
- // Convert all errors in one string to show in toast provider
102
- const list = Object.values(errors);
103
- let stringError = '';
104
- list.map((item: any, i: number) => {
105
- stringError +=
106
- i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
107
- });
108
- showToast(ToastType.Error, stringError);
109
- }
110
- }, [errors]);
111
-
112
- useEffect(() => {
113
- if (alertState.open) {
114
- alertState.content && showToast(
115
- ToastType.Error,
116
- alertState.content
117
- )
118
- }
119
- }, [alertState.content])
120
-
121
-
122
- const getStar = (star: number, index: number, category: string) => {
123
- switch (star) {
124
- case 0:
125
- return (
126
- <TouchableOpacity key={index} onPress={() => handleChangeRating({ target: { name: category, value: index + 1 } })}>
127
- <MaterialCommunityIcon name='star-outline' size={24} color={theme.colors.backgroundDark} />
128
- </TouchableOpacity>
129
- )
130
- case 1:
131
- return (
132
- <TouchableOpacity key={index} onPress={() => handleChangeRating({ target: { name: category, value: index + 1 } })}>
133
- <MaterialCommunityIcon name='star' size={24} color={theme.colors.primary} />
134
- </TouchableOpacity>
135
- )
136
- }
137
- }
138
-
139
- return (
140
- <ReviewOrderContainer>
141
- <NavBar
142
- title={t('REVIEW_ORDER', 'Review your Order')}
143
- titleAlign={'center'}
144
- onActionLeft={() => navigation?.canGoBack() && navigation.goBack()}
145
- showCall={false}
146
- btnStyle={{ paddingLeft: 0 }}
147
- paddingTop={0}
148
- />
149
- <BusinessLogo>
150
- <OIcon url={order?.logo} width={100} height={100} />
151
- </BusinessLogo>
152
- <View style={{ flex: 1, justifyContent: 'flex-end' }}>
153
-
154
- <FormReviews>
155
- {Object.values(categories).map(category => (
156
- <Category key={category.name}>
157
- <OText>{category.show}</OText>
158
- <Stars>
159
- {getStarArr(stars[category?.name]).map((star, index) => getStar(star, index, category.name))}
160
- </Stars>
161
- </Category>
162
- ))}
163
- <Controller
164
- control={control}
165
- defaultValue=''
166
- name='comments'
167
- render={({ onChange }: any) => (
168
- <OInput
169
- name='comments'
170
- placeholder={t('COMMENTS', 'Comments')}
171
- onChange={(val: string) => {
172
- onChange(val)
173
- handleChangeInput(val)
174
- }}
175
- style={styles.inputTextArea}
176
- multiline
177
- bgColor={theme.colors.inputDisabled}
178
- />
179
- )}
180
- />
181
- </FormReviews>
182
- <OButton
183
- textStyle={{ color: theme.colors.white }}
184
- style={{ marginTop: 20 }}
185
- text={t('SAVE', 'Save')}
186
- imgRightSrc=''
187
- onClick={handleSubmit(onSubmit)}
188
- />
189
- </View>
190
- <Spinner visible={formState.loading} />
191
- </ReviewOrderContainer>
192
- )
193
- }
26
+ const {
27
+ order,
28
+ stars,
29
+ handleSendReview,
30
+ formState,
31
+ navigation,
32
+ setStars,
33
+ onNavigationRedirect,
34
+ handleReviewState,
35
+ setIsReviewed
36
+ } = props
37
+
38
+ const theme = useTheme()
39
+
40
+ const styles = StyleSheet.create({
41
+ logoWrapper: {
42
+ shadowColor: theme.colors.black,
43
+ shadowRadius: 3,
44
+ shadowOffset: {width: 1, height: 4},
45
+ elevation: 3,
46
+ borderRadius: 8,
47
+ shadowOpacity: 0.1,
48
+ overflow: 'hidden'
49
+ },
50
+ inputTextArea: {
51
+ borderColor: theme.colors.lightGray,
52
+ borderRadius: 8,
53
+ marginTop: 10,
54
+ marginBottom: 40,
55
+ height: 100,
56
+ alignItems: 'flex-start'
57
+ },
58
+ statusBar: {
59
+ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }],
60
+ height: 10,
61
+ borderRadius: 5,
62
+ marginTop: 5
63
+ },
64
+ ratingItemContainer: {
65
+ position: 'absolute',
66
+ top: -20
67
+ },
68
+ ratingItem: {
69
+ left: '-50%',
70
+ flexDirection: 'column',
71
+ alignItems: 'center'
72
+ },
73
+ ratingLineStyle: {
74
+ height: 10,
75
+ width: 1,
76
+ marginBottom: 10,
77
+ backgroundColor: theme.colors.dusk
78
+ },
79
+ reviewedStyle: {
80
+ flexDirection: 'row',
81
+ justifyContent: 'center',
82
+ marginVertical: 20
83
+ },
84
+ })
85
+
86
+ const [, t] = useLanguage()
87
+ const [, { showToast }] = useToast()
88
+ const { handleSubmit, control, errors } = useForm()
89
+
90
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<any>, success?: boolean }>({ open: false, content: [], success: false })
91
+ const [comments, setComments] = useState<Array<any>>([])
92
+ const [extraComment, setExtraComment] = useState('')
93
+
94
+ const onSubmit = () => {
95
+ if (Object.values(stars).some((value: any) => value === 0)) {
96
+ setAlertState({
97
+ open: true,
98
+ content: stars.quality === 0 ? [`${t('REVIEW_QUALIFICATION_REQUIRED', 'Review qualification is required')}`] : []
99
+ })
100
+ return
101
+ }
102
+ handleSendReview()
103
+ handleReviewState && handleReviewState(order?.id)
104
+ setIsReviewed && setIsReviewed(true)
105
+ setAlertState({ ...alertState, success: true })
106
+ }
107
+
108
+ const qualificationList = [
109
+ { key: 1, text: t('TERRIBLE', 'Terrible'), percent: 0, parentStyle: { left: '0%' }, isInnerStyle: false, pointerColor: false },
110
+ { key: 2, text: t('BAD', 'Bad'), percent: 0.25, parentStyle: { left: '25%' }, isInnerStyle: true, pointerColor: true },
111
+ { key: 3, text: t('OKAY', 'Okay'), percent: 0.5, parentStyle: { left: '50%' }, isInnerStyle: true, pointerColor: true },
112
+ { key: 4, text: t('GOOD', 'Good'), percent: 0.75, parentStyle: { left: '75%' }, isInnerStyle: true, pointerColor: true },
113
+ { key: 5, text: t('GREAT', 'Great'), percent: 1, parentStyle: { right: '0%' }, isInnerStyle: false, pointerColor: false }
114
+ ]
115
+
116
+ const commentsList = [
117
+ { key: 0, content: t('IT_WASNT_TASTY', "It wasn't tasty") },
118
+ { key: 1, content: t('IT_DOESNT_PACK_WELL', "It doesn't pack well") },
119
+ { key: 2, content: t('IT_ISNT_WORTH_WHAT_IT_COSTS', "It isn't worth what it costs") },
120
+ { key: 3, content: t('TOO_SLOW', 'Too slow') },
121
+ { key: 4, content: t('SUSTAINABLE_PACKAGING_WASNT_USED', "Sustainable packaging wasn't used") },
122
+ { key: 5, content: t('THEY_DID_NOT_FOLLOW_THE_ORDER_NOTES', 'They did not follow the order notes') }
123
+ ]
124
+
125
+ const handleChangeStars = (index: number) => {
126
+ switch (index) {
127
+ case 1:
128
+ setStars({ ...stars, quality: 1, punctiality: 1, service: 1, packaging: 1 })
129
+ break
130
+ case 2:
131
+ setStars({ ...stars, quality: 2, punctiality: 2, service: 2, packaging: 2 })
132
+ break
133
+ case 3:
134
+ setStars({ ...stars, quality: 3, punctiality: 3, service: 3, packaging: 3 })
135
+ break
136
+ case 4:
137
+ setStars({ ...stars, quality: 4, punctiality: 4, service: 4, packaging: 4 })
138
+ break
139
+ case 5:
140
+ setStars({ ...stars, quality: 5, punctiality: 5, service: 5, packaging: 5 })
141
+ break
142
+ }
143
+ }
144
+
145
+ const handleChangeComment = (commentItem: any) => {
146
+ const found = comments.find((comment: any) => comment?.key === commentItem.key)
147
+ if (found) {
148
+ const _comments = comments.filter((comment: any) => comment?.key !== commentItem.key)
149
+ setComments(_comments)
150
+ } else {
151
+ setComments([...comments, commentItem])
152
+ }
153
+ }
194
154
 
155
+ const isSelectedComment = (commentKey: number) => {
156
+ const found = comments.find((comment: any) => comment?.key === commentKey)
157
+ return found
158
+ }
159
+
160
+ const handleContinueClick = () => {
161
+ if (!order?.review) {
162
+ onSubmit()
163
+ } else {
164
+ onNavigationRedirect('ReviewProducts', { order: order })
165
+ }
166
+ }
167
+
168
+ useEffect(() => {
169
+ if (formState.error && !formState?.loading) {
170
+ showToast(ToastType.Error, formState.result)
171
+ }
172
+ if (!formState.loading && !formState.error && alertState.success) {
173
+ showToast(ToastType.Success, t('ORDER_REVIEW_SUCCESS_CONTENT', 'Thank you, Order review successfully submitted!'))
174
+ onNavigationRedirect && onNavigationRedirect('ReviewProducts', { order: order })
175
+ }
176
+ }, [formState.result])
177
+
178
+ useEffect(() => {
179
+ if (Object.keys(errors).length > 0) {
180
+ // Convert all errors in one string to show in toast provider
181
+ const list = Object.values(errors);
182
+ let stringError = '';
183
+ list.map((item: any, i: number) => {
184
+ stringError +=
185
+ i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
186
+ });
187
+ showToast(ToastType.Error, stringError);
188
+ }
189
+ }, [errors])
190
+
191
+ useEffect(() => {
192
+ if (alertState.open) {
193
+ alertState.content && showToast(
194
+ ToastType.Error,
195
+ alertState.content
196
+ )
197
+ }
198
+ }, [alertState.content])
199
+
200
+ useEffect(() => {
201
+ let _comments = ''
202
+ if (comments.length > 0) {
203
+ comments.map(comment => _comments += comment.content + '. ')
204
+ }
205
+ let _comment
206
+ _comment = _comments + extraComment
207
+ setStars({ ...stars, comments: _comment })
208
+ }, [comments, extraComment])
209
+
210
+ return (
211
+ <>
212
+ <ReviewOrderContainer>
213
+ <NavBar
214
+ title={t('REVIEW_ORDER', 'Review your Order')}
215
+ titleAlign={'center'}
216
+ onActionLeft={() => navigation?.canGoBack() && navigation.goBack()}
217
+ showCall={false}
218
+ btnStyle={{ paddingLeft: 0 }}
219
+ style={{ flexDirection: 'column', alignItems: 'flex-start' }}
220
+ titleWrapStyle={{ paddingHorizontal: 0 }}
221
+ titleStyle={{ marginRight: 0, marginLeft: 0 }}
222
+ />
223
+ <BusinessLogo>
224
+ <View style={styles.logoWrapper}>
225
+ <OIcon
226
+ url={order?.logo}
227
+ width={80}
228
+ height={80}
229
+ />
230
+ </View>
231
+ </BusinessLogo>
232
+ {order?.review ? (
233
+ <View style={styles.reviewedStyle}>
234
+ <OText color={theme.colors.primary}>{t('ORDER_REVIEWED', 'This order has been already reviewed')}</OText>
235
+ </View>
236
+ ) : (
237
+ <View style={{flex: 1, justifyContent: 'flex-end'}}>
238
+ <FormReviews>
239
+ <OText mBottom={13} color={theme.colors.textNormal}>{t('HOW_WAS_YOUR_ORDER', 'How was your order?')}</OText>
240
+ <RatingBarContainer>
241
+ <LinearGradient
242
+ start={{ x: 0.0, y: 0.0 }}
243
+ end={{ x: qualificationList[stars.quality - 1]?.percent || 0, y: 0 }}
244
+ locations={[.9999, .9999]}
245
+ colors={[theme.colors.primary, theme.colors.backgroundGray200]}
246
+ style={styles.statusBar}
247
+ />
248
+ <RatingTextContainer>
249
+ {qualificationList.map((qualification: any) => (
250
+ <View
251
+ key={qualification.key}
252
+ style={{ ...qualification.parentStyle, ...styles.ratingItemContainer }}
253
+ >
254
+ <TouchableOpacity
255
+ style={qualification.isInnerStyle && styles.ratingItem}
256
+ onPress={() => handleChangeStars(qualification.key)}
257
+ >
258
+ <View
259
+ style={{
260
+ ...styles.ratingLineStyle,
261
+ backgroundColor: (qualification.pointerColor && !(stars.quality >= qualification.key)) ? theme.colors.dusk : 'transparent'
262
+ }}
263
+ />
264
+ <OText size={12} color={stars.quality === qualification.key ? theme.colors.black : theme.colors.backgroundGray200}>{qualification.text}</OText>
265
+ </TouchableOpacity>
266
+ </View>
267
+ ))}
268
+ </RatingTextContainer>
269
+ </RatingBarContainer>
270
+
271
+ <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>{t('COMMENTS', 'Comments')}</OText>
272
+ <CommentsButtonGroup>
273
+ {commentsList.map(commentItem => (
274
+ <OButton
275
+ key={commentItem.key}
276
+ text={commentItem.content}
277
+ bgColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
278
+ borderColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
279
+ textStyle={{
280
+ color: isSelectedComment(commentItem.key) ? theme.colors.white : theme.colors.black,
281
+ fontSize: 13,
282
+ paddingRight: isSelectedComment(commentItem.key) ? 15 : 0
283
+ }}
284
+ style={{ height: 35, paddingLeft: 5, paddingRight: 5, marginHorizontal: 3, marginVertical: 10 }}
285
+ imgRightSrc={isSelectedComment(commentItem.key) ? theme.images.general.close : null}
286
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
287
+ onClick={() => handleChangeComment(commentItem) }
288
+ />
289
+ ))}
290
+ </CommentsButtonGroup>
291
+
292
+ <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>{t('REVIEW_COMMENT_QUESTION', 'Do you want to add something?')}</OText>
293
+ <Controller
294
+ control={control}
295
+ defaultValue=''
296
+ name='comments'
297
+ render={({ onChange }: any) => (
298
+ <OInput
299
+ name='comments'
300
+ onChange={(val: any) => {
301
+ onChange(val)
302
+ setExtraComment(val.target.value)
303
+ }}
304
+ style={styles.inputTextArea}
305
+ multiline
306
+ />
307
+ )}
308
+ />
309
+ </FormReviews>
310
+ </View>
311
+ )}
312
+ <Spinner visible={formState.loading} />
313
+ </ReviewOrderContainer>
314
+ <FloatingBottomContainer>
315
+ <ActionContainer>
316
+ <SkipButton
317
+ onPress={() => onNavigationRedirect('ReviewProducts', { order: order })}
318
+ >
319
+ <OText weight={700} size={18} color={theme.colors.textNormal}>{t('FRONT_VISUALS_SKIP', 'Skip')}</OText>
320
+ </SkipButton>
321
+ <OButton
322
+ textStyle={{ color: theme.colors.white, paddingRight: 10 }}
323
+ text={t('CONTINUE', 'Continue')}
324
+ style={{ borderRadius: 8 }}
325
+ imgRightSrc={theme.images.general.arrow_right}
326
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
327
+ onClick={handleSubmit(handleContinueClick)}
328
+ />
329
+ </ActionContainer>
330
+ </FloatingBottomContainer>
331
+ </>
332
+ )
333
+ }
195
334
 
196
335
  export const ReviewOrder = (props: ReviewOrderParams) => {
197
- const reviewOrderProps = {
198
- ...props,
199
- UIComponent: ReviewOrderUI
200
- }
201
- return <ReviewOrderController {...reviewOrderProps} />
336
+ const reviewOrderProps = {
337
+ ...props,
338
+ UIComponent: ReviewOrderUI
339
+ }
340
+ return <ReviewOrderController {...reviewOrderProps} />
202
341
  }
@@ -1,11 +1,8 @@
1
1
  import styled from 'styled-components/native'
2
2
 
3
- export const ReviewOrderContainer = styled.View`
4
- width: 100%;
5
- flex: 1;
6
- `
7
- export const ReviewOrderTitle = styled.View`
8
-
3
+ export const ReviewOrderContainer = styled.ScrollView`
4
+ padding: 20px 40px;
5
+ margin-bottom: 100px;
9
6
  `
10
7
 
11
8
  export const BusinessLogo = styled.View`
@@ -16,18 +13,32 @@ export const BusinessLogo = styled.View`
16
13
  export const FormReviews = styled.View`
17
14
  flex: 1;
18
15
  height: 100%;
16
+ margin-top: 30px;
19
17
  `
20
18
 
21
- export const Category = styled.View`
22
- padding: 10px;
23
- border-width: 1px;
24
- border-color: ${(props: any) => props.theme.colors.secundaryContrast};
19
+ export const CommentsButtonGroup = styled.View`
25
20
  flex-direction: row;
21
+ flex-wrap: wrap;
22
+ `
23
+
24
+ export const ActionContainer = styled.View`
25
+ flex-direction: row;
26
+ align-items: center;
26
27
  justify-content: space-between;
27
- margin-vertical: 5px;
28
- border-radius: 10px;
28
+ padding: 3px 30px;
29
+ `
30
+
31
+ export const SkipButton = styled.TouchableOpacity`
29
32
  `
30
33
 
31
- export const Stars = styled.View`
34
+ export const RatingBarContainer = styled.View`
35
+ margin-top: 10px;
36
+ margin-bottom: 25px;
37
+ `
38
+
39
+ export const RatingTextContainer = styled.View`
32
40
  flex-direction: row;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ margin-top: 10px;
33
44
  `