ordering-ui-react-native 0.16.51 → 0.16.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.16.51",
3
+ "version": "0.16.52",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -29,6 +29,9 @@ import { UserProfileForm } from './src/components/UserProfileForm';
29
29
  import { ReviewOrder } from './src/components/ReviewOrder';
30
30
  import { ReviewProducts } from './src/components/ReviewProducts';
31
31
  import { ReviewDriver } from './src/components/ReviewDriver';
32
+ import { ReviewOrder as ReviewOrderModal } from './src/components/Reviews/ReviewOrder';
33
+ import { ReviewProducts as ReviewProductsModal } from './src/components/Reviews/ReviewProducts';
34
+ import { ReviewDriver as ReviewDriverModal } from './src/components/Reviews/ReviewDriver';
32
35
  import { UserProfile } from './src/components/UserProfile';
33
36
  import { MessageListing } from './src/components/MessageListing';
34
37
  import { Messages } from './src/components/Messages';
@@ -186,6 +189,9 @@ export {
186
189
  ReviewOrder,
187
190
  ReviewProducts,
188
191
  ReviewDriver,
192
+ ReviewOrderModal,
193
+ ReviewProductsModal,
194
+ ReviewDriverModal,
189
195
  BusinessMenuList,
190
196
  UserProfile,
191
197
  MessageListing,
@@ -320,7 +320,15 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
320
320
  </MomentWrapper>
321
321
  <View style={styles.wrapperOrderOptions}>
322
322
  <WrapMomentOption onPress={() => navigation.navigate('OrderTypes', { configTypes: configTypes, setOrderTypeValue })}>
323
- <OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textSecondary}>{t(getTypesText(orderTypeValue || orderState?.options?.type || 1), 'Delivery')}</OText>
323
+ <OText
324
+ size={12}
325
+ numberOfLines={1}
326
+ ellipsizeMode={'tail'}
327
+ color={theme.colors.textSecondary}
328
+ style={{ textAlign: 'left' }}
329
+ >
330
+ {t(getTypesText(orderTypeValue || orderState?.options?.type || 1), 'Delivery')}
331
+ </OText>
324
332
  <OIcon
325
333
  src={theme.images.general.arrow_down}
326
334
  width={10}
@@ -43,8 +43,9 @@ export const WrapMomentOption = styled.TouchableOpacity`
43
43
  font-size: 12px;
44
44
  max-width: 240px;
45
45
  height: 26px;
46
+ width: 130px;
46
47
  align-items: center;
47
- justify-content: center;
48
+ justify-content: space-between;
48
49
  padding-horizontal: 8px;
49
50
  flex-direction: row;
50
51
  margin-end: 12px;
@@ -84,7 +85,7 @@ export const FarAwayMessage = styled.View`
84
85
  `
85
86
 
86
87
  export const SearchBarWrapper = styled.View`
87
- width: 100px;
88
+ width: 130px;
88
89
  `
89
90
 
90
91
  export const MomentWrapper = styled.View`
@@ -1,42 +1,91 @@
1
1
 
2
2
  import React, { useState, useEffect } from 'react'
3
- import { useOrder, useSession } from 'ordering-components/native';
3
+ import { useOrder, useSession, useLanguage } from 'ordering-components/native';
4
4
 
5
5
  import { useTheme } from 'styled-components/native'
6
6
  import { BusinessesListing as OriginalBusinessListing } from './Layout/Original'
7
7
  import { BusinessesListing as AppointmentBusinessListing } from './Layout/Appointment'
8
+ import { OBottomPopup } from '../shared';
9
+ import { ReviewOrderModal, ReviewProductsModal, ReviewDriverModal } from '../Reviews'
8
10
 
9
11
  export const BusinessesListing = (props: any) => {
10
12
  const theme = useTheme()
13
+ const [, t] = useLanguage();
11
14
  const layout = theme?.layout?.businessListing?.layout?.type || 'original'
12
15
  const [{ auth }] = useSession()
13
16
  const [, { getLastOrderHasNoReview }] = useOrder();
14
- const [, setIsReviewed] = useState(false)
15
- const handleOrderReview = (order: any) => {
16
- props?.navigation && props.navigation.navigate(
17
- 'ReviewOrder',
18
- {
19
- order: {
20
- id: order?.id,
21
- business_id: order?.business_id,
22
- business_name: order?.business?.name,
23
- delivery_datetime: order?.delivery_datetime,
24
- logo: order.business?.logo,
25
- driver: order?.driver,
26
- products: order?.products,
27
- review: order?.review,
28
- user_review: order?.user_review
29
- },
30
- setIsReviewed
31
- }
32
- )
33
- }
17
+
18
+ const [lastOrderReview, setLastOrderReview] = useState({
19
+ isReviewOpen: false,
20
+ order: {
21
+ id: 0,
22
+ business_id: 0,
23
+ business_name: '',
24
+ delivery_datetime: '',
25
+ logo: '',
26
+ driver: null,
27
+ products: [],
28
+ review: null,
29
+ user_review: null
30
+ },
31
+ reviewStatus: { order: false, product: false, driver: false },
32
+ reviewed: { isOrderReviewed: false, isProductReviewed: false, isDriverReviewed: false }
33
+ })
34
34
 
35
35
  const _getLastOrderHasNoReview = async () => {
36
36
  const lastOrderHasNoReview = await getLastOrderHasNoReview()
37
37
  lastOrderHasNoReview && handleOrderReview(lastOrderHasNoReview)
38
38
  }
39
39
 
40
+ const handleOrderReview = (order: any) => {
41
+ setLastOrderReview({
42
+ isReviewOpen: true,
43
+ order: {
44
+ id: order?.id,
45
+ business_id: order?.business_id,
46
+ business_name: order?.business?.name,
47
+ delivery_datetime: order?.delivery_datetime,
48
+ logo: order.business?.logo,
49
+ driver: order?.driver,
50
+ products: order?.products,
51
+ review: order?.review,
52
+ user_review: order?.user_review
53
+ },
54
+ reviewStatus: { order: true, product: false, driver: false },
55
+ reviewed: { isOrderReviewed: false, isProductReviewed: false, isDriverReviewed: false }
56
+ })
57
+ }
58
+
59
+ const handleCloseReivew = () => {
60
+ setLastOrderReview({
61
+ ...lastOrderReview,
62
+ isReviewOpen: false,
63
+ reviewStatus: { order: false, product: false, driver: false }
64
+ })
65
+ }
66
+
67
+ const setIsReviewed = (reviewType: string) => {
68
+ const _reviewStatus = { ...lastOrderReview?.reviewed }
69
+ setLastOrderReview({
70
+ ...lastOrderReview,
71
+ reviewed: { ..._reviewStatus, [reviewType]: true }
72
+ })
73
+ }
74
+
75
+ const closeReviewOrder = () => {
76
+ if (!lastOrderReview?.reviewed?.isProductReviewed) setLastOrderReview({ ...lastOrderReview, reviewStatus: { order: false, product: true, driver: false } })
77
+ else if (lastOrderReview?.order?.driver && !lastOrderReview?.order?.user_review && !lastOrderReview?.reviewed?.isDriverReviewed) setLastOrderReview({ ...lastOrderReview, reviewStatus: { order: false, product: false, driver: true } })
78
+ else handleCloseReivew()
79
+ }
80
+
81
+ const closeReviewProduct = () => {
82
+ if (lastOrderReview?.order?.driver && !lastOrderReview?.order?.user_review && !lastOrderReview?.reviewed?.isDriverReviewed) setLastOrderReview({ ...lastOrderReview, reviewStatus: { order: false, product: false, driver: true } })
83
+ else {
84
+ setIsReviewed('isDriverReviewed')
85
+ handleCloseReivew()
86
+ }
87
+ }
88
+
40
89
  useEffect(() => {
41
90
  auth && _getLastOrderHasNoReview()
42
91
  }, [auth])
@@ -45,6 +94,32 @@ export const BusinessesListing = (props: any) => {
45
94
  <>
46
95
  {(layout === 'original') && <OriginalBusinessListing {...props} />}
47
96
  {(layout === 'appointment') && <AppointmentBusinessListing {...props} />}
97
+
98
+ {lastOrderReview?.isReviewOpen && (
99
+ <OBottomPopup
100
+ open={lastOrderReview?.isReviewOpen}
101
+ onClose={handleCloseReivew}
102
+ title={lastOrderReview?.order
103
+ ? (lastOrderReview?.reviewStatus?.order
104
+ ? t('HEY', 'Hey! ') + t('HOW_WAS_YOUR_ORDER', 'How was your order?')
105
+ : (lastOrderReview?.reviewStatus?.product
106
+ ? t('REVIEW_PRODUCT', 'Review Product')
107
+ : t('REVIEW_DRIVER', 'Review Driver')))
108
+ : t('LOADING', 'Loading...')}
109
+ bottomContainerStyle={{ height: 'auto' }}
110
+ titleStyle={{ textAlign: 'center' }}
111
+ closeIcon={theme.images.general.close}
112
+ >
113
+ {
114
+ lastOrderReview?.reviewStatus?.order
115
+ ? <ReviewOrderModal order={lastOrderReview?.order} closeReviewOrder={closeReviewOrder} skipReview={handleCloseReivew} setIsReviewed={() => setIsReviewed('isOrderReviewed')} />
116
+ : (lastOrderReview?.reviewStatus?.product
117
+ ? <ReviewProductsModal order={lastOrderReview?.order} closeReviewProduct={closeReviewProduct} setIsProductReviewed={() => setIsReviewed('isProductReviewed')} />
118
+ : <ReviewDriverModal order={lastOrderReview?.order} closeReviewDriver={handleCloseReivew} setIsDriverReviewed={() => setIsReviewed('isDriverReviewed')} />)
119
+ }
120
+
121
+ </OBottomPopup>
122
+ )}
48
123
  </>
49
124
  )
50
- }
125
+ }
@@ -0,0 +1,301 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { useLanguage, useToast, ToastType, ReviewDriver as ReviewDriverController } from 'ordering-components/native'
3
+ import { StyleSheet, View, I18nManager, TouchableOpacity } from 'react-native'
4
+ import { ReviewDriverParams } from '../../../types'
5
+ import { useTheme } from 'styled-components/native'
6
+ import { useForm, Controller } from 'react-hook-form'
7
+ import { OText, OIcon, OButton, OInput } from '../../shared'
8
+ import LinearGradient from 'react-native-linear-gradient'
9
+ import { FloatingBottomContainer } from '../../../layouts/FloatingBottomContainer'
10
+ import Spinner from 'react-native-loading-spinner-overlay'
11
+
12
+ import { reviewCommentList } from '../../../../../../src/utils'
13
+
14
+ import {
15
+ ReviewDriverContainer,
16
+ DriverPhotoContainer,
17
+ FormReviews,
18
+ RatingBarContainer,
19
+ RatingTextContainer,
20
+ CommentsButtonGroup,
21
+ ActionContainer,
22
+ } from './styles'
23
+
24
+ const ReviewDriverUI = (props: ReviewDriverParams) => {
25
+ const {
26
+ order,
27
+ navigation,
28
+ formState,
29
+ dirverReviews,
30
+ setDriverReviews,
31
+ handleSendDriverReview,
32
+ closeReviewDriver
33
+ } = props
34
+
35
+ const [, t] = useLanguage()
36
+ const theme = useTheme()
37
+ const { handleSubmit, control, errors } = useForm()
38
+ const [, { showToast }] = useToast()
39
+
40
+ const [isDriverReviewed, setIsDriverReviewed] = useState(false)
41
+
42
+ const styles = StyleSheet.create({
43
+ photoWrapper: {
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
+ })
82
+
83
+ const [comments, setComments] = useState<Array<any>>([])
84
+ const [extraComment, setExtraComment] = useState('')
85
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<any>, success?: boolean }>({ open: false, content: [], success: false })
86
+
87
+ const qualificationList = [
88
+ { key: 1, text: t('TERRIBLE', 'Terrible'), percent: 0, parentStyle: { left: '0%' }, isInnerStyle: false, pointerColor: false },
89
+ { key: 2, text: t('BAD', 'Bad'), percent: 0.25, parentStyle: { left: '25%' }, isInnerStyle: true, pointerColor: true },
90
+ { key: 3, text: t('OKAY', 'Okay'), percent: 0.5, parentStyle: { left: '50%' }, isInnerStyle: true, pointerColor: true },
91
+ { key: 4, text: t('GOOD', 'Good'), percent: 0.75, parentStyle: { left: '75%' }, isInnerStyle: true, pointerColor: true },
92
+ { key: 5, text: t('GREAT', 'Great'), percent: 1, parentStyle: { right: '0%' }, isInnerStyle: false, pointerColor: false }
93
+ ]
94
+
95
+ const commentsList = reviewCommentList('driver')
96
+
97
+ const onSubmit = () => {
98
+ if (dirverReviews?.qualification === 0) {
99
+ setAlertState({
100
+ open: true,
101
+ content: dirverReviews?.qualification === 0 ? [`${t('REVIEW_QUALIFICATION_REQUIRED', 'Review qualification is required')}`] : []
102
+ })
103
+ return
104
+ }
105
+ handleSendDriverReview()
106
+ setAlertState({ ...alertState, success: true })
107
+ }
108
+
109
+ const isSelectedComment = (commentKey: number) => {
110
+ const found = comments.find((comment: any) => comment?.key === commentKey)
111
+ return found
112
+ }
113
+
114
+ const handleChangeComment = (commentItem: any) => {
115
+ const found = comments.find((comment: any) => comment?.key === commentItem.key)
116
+ if (found) {
117
+ const _comments = comments.filter((comment: any) => comment?.key !== commentItem.key)
118
+ setComments(_comments)
119
+ } else {
120
+ setComments([...comments, commentItem])
121
+ }
122
+ }
123
+
124
+ const handleChangeQualification = (qualification: number) => {
125
+ if (qualification) setDriverReviews({ ...dirverReviews, qualification: qualification, comment: '' })
126
+ setComments([])
127
+ }
128
+
129
+ const handleSendReviewClick = () => {
130
+ (!order?.user_review && !isDriverReviewed) && onSubmit()
131
+ }
132
+
133
+ useEffect(() => {
134
+ if (!formState.loading && formState.result?.error) {
135
+ setAlertState({
136
+ open: true,
137
+ success: false,
138
+ content: formState.result?.result || [t('ERROR', 'Error')]
139
+ })
140
+ }
141
+ if (!formState.loading && !formState.result?.error && alertState.success) {
142
+ setIsDriverReviewed && setIsDriverReviewed(true)
143
+ closeReviewDriver && closeReviewDriver()
144
+ }
145
+ }, [formState])
146
+
147
+ useEffect(() => {
148
+ if (Object.keys(errors).length > 0) {
149
+ // Convert all errors in one string to show in toast provider
150
+ const list = Object.values(errors);
151
+ let stringError = '';
152
+ list.map((item: any, i: number) => {
153
+ stringError +=
154
+ i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
155
+ });
156
+ showToast(ToastType.Error, stringError);
157
+ }
158
+ }, [errors])
159
+
160
+ useEffect(() => {
161
+ if (alertState.open) {
162
+ alertState.content && showToast(
163
+ ToastType.Error,
164
+ alertState.content
165
+ )
166
+ }
167
+ }, [alertState.content])
168
+
169
+ useEffect(() => {
170
+ let _comments = ''
171
+ if (comments.length > 0) {
172
+ comments.map((comment: any) => (_comments += comment.content + '. '))
173
+ }
174
+ const _comment = _comments + extraComment
175
+ setDriverReviews({ ...dirverReviews, comment: _comment })
176
+ }, [comments, extraComment])
177
+
178
+ return (
179
+ <>
180
+ <ReviewDriverContainer>
181
+ <DriverPhotoContainer>
182
+ <View
183
+ style={{
184
+ ...styles.photoWrapper,
185
+ backgroundColor: theme.colors.white,
186
+ padding: !order?.driver?.photo ? 5 : 0
187
+ }}
188
+ >
189
+ <OIcon
190
+ url={order?.driver?.photo}
191
+ src={!order?.driver?.photo && theme.images.general.user}
192
+ cover={order?.driver?.photo ? true : false}
193
+ width={80}
194
+ height={80}
195
+ />
196
+ </View>
197
+ <OText weight={500} style={{ marginVertical: 10 }} color={theme.colors.textNormal}>{order?.driver?.name} {order?.driver?.lastname}</OText>
198
+ </DriverPhotoContainer>
199
+
200
+ <View style={{ flex: 1, justifyContent: 'flex-end' }}>
201
+ <FormReviews>
202
+ <OText mBottom={13} color={theme.colors.textNormal}>{t('HOW_WAS_YOUR_DRIVER', 'How was your driver?')}</OText>
203
+ <RatingBarContainer>
204
+ <LinearGradient
205
+ start={{ x: 0.0, y: 0.0 }}
206
+ end={{ x: qualificationList[dirverReviews?.qualification - 1]?.percent || 0, y: 0 }}
207
+ locations={[.9999, .9999]}
208
+ colors={[theme.colors.primary, theme.colors.backgroundGray200]}
209
+ style={styles.statusBar}
210
+ />
211
+ <RatingTextContainer>
212
+ {qualificationList.map((qualification: any) => (
213
+ <View
214
+ key={qualification.key}
215
+ style={{ ...qualification.parentStyle, ...styles.ratingItemContainer }}
216
+ >
217
+ <TouchableOpacity
218
+ style={qualification.isInnerStyle && styles.ratingItem}
219
+ onPress={() => handleChangeQualification(qualification.key)}
220
+ >
221
+ <View
222
+ style={{
223
+ ...styles.ratingLineStyle,
224
+ backgroundColor: (qualification.pointerColor && !(dirverReviews?.qualification >= qualification.key)) ? theme.colors.dusk : 'transparent'
225
+ }}
226
+ />
227
+ <OText size={12} color={dirverReviews?.qualification === qualification.key ? theme.colors.black : theme.colors.lightGray}>{qualification.text}</OText>
228
+ </TouchableOpacity>
229
+ </View>
230
+ ))}
231
+ </RatingTextContainer>
232
+ </RatingBarContainer>
233
+
234
+ <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>
235
+ {commentsList[dirverReviews?.qualification || 1]?.title}
236
+ </OText>
237
+ <CommentsButtonGroup>
238
+ {commentsList[dirverReviews?.qualification || 1]?.list?.map(commentItem => (
239
+ <OButton
240
+ key={commentItem.key}
241
+ text={commentItem.content}
242
+ bgColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
243
+ borderColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
244
+ textStyle={{
245
+ color: isSelectedComment(commentItem.key) ? theme.colors.white : theme.colors.textNormal,
246
+ fontSize: 13,
247
+ paddingRight: isSelectedComment(commentItem.key) ? 15 : 0
248
+ }}
249
+ style={{ height: 35, paddingLeft: 5, paddingRight: 5, marginHorizontal: 3, marginVertical: 10 }}
250
+ imgRightSrc={isSelectedComment(commentItem.key) ? theme.images.general.close : null}
251
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
252
+ onClick={() => handleChangeComment(commentItem)}
253
+ />
254
+ ))}
255
+ </CommentsButtonGroup>
256
+
257
+ <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>{t('REVIEW_COMMENT_QUESTION', 'Do you want to add something?')}</OText>
258
+ <Controller
259
+ control={control}
260
+ defaultValue=''
261
+ name='comments'
262
+ render={({ onChange }: any) => (
263
+ <OInput
264
+ name='comments'
265
+ onChange={(val: any) => {
266
+ onChange(val)
267
+ setExtraComment(val.target.value)
268
+ }}
269
+ style={styles.inputTextArea}
270
+ multiline
271
+ />
272
+ )}
273
+ />
274
+ </FormReviews>
275
+ </View>
276
+ </ReviewDriverContainer>
277
+ <Spinner visible={formState.loading} />
278
+ <FloatingBottomContainer>
279
+ <ActionContainer>
280
+ <OButton
281
+ textStyle={{ color: theme.colors.white, paddingRight: 10 }}
282
+ text={t('SEND_REVIEW', 'Send Review')}
283
+ style={{ borderRadius: 8 }}
284
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
285
+ isDisabled={dirverReviews?.qualification < 1 || dirverReviews?.comment.length < 1}
286
+ onClick={handleSubmit(handleSendReviewClick)}
287
+ />
288
+ </ActionContainer>
289
+ </FloatingBottomContainer>
290
+ </>
291
+ )
292
+ }
293
+
294
+ export const ReviewDriver = (props: any) => {
295
+ const reviewDriverProps = {
296
+ ...props,
297
+ UIComponent: ReviewDriverUI,
298
+ isToast: true
299
+ }
300
+ return <ReviewDriverController {...reviewDriverProps} />
301
+ }
@@ -0,0 +1,39 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const ReviewDriverContainer = styled.ScrollView`
4
+ padding: 20px 40px;
5
+ margin-bottom: 100px;
6
+ max-height: 400px;
7
+ `
8
+
9
+ export const DriverPhotoContainer = styled.View`
10
+ margin-vertical: 5px;
11
+ flex-direction: column;
12
+ align-items: center;
13
+ `
14
+
15
+ export const FormReviews = styled.View`
16
+ flex: 1;
17
+ height: 100%;
18
+ margin-top: 30px;
19
+ `
20
+
21
+ export const RatingBarContainer = styled.View`
22
+ margin-top: 10px;
23
+ margin-bottom: 25px;
24
+ `
25
+
26
+ export const RatingTextContainer = styled.View`
27
+ flex-direction: row;
28
+ align-items: center;
29
+ justify-content: space-between;
30
+ margin-top: 10px;
31
+ `
32
+ export const CommentsButtonGroup = styled.View`
33
+ flex-direction: row;
34
+ flex-wrap: wrap;
35
+ `
36
+
37
+ export const ActionContainer = styled.View`
38
+ padding: 3px 30px;
39
+ `
@@ -0,0 +1,326 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { TouchableOpacity, StyleSheet, View, I18nManager } from 'react-native';
3
+ import FontAwesome from 'react-native-vector-icons/FontAwesome';
4
+ import { OrderReview as ReviewOrderController, useLanguage, useToast, ToastType, useUtils } from 'ordering-components/native'
5
+ import { useForm, Controller } from 'react-hook-form'
6
+ import LinearGradient from 'react-native-linear-gradient'
7
+
8
+ import {
9
+ ReviewOrderContainer,
10
+ BusinessLogo,
11
+ FormReviews,
12
+ CommentsButtonGroup,
13
+ ActionContainer,
14
+ SkipButton,
15
+ RatingBarContainer,
16
+ RatingTextContainer,
17
+ RatingStarContainer,
18
+ PlacedDate
19
+ } from './styles'
20
+ import { OButton, OIcon, OInput, OText } from '../../shared'
21
+ import { FloatingBottomContainer } from '../../../layouts/FloatingBottomContainer'
22
+ import Spinner from 'react-native-loading-spinner-overlay'
23
+
24
+ import { ReviewOrderParams } from '../../../types'
25
+ import { useTheme } from 'styled-components/native'
26
+
27
+ import { reviewCommentList } from '../../../../../../src/utils'
28
+
29
+ export const ReviewOrderUI = (props: ReviewOrderParams) => {
30
+ const {
31
+ order,
32
+ stars,
33
+ handleSendReview,
34
+ formState,
35
+ setStars,
36
+ setIsReviewed,
37
+ closeReviewOrder,
38
+ skipReview
39
+ } = props
40
+
41
+ const theme = useTheme()
42
+
43
+ const styles = StyleSheet.create({
44
+ logoWrapper: {
45
+ shadowColor: theme.colors.black,
46
+ shadowRadius: 3,
47
+ shadowOffset: { width: 1, height: 4 },
48
+ elevation: 3,
49
+ borderRadius: 8,
50
+ shadowOpacity: 0.1,
51
+ overflow: 'hidden'
52
+ },
53
+ inputTextArea: {
54
+ borderColor: theme.colors.lightGray,
55
+ borderRadius: 8,
56
+ marginTop: 10,
57
+ marginBottom: 40,
58
+ height: 100,
59
+ alignItems: 'flex-start'
60
+ },
61
+ statusBar: {
62
+ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }],
63
+ height: 10,
64
+ borderRadius: 5,
65
+ marginTop: 5
66
+ },
67
+ ratingItemContainer: {
68
+ position: 'absolute',
69
+ top: -20
70
+ },
71
+ ratingItem: {
72
+ left: '-50%',
73
+ flexDirection: 'column',
74
+ alignItems: 'center'
75
+ },
76
+ ratingLineStyle: {
77
+ height: 10,
78
+ width: 1,
79
+ marginBottom: 10,
80
+ backgroundColor: theme.colors.dusk
81
+ },
82
+ reviewedStyle: {
83
+ flexDirection: 'row',
84
+ justifyContent: 'center',
85
+ marginVertical: 20
86
+ },
87
+ })
88
+
89
+ const [, t] = useLanguage()
90
+ const [, { showToast }] = useToast()
91
+ const { handleSubmit, control, errors } = useForm()
92
+ const [{ parseDate }] = useUtils()
93
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<any>, success?: boolean }>({ open: false, content: [], success: false })
94
+ const [comments, setComments] = useState<Array<any>>([])
95
+ const [extraComment, setExtraComment] = useState('')
96
+ const placedOnDate = parseDate(order?.delivery_datetime, { outputFormat: 'dddd MMMM DD, YYYY' })
97
+
98
+ const onSubmit = () => {
99
+ if (Object.values(stars).some((value: any) => value === 0)) {
100
+ setAlertState({
101
+ open: true,
102
+ content: stars.quality === 0 ? [`${t('REVIEW_QUALIFICATION_REQUIRED', 'Review qualification is required')}`] : []
103
+ })
104
+ return
105
+ }
106
+ setAlertState({ ...alertState, success: true })
107
+ handleSendReview()
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
+ if (index) setStars({ ...stars, quality: index, punctiality: index, service: index, packaging: index, comments: '' })
122
+ setComments([])
123
+ }
124
+
125
+ const handleChangeComment = (commentItem: any) => {
126
+ const found = comments.find((comment: any) => comment?.key === commentItem.key)
127
+ if (found) {
128
+ const _comments = comments.filter((comment: any) => comment?.key !== commentItem.key)
129
+ setComments(_comments)
130
+ } else {
131
+ setComments([...comments, commentItem])
132
+ }
133
+ }
134
+
135
+ const isSelectedComment = (commentKey: number) => {
136
+ const found = comments.find((comment: any) => comment?.key === commentKey)
137
+ return found
138
+ }
139
+
140
+ const handleContinueClick = () => {
141
+ !order?.review && onSubmit()
142
+ }
143
+
144
+ useEffect(() => {
145
+ if (formState.error && !formState?.loading) {
146
+ showToast(ToastType.Error, formState.result)
147
+ }
148
+ if (!formState.loading && !formState.error && alertState.success) {
149
+ showToast(ToastType.Success, t('ORDER_REVIEW_SUCCESS_CONTENT', 'Thank you, Order review successfully submitted!'))
150
+ setIsReviewed && setIsReviewed(true)
151
+ closeReviewOrder && closeReviewOrder()
152
+ }
153
+ }, [formState.result])
154
+
155
+ useEffect(() => {
156
+ if (Object.keys(errors).length > 0) {
157
+ // Convert all errors in one string to show in toast provider
158
+ const list = Object.values(errors);
159
+ let stringError = '';
160
+ list.map((item: any, i: number) => {
161
+ stringError +=
162
+ i + 1 === list.length ? `- ${item.message}` : `- ${item.message}\n`;
163
+ });
164
+ showToast(ToastType.Error, stringError);
165
+ }
166
+ }, [errors])
167
+
168
+ useEffect(() => {
169
+ if (alertState.open) {
170
+ alertState.content && showToast(
171
+ ToastType.Error,
172
+ alertState.content
173
+ )
174
+ }
175
+ }, [alertState.content])
176
+
177
+ useEffect(() => {
178
+ let _comments = ''
179
+ if (comments.length > 0) {
180
+ comments.map(comment => _comments += comment.content + '. ')
181
+ }
182
+ let _comment
183
+ _comment = _comments + extraComment
184
+ setStars({ ...stars, comments: _comment })
185
+ }, [comments, extraComment])
186
+
187
+ return (
188
+ <>
189
+ <ReviewOrderContainer>
190
+ <BusinessLogo>
191
+ <View style={styles.logoWrapper}>
192
+ <OIcon
193
+ url={order?.logo}
194
+ width={80}
195
+ height={80}
196
+ />
197
+ </View>
198
+ </BusinessLogo>
199
+ {!!order?.business_name && <OText style={{ textAlign: 'center', marginTop: 15 }} color={theme.colors.textNormal}>{order?.business_name}</OText>}
200
+ {order?.review ? (
201
+ <View style={styles.reviewedStyle}>
202
+ <OText color={theme.colors.primary}>{t('ORDER_REVIEWED', 'This order has been already reviewed')}</OText>
203
+ </View>
204
+ ) : (
205
+ <View style={{ flex: 1, justifyContent: 'flex-end' }}>
206
+ <FormReviews>
207
+ {/* <OText mBottom={13} color={theme.colors.textNormal}>{t('HOW_WAS_YOUR_ORDER', 'How was your order?')}</OText> */}
208
+ {false && (
209
+ <RatingBarContainer>
210
+ <LinearGradient
211
+ start={{ x: 0.0, y: 0.0 }}
212
+ end={{ x: qualificationList[stars.quality - 1]?.percent || 0, y: 0 }}
213
+ locations={[.9999, .9999]}
214
+ colors={[theme.colors.primary, theme.colors.backgroundGray200]}
215
+ style={styles.statusBar}
216
+ />
217
+ <RatingTextContainer>
218
+ {qualificationList.map((qualification: any) => (
219
+ <View
220
+ key={qualification.key}
221
+ style={{ ...qualification.parentStyle, ...styles.ratingItemContainer }}
222
+ >
223
+ <TouchableOpacity
224
+ style={qualification.isInnerStyle && styles.ratingItem}
225
+ onPress={() => handleChangeStars(qualification.key)}
226
+ >
227
+ <View
228
+ style={{
229
+ ...styles.ratingLineStyle,
230
+ backgroundColor: (qualification.pointerColor && !(stars.quality >= qualification.key)) ? theme.colors.dusk : 'transparent'
231
+ }}
232
+ />
233
+ <OText size={12} color={stars.quality === qualification.key ? theme.colors.black : theme.colors.backgroundGray200}>{qualification.text}</OText>
234
+ </TouchableOpacity>
235
+ </View>
236
+ ))}
237
+ </RatingTextContainer>
238
+ </RatingBarContainer>
239
+ )}
240
+ <RatingStarContainer>
241
+ {[...Array(5).keys()].map((index) => (<FontAwesome name={(index <= (stars?.quality - 1)) ? 'star' : 'star-o'} size={28} key={`star-symbol-${index}`} onPress={() => handleChangeStars(index + 1)} color={theme?.colors?.primary} />)
242
+ )}
243
+ </RatingStarContainer>
244
+ <PlacedDate>
245
+ <OText color={theme.colors.textNormal}>{t('DONOT_FORGET_RATE_YOUR_ORDER', 'Do not forget to rate your order placed on ')}</OText>
246
+ <OText color={theme.colors.textNormal} style={{ fontWeight: "bold" }}>{placedOnDate}</OText>
247
+ </PlacedDate>
248
+ {false && (
249
+ <>
250
+ <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>
251
+ {commentsList[stars?.quality || 1]?.title}
252
+ </OText>
253
+ <CommentsButtonGroup>
254
+ {commentsList[stars?.quality || 1]?.list?.map((commentItem: any) => (
255
+ <OButton
256
+ key={commentItem.key}
257
+ text={commentItem.content}
258
+ bgColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
259
+ borderColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.backgroundGray200}
260
+ textStyle={{
261
+ color: isSelectedComment(commentItem.key) ? theme.colors.white : theme.colors.black,
262
+ fontSize: 13,
263
+ paddingRight: isSelectedComment(commentItem.key) ? 15 : 0
264
+ }}
265
+ style={{ height: 35, paddingLeft: 5, paddingRight: 5, marginHorizontal: 3, marginVertical: 10 }}
266
+ imgRightSrc={isSelectedComment(commentItem.key) ? theme.images.general.close : null}
267
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
268
+ onClick={() => handleChangeComment(commentItem)}
269
+ />
270
+ ))}
271
+ </CommentsButtonGroup>
272
+ </>
273
+ )}
274
+ {/* <OText style={{ marginTop: 30 }} color={theme.colors.textNormal}>{t('REVIEW_COMMENT_QUESTION', 'Do you want to add something?')}</OText> */}
275
+ {false && (
276
+ <Controller
277
+ control={control}
278
+ defaultValue=''
279
+ name='comments'
280
+ render={({ onChange }: any) => (
281
+ <OInput
282
+ name='comments'
283
+ onChange={(val: any) => {
284
+ onChange(val)
285
+ setExtraComment(val.target.value)
286
+ }}
287
+ style={styles.inputTextArea}
288
+ multiline
289
+ />
290
+ )}
291
+ />
292
+ )}
293
+ </FormReviews>
294
+ </View>
295
+ )}
296
+ <Spinner visible={formState.loading} />
297
+ </ReviewOrderContainer>
298
+ <FloatingBottomContainer>
299
+ <ActionContainer>
300
+ <SkipButton
301
+ onPress={skipReview}
302
+ >
303
+ <OText weight={700} size={18} color={theme.colors.textNormal}>{t('FRONT_VISUALS_SKIP', 'Skip')}</OText>
304
+ </SkipButton>
305
+ <OButton
306
+ textStyle={{ color: theme.colors.white, paddingRight: 10 }}
307
+ text={t('CONTINUE_REVIEW', 'Continue Review')}
308
+ style={{ borderRadius: 8 }}
309
+ imgRightSrc={theme.images.general.arrow_right}
310
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
311
+ onClick={handleSubmit(handleContinueClick)}
312
+ />
313
+ </ActionContainer>
314
+ </FloatingBottomContainer>
315
+ </>
316
+ )
317
+ }
318
+
319
+ export const ReviewOrder = (props: ReviewOrderParams) => {
320
+ const reviewOrderProps = {
321
+ ...props,
322
+ UIComponent: ReviewOrderUI,
323
+ defaultStar: 5
324
+ }
325
+ return <ReviewOrderController {...reviewOrderProps} />
326
+ }
@@ -0,0 +1,53 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const ReviewOrderContainer = styled.ScrollView`
4
+ padding: 20px 40px;
5
+ margin-bottom: 100px;
6
+ `
7
+
8
+ export const BusinessLogo = styled.View`
9
+ margin-vertical: 5px;
10
+ align-items: center;
11
+ `
12
+
13
+ export const FormReviews = styled.View`
14
+ flex: 1;
15
+ height: 100%;
16
+ margin-top: 30px;
17
+ `
18
+
19
+ export const CommentsButtonGroup = styled.View`
20
+ flex-direction: row;
21
+ flex-wrap: wrap;
22
+ `
23
+
24
+ export const ActionContainer = styled.View`
25
+ flex-direction: row;
26
+ align-items: center;
27
+ justify-content: space-between;
28
+ padding: 3px 30px;
29
+ `
30
+
31
+ export const SkipButton = styled.TouchableOpacity`
32
+ `
33
+
34
+ export const RatingBarContainer = styled.View`
35
+ margin-top: 10px;
36
+ margin-bottom: 25px;
37
+ `
38
+
39
+ export const RatingTextContainer = styled.View`
40
+ flex-direction: row;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ margin-top: 10px;
44
+ `
45
+ export const RatingStarContainer = styled.View`
46
+ flex-direction: row;
47
+ align-items: center;
48
+ justify-content: space-between;
49
+ margin-top: 10px;
50
+ `
51
+ export const PlacedDate = styled.View`
52
+ margin-top: 30px;
53
+ `
@@ -0,0 +1,101 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { useLanguage, useToast, ToastType, ReviewProduct as ReviewProductController } from 'ordering-components/native'
3
+ import { OText, OButton } from '../../shared'
4
+ import { ReviewProductParams } from '../../../types'
5
+ import { FloatingBottomContainer } from '../../../layouts/FloatingBottomContainer'
6
+ import { useTheme } from 'styled-components/native'
7
+ import { SingleProductReview } from '../../SingleProductReview'
8
+
9
+ import {
10
+ ReviewProductsContainer,
11
+ ActionContainer,
12
+ SkipButton
13
+ } from './styles'
14
+
15
+ const ReviewProductsUI = (props: ReviewProductParams) => {
16
+ const {
17
+ navigation,
18
+ order,
19
+ formState,
20
+ handleChangeFormState,
21
+ handleSendProductReview,
22
+ closeReviewProduct
23
+ } = props
24
+
25
+ const [, t] = useLanguage()
26
+ const theme = useTheme()
27
+ const [, { showToast }] = useToast()
28
+
29
+ const [isProductReviewed, setIsProductReviewed] = useState(false)
30
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<any>, success?: boolean }>({ open: false, content: [], success: false })
31
+
32
+ const handleContinueClick = () => {
33
+ setAlertState({ ...alertState, success: true })
34
+ handleSendProductReview()
35
+ }
36
+ useEffect(() => {
37
+ if (alertState.open) {
38
+ alertState.content && showToast(
39
+ ToastType.Error,
40
+ alertState.content
41
+ )
42
+ }
43
+ }, [alertState.content])
44
+
45
+ useEffect(() => {
46
+ if (!formState.loading && formState.result?.error) {
47
+ setAlertState({
48
+ open: true,
49
+ success: false,
50
+ content: formState.result?.result || [t('ERROR', 'Error')]
51
+ })
52
+ }
53
+ if (!formState.loading && !formState.result?.error && alertState.success) {
54
+ setIsProductReviewed && setIsProductReviewed(true)
55
+ closeReviewProduct && closeReviewProduct()
56
+ }
57
+ }, [formState])
58
+
59
+ return (
60
+ <>
61
+ <ReviewProductsContainer>
62
+ {order?.products?.map((product: any) => (
63
+ <SingleProductReview
64
+ key={product.id}
65
+ product={product}
66
+ formState={formState}
67
+ handleChangeFormState={handleChangeFormState}
68
+ />
69
+ ))}
70
+ </ReviewProductsContainer>
71
+
72
+ <FloatingBottomContainer>
73
+ <ActionContainer>
74
+ <SkipButton
75
+ onPress={() => closeReviewProduct && closeReviewProduct()}
76
+ >
77
+ <OText weight={700} size={18} color={theme.colors.textNormal}>{t('FRONT_VISUALS_SKIP', 'Skip')}</OText>
78
+ </SkipButton>
79
+ <OButton
80
+ textStyle={{ color: theme.colors.white, paddingRight: 10 }}
81
+ text={order?.driver && !order?.user_review ? t('CONTINUE', 'Continue') : t('SEND_REVIEW', 'Send Review')}
82
+ style={{ borderRadius: 8 }}
83
+ imgRightSrc={theme.images.general.arrow_right}
84
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
85
+ isDisabled={formState.loading || formState?.changes?.length === 0}
86
+ onClick={() => handleContinueClick()}
87
+ />
88
+ </ActionContainer>
89
+ </FloatingBottomContainer>
90
+ </>
91
+ )
92
+ }
93
+
94
+ export const ReviewProducts = (props: any) => {
95
+ const reviewProductProps = {
96
+ ...props,
97
+ UIComponent: ReviewProductsUI,
98
+ isToast: true
99
+ }
100
+ return <ReviewProductController {...reviewProductProps} />
101
+ }
@@ -0,0 +1,17 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const ReviewProductsContainer = styled.ScrollView`
4
+ padding: 20px 40px;
5
+ margin-bottom: 100px;
6
+ max-height: 400px;
7
+ `
8
+
9
+ export const ActionContainer = styled.View`
10
+ flex-direction: row;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+ padding: 3px 30px;
14
+ `
15
+
16
+ export const SkipButton = styled.TouchableOpacity`
17
+ `
@@ -0,0 +1,9 @@
1
+ import { ReviewOrder as ReviewOrderModal } from './ReviewOrder';
2
+ import { ReviewProducts as ReviewProductsModal } from './ReviewProducts';
3
+ import { ReviewDriver as ReviewDriverModal } from './ReviewDriver';
4
+
5
+ export {
6
+ ReviewOrderModal,
7
+ ReviewProductsModal,
8
+ ReviewDriverModal
9
+ }
@@ -65,8 +65,8 @@ const ServiceFormUI = (props: ServiceFormParams) => {
65
65
 
66
66
  const styles = StyleSheet.create({
67
67
  photoStyle: {
68
- width: 42,
69
- height: 42,
68
+ width: 45,
69
+ height: 45,
70
70
  borderRadius: 7.6
71
71
  },
72
72
  buttonStyle: {
@@ -313,12 +313,14 @@ const ServiceFormUI = (props: ServiceFormParams) => {
313
313
  <OText
314
314
  size={14}
315
315
  weight={'400'}
316
+ lineHeight={22}
316
317
  >
317
318
  {currentProfessional?.name} {currentProfessional?.lastname}
318
319
  </OText>
319
320
  <OText
320
321
  size={12}
321
322
  weight={'400'}
323
+ lineHeight={17}
322
324
  color={isBusyTime(currentProfessional) ? theme.colors.danger5 : theme.colors.success500}
323
325
  >
324
326
  {isBusyTime(currentProfessional)
@@ -459,9 +461,7 @@ const ServiceFormUI = (props: ServiceFormParams) => {
459
461
  size={14}
460
462
  weight={Platform.OS === 'ios' ? '600' : 'bold'}
461
463
  >
462
- {dateSelected
463
- ? moment(dateSelected).format('hh:mm A')
464
- : t('ASAP_ABBREVIATION', 'ASAP')}
464
+ {dateSelected && moment(dateSelected).format('hh:mm A')}
465
465
  </OText>
466
466
  {((productCart &&
467
467
  auth &&
@@ -517,6 +517,14 @@ const ServiceFormUI = (props: ServiceFormParams) => {
517
517
  entireModal
518
518
  >
519
519
  <ScrollView contentContainerStyle={styles.professionalList}>
520
+ <View style={{ padding: 11 }}>
521
+ <OText
522
+ size={14}
523
+ weight={'400'}
524
+ >
525
+ {t('ANY_OROFESSIONAL_MEMBER', 'Any professional member')}
526
+ </OText>
527
+ </View>
520
528
  {professionalList?.map((professional: any) => professional?.products?.includes(product?.id) && (
521
529
  <TouchableOpacity
522
530
  key={professional?.id}
@@ -536,12 +544,14 @@ const ServiceFormUI = (props: ServiceFormParams) => {
536
544
  <OText
537
545
  size={14}
538
546
  weight={'400'}
547
+ lineHeight={22}
539
548
  >
540
549
  {professional?.name} {professional?.lastname}
541
550
  </OText>
542
551
  <OText
543
552
  size={12}
544
553
  weight={'400'}
554
+ lineHeight={17}
545
555
  color={isBusyTime(professional) ? theme.colors.danger5 : theme.colors.success500}
546
556
  >
547
557
  {isBusyTime(professional)
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
- import { Modal, TouchableWithoutFeedback, Dimensions, StyleSheet, View, Text, Platform, StatusBar } from 'react-native'
2
+ import { Modal, TouchableWithoutFeedback, TouchableOpacity, Dimensions, StyleSheet, View, Text, Platform, StatusBar } from 'react-native'
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
+ import { OIcon } from '.';
4
5
  const deviceHeight = Dimensions.get('window').height
5
6
 
6
7
  interface Props {
@@ -9,6 +10,9 @@ interface Props {
9
10
  children?: any;
10
11
  onClose?: any;
11
12
  isStatusBar?: boolean;
13
+ bottomContainerStyle?: any;
14
+ titleStyle?: any;
15
+ closeIcon?: any;
12
16
  }
13
17
  const OBottomPopup = (props: Props) => {
14
18
  const {
@@ -16,7 +20,10 @@ const OBottomPopup = (props: Props) => {
16
20
  title,
17
21
  onClose,
18
22
  children,
19
- isStatusBar
23
+ isStatusBar,
24
+ titleStyle,
25
+ bottomContainerStyle,
26
+ closeIcon
20
27
  } = props
21
28
  const { top, bottom } = useSafeAreaInsets();
22
29
  return (
@@ -27,7 +34,7 @@ const OBottomPopup = (props: Props) => {
27
34
  onRequestClose={() => onClose()}
28
35
  presentationStyle={'fullScreen'}
29
36
  >
30
- {isStatusBar && <StatusBar translucent={false} />}
37
+ {isStatusBar && <StatusBar translucent={false} />}
31
38
  <View style={styles.container}>
32
39
  <TouchableWithoutFeedback
33
40
  style={styles.touchableOutsideStyle}
@@ -35,10 +42,18 @@ const OBottomPopup = (props: Props) => {
35
42
  >
36
43
  <View style={styles.touchableOutsideStyle} />
37
44
  </TouchableWithoutFeedback>
38
- <View style={styles.bottomContainer}>
45
+ <View style={{ ...styles.bottomContainer, ...bottomContainerStyle }}>
39
46
  <View style={{ paddingTop: top, paddingBottom: bottom }}>
40
- {title != '' && (
41
- <Text style={styles.titleStyle}>
47
+ {closeIcon && (
48
+ <TouchableOpacity onPress={onClose} style={styles.closeIconStyle}>
49
+ <OIcon
50
+ src={closeIcon}
51
+ width={30}
52
+ />
53
+ </TouchableOpacity>
54
+ )}
55
+ {!!title && (
56
+ <Text style={{ ...styles.titleStyle, ...titleStyle }}>
42
57
  {title}
43
58
  </Text>
44
59
  )}
@@ -69,7 +84,11 @@ const styles = StyleSheet.create({
69
84
  titleStyle: {
70
85
  fontSize: 20,
71
86
  fontWeight: 'bold',
72
- marginVertical: 15
87
+ marginVertical: 10
88
+ },
89
+ closeIconStyle: {
90
+ paddingTop: 20,
91
+ paddingLeft: 20
73
92
  }
74
93
  })
75
94
 
@@ -417,25 +417,28 @@ export interface ProductItemAccordionParams {
417
417
  isFromCheckout?: any
418
418
  }
419
419
  export interface ReviewOrderParams {
420
- order?: { id: number, businessId: number, business_name?: string, delivery_datetime?: string, logo: string, driver: any, products: Array<any>, review: any, user_review: any },
421
- stars?: any,
422
- handleChangeInput?: any,
423
- handleChangeRating?: any,
424
- handleSendReview?: any,
425
- formState?: any,
426
- navigation?: any,
427
- setIsReviewed?: (isReviewed: boolean) => {},
428
- handleReviewState?: any,
429
- setStars?: any,
430
- onNavigationRedirect?: any
420
+ order?: { id: number, business_id: number, business_name?: string, delivery_datetime?: string, logo: string, driver: any, products: Array<any>, review: any, user_review: any };
421
+ stars?: any;
422
+ handleChangeInput?: any;
423
+ handleChangeRating?: any;
424
+ handleSendReview?: any;
425
+ formState?: any;
426
+ navigation?: any;
427
+ setIsReviewed?: (isReviewed: boolean) => void;
428
+ handleReviewState?: any;
429
+ setStars?: any;
430
+ onNavigationRedirect?: any;
431
+ closeReviewOrder?: () => void;
432
+ skipReview?: () => void;
431
433
  }
432
434
  export interface ReviewProductParams {
433
435
  navigation?: any,
434
436
  onNavigationRedirect?: any,
435
- order?: { orderId: number, businessId: number, logo: string, driver: any, products: Array<any>, review: any, user_review: any },
437
+ order?: { orderId: number, business_id: number, logo: string, driver: any, products: Array<any>, review: any, user_review: any },
436
438
  formState?: any,
437
439
  handleChangeFormState?: any,
438
- handleSendProductReview?: any
440
+ handleSendProductReview?: any;
441
+ closeReviewProduct?: () => void;
439
442
  }
440
443
  export interface SingleProductReviewParams {
441
444
  product: any,
@@ -445,12 +448,13 @@ export interface SingleProductReviewParams {
445
448
  export interface ReviewDriverParams {
446
449
  navigation?: any,
447
450
  onNavigationRedirect?: any,
448
- order?: { orderId: number, businessId: number, logo: string, driver: any, products: Array<any>, review: any, user_review: any },
451
+ order?: { orderId: number, business_id: number, logo: string, driver: any, products: Array<any>, review: any, user_review: any },
449
452
  formState?: any,
450
453
  setIsDriverReviewed?: (isReviewed: boolean) => {},
451
454
  dirverReviews?: any,
452
455
  setDriverReviews?: any,
453
- handleSendDriverReview?: any
456
+ handleSendDriverReview?: any;
457
+ closeReviewDriver?: () => void;
454
458
  }
455
459
  export interface MessagesParams {
456
460
  type?: string,