ordering-ui-react-native 0.12.27 → 0.12.28

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.12.27",
3
+ "version": "0.12.28",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -27,6 +27,7 @@ import { PhoneInputNumber } from './src/components/PhoneInputNumber';
27
27
  import { PreviousMessages } from './src/components/PreviousMessages';
28
28
  import { PreviousOrders } from './src/components/PreviousOrders';
29
29
  import { ProductItemAccordion } from './src/components/ProductItemAccordion';
30
+ import { ReviewCustomer } from './src/components/ReviewCustomer'
30
31
  import { SearchBar } from './src/components/SearchBar';
31
32
  import { SignupForm } from './src/components/SignupForm';
32
33
  import { StoresList } from './src/components/StoresList';
@@ -91,6 +92,7 @@ export {
91
92
  PreviousMessages,
92
93
  PreviousOrders,
93
94
  ProductItemAccordion,
95
+ ReviewCustomer,
94
96
  SafeAreaContainerLayout,
95
97
  SearchBar,
96
98
  SignupForm,
@@ -1,8 +1,8 @@
1
- import React from 'react'
1
+ import React, { useState } from 'react'
2
2
 
3
3
  import { Platform, StyleSheet, View } from 'react-native';
4
4
 
5
- import { OText, OLink } from '../shared'
5
+ import { OButton, OText, OLink, OModal } from '../shared'
6
6
  import {
7
7
  OrderContent,
8
8
  OrderBusiness,
@@ -23,7 +23,7 @@ import {
23
23
  useConfig,
24
24
  } from 'ordering-components/native';
25
25
  import { useTheme } from 'styled-components/native';
26
-
26
+ import { ReviewCustomer } from '../ReviewCustomer'
27
27
 
28
28
  interface OrderContent {
29
29
  order: any
@@ -37,6 +37,10 @@ export const OrderContentComponent = (props: OrderContent) => {
37
37
 
38
38
  const [{ parsePrice, parseNumber }] = useUtils();
39
39
  const [{ configs }] = useConfig();
40
+ const [openReviewModal, setOpenReviewModal] = useState(false)
41
+ const [isCustomerReviewed, setIsCustomerReviewed] = useState(false)
42
+
43
+ const pastOrderStatuses = [1, 2, 5, 6, 10, 11, 12, 16, 17]
40
44
 
41
45
  const styles = StyleSheet.create({
42
46
  linkWithIcons: {
@@ -51,8 +55,18 @@ export const OrderContentComponent = (props: OrderContent) => {
51
55
  },
52
56
  textLink: {
53
57
  color: '#365CC7'
58
+ },
59
+ btnReview: {
60
+ borderWidth: 0,
61
+ backgroundColor: theme.colors.primary,
62
+ borderRadius: 8,
54
63
  }
55
64
  })
65
+
66
+ const handleSuccessReviewed = () => {
67
+ setOpenReviewModal(false)
68
+ setIsCustomerReviewed(true)
69
+ }
56
70
  return (
57
71
  <OrderContent>
58
72
  <OrderBusiness>
@@ -232,6 +246,16 @@ export const OrderContentComponent = (props: OrderContent) => {
232
246
  {order?.customer?.zipcode}
233
247
  </OText>
234
248
  )}
249
+
250
+ {!order?.user_review && pastOrderStatuses.includes(order?.status) && !isCustomerReviewed && (
251
+ <OButton
252
+ style={styles.btnReview}
253
+ textStyle={{ color: theme.colors.white }}
254
+ text={t('REVIEW_CUSTOMER', 'Review customer')}
255
+ imgRightSrc={false}
256
+ onClick={() => setOpenReviewModal(true)}
257
+ />
258
+ )}
235
259
  </OrderCustomer>
236
260
 
237
261
  <OrderProducts>
@@ -386,6 +410,19 @@ export const OrderContentComponent = (props: OrderContent) => {
386
410
  </Table>
387
411
  </Total>
388
412
  </OrderBill>
413
+
414
+ <OModal
415
+ open={openReviewModal}
416
+ onClose={() => setOpenReviewModal(false)}
417
+ entireModal
418
+ customClose
419
+ >
420
+ <ReviewCustomer
421
+ order={order}
422
+ closeModal={() => setOpenReviewModal(false)}
423
+ onClose={() => handleSuccessReviewed()}
424
+ />
425
+ </OModal>
389
426
  </OrderContent>
390
427
  )
391
428
  }
@@ -0,0 +1,314 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import {
3
+ useLanguage,
4
+ useUtils,
5
+ ReviewCustomer as ReviewCustomerController
6
+ } from 'ordering-components/native'
7
+ import {
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ View,
11
+ StyleSheet,
12
+ I18nManager,
13
+ TouchableOpacity
14
+ } from 'react-native'
15
+ import { useTheme } from 'styled-components/native'
16
+ import { ReviewCustomerParams } from '../../types'
17
+ import { OButton, OText, OIconButton, OIcon, OInput } from '../shared'
18
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
19
+ import { FloatingButton } from '../FloatingButton'
20
+ import LinearGradient from 'react-native-linear-gradient'
21
+ import Alert from '../../providers/AlertProvider'
22
+
23
+ import {
24
+ Content,
25
+ ActionButtonWrapper,
26
+ CustomerInfoContainer,
27
+ RatingBarContainer,
28
+ RatingTextContainer,
29
+ CommentsButtonGroup
30
+ } from './styles'
31
+
32
+ const ReviewCustomerUI = (props: ReviewCustomerParams) => {
33
+ const {
34
+ order,
35
+ closeModal,
36
+ reviewState,
37
+ setReviewState,
38
+ actionState,
39
+ handleChangeQualification,
40
+ handleSendCustomerReview
41
+ } = props
42
+
43
+ const theme = useTheme()
44
+ const [, t] = useLanguage()
45
+ const [{ optimizeImage }] = useUtils()
46
+ const [alertState, setAlertState] = useState<{
47
+ open: boolean;
48
+ content: Array<string>;
49
+ key?: string | null;
50
+ }>({ open: false, content: [] })
51
+ const { top, bottom } = useSafeAreaInsets()
52
+ const [comments, setComments] = useState<Array<any>>([])
53
+ const [extraComment, setExtraComment] = useState('')
54
+
55
+ const styles = StyleSheet.create({
56
+ photoWrapper: {
57
+ shadowColor: theme.colors.black,
58
+ shadowRadius: 3,
59
+ shadowOffset: {width: 1, height: 4},
60
+ elevation: 3,
61
+ borderRadius: 8,
62
+ shadowOpacity: 0.1,
63
+ overflow: 'hidden'
64
+ },
65
+ statusBar: {
66
+ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }],
67
+ height: 8,
68
+ borderRadius: 5,
69
+ marginTop: 5
70
+ },
71
+ ratingItemContainer: {
72
+ position: 'absolute',
73
+ top: -18
74
+ },
75
+ ratingItem: {
76
+ left: '-50%',
77
+ flexDirection: 'column',
78
+ alignItems: 'center'
79
+ },
80
+ ratingLineStyle: {
81
+ height: 8,
82
+ width: 1,
83
+ marginBottom: 10,
84
+ backgroundColor: theme.colors.lightGray
85
+ },
86
+ inputTextArea: {
87
+ borderColor: theme.colors.lightGray,
88
+ borderRadius: 8,
89
+ marginTop: 10,
90
+ marginBottom: 40,
91
+ height: 100,
92
+ alignItems: 'flex-start'
93
+ }
94
+ })
95
+
96
+ const qualificationList = [
97
+ { key: 1, text: t('TERRIBLE', 'Terrible'), percent: 0, parentStyle: { left: '0%' }, isInnerStyle: false, pointerColor: false },
98
+ { key: 2, text: t('BAD', 'Bad'), percent: 0.25, parentStyle: { left: '25%' }, isInnerStyle: true, pointerColor: true },
99
+ { key: 3, text: t('OKAY', 'Okay'), percent: 0.5, parentStyle: { left: '50%' }, isInnerStyle: true, pointerColor: true },
100
+ { key: 4, text: t('GOOD', 'Good'), percent: 0.75, parentStyle: { left: '75%' }, isInnerStyle: true, pointerColor: true },
101
+ { key: 5, text: t('GREAT', 'Great'), percent: 1, parentStyle: { right: '0%' }, isInnerStyle: false, pointerColor: false }
102
+ ]
103
+
104
+ const commentsList = [
105
+ { key: 0, content: t('RESPECTFUL', 'Respectful') },
106
+ { key: 1, content: t('EXCELLENT_COMMUNICATION', "Excellent communication") },
107
+ { key: 2, content: t('CORDIAL_SERVICE', 'Cordial service') }
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
+ useEffect(() => {
125
+ let _comments = ''
126
+ if (comments.length > 0) {
127
+ comments.map((comment: any) => (_comments += comment.content + '. '))
128
+ }
129
+ const _comment = _comments + extraComment
130
+ setReviewState({ ...reviewState, comment: _comment })
131
+ }, [comments, extraComment])
132
+
133
+ useEffect(() => {
134
+ if (!actionState.error) return
135
+ setAlertState({
136
+ open: true,
137
+ content: actionState.error
138
+ })
139
+
140
+ }, [actionState.error])
141
+
142
+ return (
143
+ <KeyboardAvoidingView
144
+ enabled
145
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
146
+ style={{
147
+ flex: 1,
148
+ paddingHorizontal: 30,
149
+ paddingTop: 28,
150
+ marginTop: top,
151
+ marginBottom: bottom,
152
+ justifyContent: 'space-between'
153
+ }}
154
+ >
155
+ <View>
156
+ <OIconButton
157
+ icon={theme.images.general.arrow_left}
158
+ borderColor={theme.colors.clear}
159
+ iconStyle={{ width: 20, height: 16 }}
160
+ style={{
161
+ maxWidth: 40,
162
+ height: 20,
163
+ justifyContent: 'flex-end',
164
+ marginBottom: 20,
165
+ }}
166
+ onClick={() => closeModal()}
167
+ />
168
+ <OText
169
+ size={20}
170
+ weight="600"
171
+ >
172
+ {t('REVIEW_CUSTOMER', 'Review customer')}
173
+ </OText>
174
+ </View>
175
+
176
+ <Content
177
+ showsVerticalScrollIndicator={false}
178
+ contentContainerStyle={{ paddingBottom: 30 }}
179
+ >
180
+ <CustomerInfoContainer>
181
+ <View
182
+ style={{
183
+ ...styles.photoWrapper,
184
+ backgroundColor: theme.colors.white,
185
+ padding: !order?.customer?.photo ? 5 : 0
186
+ }}
187
+ >
188
+ <OIcon
189
+ url={optimizeImage(order?.customer?.photo, 'h_100,c_limit')}
190
+ src={!order?.customer?.photo && theme.images.general.user}
191
+ width={72}
192
+ height={72}
193
+ style={{ borderRadius: 7.6 }}
194
+ />
195
+ </View>
196
+ <OText
197
+ size={14}
198
+ weight="500"
199
+ style={{
200
+ marginTop: 16
201
+ }}
202
+ >
203
+ {order?.customer?.name} {order?.customer?.middle_name} {order?.customer?.lastname} {order?.customer?.second_lastname}
204
+ </OText>
205
+ </CustomerInfoContainer>
206
+ <OText
207
+ size={12}
208
+ >
209
+ {t('HOW_WAS_YOUR_CUSTOMER', 'How was your experience with _name_?').replace('_name_', `${order?.customer?.name} ${order?.customer?.middle_name} ${order?.customer?.lastname} ${order?.customer?.second_lastname}`)}
210
+ </OText>
211
+ <RatingBarContainer>
212
+ <LinearGradient
213
+ start={{ x: 0.0, y: 0.0 }}
214
+ end={{ x: qualificationList[reviewState?.qualification - 1]?.percent || 0, y: 0 }}
215
+ locations={[.9999, .9999]}
216
+ colors={[theme.colors.primary, theme.colors.tabBar]}
217
+ style={styles.statusBar}
218
+ />
219
+ <RatingTextContainer>
220
+ {qualificationList.map((qualification: any) => (
221
+ <View
222
+ key={qualification.key}
223
+ style={{ ...qualification.parentStyle, ...styles.ratingItemContainer }}
224
+ >
225
+ <TouchableOpacity
226
+ style={qualification.isInnerStyle && styles.ratingItem}
227
+ onPress={() => handleChangeQualification(qualification.key)}
228
+ >
229
+ <View
230
+ style={{
231
+ ...styles.ratingLineStyle,
232
+ backgroundColor: (qualification.pointerColor && !(reviewState?.qualification >= qualification.key)) ? theme.colors.dusk : 'transparent'
233
+ }}
234
+ />
235
+ <OText
236
+ size={12}
237
+ color={
238
+ reviewState?.qualification === qualification.key
239
+ ? theme.colors.darkText
240
+ : theme.colors.lightGray
241
+ }
242
+ >
243
+ {qualification.text}
244
+ </OText>
245
+ </TouchableOpacity>
246
+ </View>
247
+ ))}
248
+ </RatingTextContainer>
249
+ </RatingBarContainer>
250
+ <OText
251
+ size={12}
252
+ style={{ marginTop: 30 }}
253
+ >
254
+ {t('COMMENTS', 'Comments')}
255
+ </OText>
256
+ <CommentsButtonGroup>
257
+ {commentsList.map(commentItem => (
258
+ <OButton
259
+ key={commentItem.key}
260
+ text={commentItem.content}
261
+ bgColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.tabBar}
262
+ borderColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.tabBar}
263
+ textStyle={{
264
+ color: isSelectedComment(commentItem.key) ? theme.colors.white : theme.colors.darkText,
265
+ fontSize: 12,
266
+ paddingRight: isSelectedComment(commentItem.key) ? 15 : 0
267
+ }}
268
+ style={{ height: 35, paddingLeft: 5, paddingRight: 5, marginHorizontal: 3, marginVertical: 10 }}
269
+ imgRightSrc={isSelectedComment(commentItem.key) ? theme.images.general.close : null}
270
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
271
+ onClick={() => handleChangeComment(commentItem) }
272
+ />
273
+ ))}
274
+ </CommentsButtonGroup>
275
+ <OText
276
+ size={12}
277
+ style={{ marginTop: 30 }}
278
+ >
279
+ {t('REVIEW_COMMENT_QUESTION', 'Do you want to add something?')}
280
+ </OText>
281
+ <OInput
282
+ name='comments'
283
+ onChange={(val: any) => setExtraComment(val.target.value)}
284
+ style={styles.inputTextArea}
285
+ multiline
286
+ />
287
+ </Content>
288
+
289
+ <ActionButtonWrapper>
290
+ <FloatingButton
291
+ firstButtonClick={() => handleSendCustomerReview()}
292
+ btnText={actionState.loading ? t('LOADING', 'Loading') : t('SEND_REVIEW', 'Send Review')}
293
+ color={theme.colors.primary}
294
+ widthButton={'100%'}
295
+ />
296
+ </ActionButtonWrapper>
297
+ <Alert
298
+ open={alertState.open}
299
+ onAccept={() => setAlertState({ open: false, content: [] })}
300
+ onClose={() => setAlertState({ open: false, content: [] })}
301
+ content={alertState.content}
302
+ title={t('ERROR', 'Error')}
303
+ />
304
+ </KeyboardAvoidingView>
305
+ )
306
+ }
307
+
308
+ export const ReviewCustomer = (props: any) => {
309
+ const reviewCustomerProps = {
310
+ ...props,
311
+ UIComponent: ReviewCustomerUI
312
+ }
313
+ return <ReviewCustomerController {...reviewCustomerProps} />
314
+ }
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const Content = styled.ScrollView`
4
+ background-color: ${(props: any) => props.theme.colors.white};
5
+ margin-bottom: 30px;
6
+ `;
7
+ export const ActionButtonWrapper = styled.View`
8
+ margin-bottom: 10px;
9
+ `
10
+ export const CustomerInfoContainer = styled.View`
11
+ flex-direction: column;
12
+ align-items: center;
13
+ margin: 25px 0;
14
+ `
15
+ export const RatingBarContainer = styled.View`
16
+ margin-top: 13px;
17
+ margin-bottom: 25px;
18
+ `
19
+ export const RatingTextContainer = styled.View`
20
+ flex-direction: row;
21
+ align-items: center;
22
+ justify-content: space-between;
23
+ margin-top: 10px;
24
+ `
25
+ export const CommentsButtonGroup = styled.View`
26
+ flex-direction: row;
27
+ flex-wrap: wrap;
28
+ `
@@ -556,3 +556,13 @@ export interface MapViewParams {
556
556
  alertState: { open: boolean, content: Array<string>, key?: string | null },
557
557
  setAlertState: ({open, content, key} : { open: boolean, content: Array<string>, key?: string | null }) => void
558
558
  }
559
+
560
+ export interface ReviewCustomerParams {
561
+ order?: any,
562
+ closeModal?: any,
563
+ reviewState?: any,
564
+ setReviewState?: any,
565
+ actionState?: any,
566
+ handleChangeQualification?: any,
567
+ handleSendCustomerReview?: any,
568
+ }