ordering-ui-react-native 0.14.85 → 0.14.88

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