ordering-ui-react-native 0.17.35-release → 0.17.36-release

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.17.35-release",
3
+ "version": "0.17.36-release",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -5,146 +5,168 @@ import WebView from 'react-native-webview';
5
5
  import { ActivityIndicator } from 'react-native-paper';
6
6
 
7
7
  import {
8
- ToastType,
9
- useToast,
10
- useApi,
11
- useLanguage,
12
- useConfig
8
+ ToastType,
9
+ useToast,
10
+ useApi,
11
+ useLanguage,
12
+ useConfig,
13
+ useOrder
13
14
  } from 'ordering-components/native';
14
15
 
15
16
  import { OText } from '../shared';
16
17
 
17
18
  interface PaymentOptionsWebViewParams {
18
- onNavigationRedirect?: Function,
19
- uri?: any,
20
- user?: any,
21
- token?: any,
22
- cart?: any,
23
- currency?: any,
24
- webviewPaymethod?: any,
25
- setShowGateway?: any,
26
- setOpenOrderCreating?: any,
27
- locationId?: any
19
+ onNavigationRedirect?: Function,
20
+ uri?: any,
21
+ user?: any,
22
+ token?: any,
23
+ cart?: any,
24
+ currency?: any,
25
+ webviewPaymethod?: any,
26
+ setShowGateway?: any,
27
+ setOpenOrderCreating?: any,
28
+ locationId?: any,
29
+ additionalParams?: any
30
+ title?: string
28
31
  }
29
32
  export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
30
- const {
31
- onNavigationRedirect,
32
- uri,
33
- user,
34
- token,
35
- cart,
36
- currency,
37
- webviewPaymethod,
38
- setShowGateway,
39
- setOpenOrderCreating,
40
- locationId
41
- } = props
33
+ const {
34
+ onNavigationRedirect,
35
+ uri,
36
+ user,
37
+ token,
38
+ cart,
39
+ currency,
40
+ webviewPaymethod,
41
+ setShowGateway,
42
+ setOpenOrderCreating,
43
+ locationId,
44
+ title,
45
+ additionalParams = {}
46
+ } = props
42
47
 
43
- const webviewRef = useRef<any>(null)
44
- const [, { showToast }] = useToast();
45
- const [ordering] = useApi()
46
- const [{ configs }] = useConfig();
47
- const [, t] = useLanguage();
48
+ const webviewRef = useRef<any>(null)
49
+ const [, { showToast }] = useToast();
50
+ const [ordering] = useApi()
51
+ const [{ configs }] = useConfig();
52
+ const [, t] = useLanguage();
53
+ const [, { confirmCart }] = useOrder()
48
54
 
49
-
50
- const [progClr, setProgClr] = useState('#424242');
51
- const [prog, setProg] = useState(true);
55
+ const [progClr, setProgClr] = useState('#424242');
56
+ const [prog, setProg] = useState(true);
52
57
 
53
- const handleCloseWebview = () => {
58
+ const handleCloseWebview = () => {
54
59
  setProg(true);
55
60
  setShowGateway({ open: false, closedByUser: true })
56
61
  }
57
62
 
58
- const onMessage = (e: any) => {
59
- if (e?.nativeEvent?.data && e?.nativeEvent?.data !== 'undefined') {
60
- let payment = JSON.parse(e.nativeEvent.data);
63
+ const onMessage = async (e: any) => {
64
+ if (e?.nativeEvent?.data && e?.nativeEvent?.data !== 'undefined') {
65
+ let payment = JSON.parse(e.nativeEvent.data);
66
+ if (payment?.response && payment?.responsetext && payment.orderid) {
67
+ const credomaticData = {
68
+ credomatic: {
69
+ ...payment
70
+ }
71
+ }
72
+ const confirmCartRes = await confirmCart(payment.orderid, credomaticData)
73
+ if (confirmCartRes.error) {
74
+ showToast(ToastType.Error, confirmCartRes.error.message)
75
+ }
76
+ if (confirmCartRes.result.order?.uuid) {
77
+ onNavigationRedirect?.('OrderDetails', { orderId: confirmCartRes.result.order.uuid, isFromCheckout: true })
78
+ }
79
+ }
61
80
 
62
81
  if (payment === 'api error' || payment === 'Cancelled by user') {
63
82
  setShowGateway({ closedByUser: true, open: false })
64
83
  setProg(true);
65
84
  }
66
85
 
67
- if (payment) {
68
- if (payment.error) {
69
- showToast(ToastType.Error, payment.result)
70
- setOpenOrderCreating && setOpenOrderCreating(false)
71
- } else if (payment?.result?.order?.uuid) {
72
- showToast(ToastType.Success, t('ORDER_PLACED_SUCCESSfULLY', 'The order was placed successfully'))
73
- onNavigationRedirect && onNavigationRedirect('OrderDetails', { orderId: payment?.result?.order?.uuid, isFromCheckout: true})
74
- }
75
- setProg(true);
76
- setShowGateway({ closedByUser: false, open: false })
77
- }
86
+ if (payment) {
87
+ if (payment.error) {
88
+ showToast(ToastType.Error, payment.result)
89
+ setOpenOrderCreating && setOpenOrderCreating(false)
90
+ } else if (payment?.result?.order?.uuid) {
91
+ showToast(ToastType.Success, t('ORDER_PLACED_SUCCESSfULLY', 'The order was placed successfully'))
92
+ onNavigationRedirect && onNavigationRedirect('OrderDetails', { orderId: payment?.result?.order?.uuid, isFromCheckout: true })
78
93
  }
79
- }
94
+ setProg(true);
95
+ setShowGateway({ closedByUser: false, open: false })
96
+ }
97
+ }
98
+ }
80
99
 
81
- return (
100
+ return (
82
101
  <View style={{ zIndex: 9999, height: '100%', width: '100%', position: 'absolute', backgroundColor: 'white' }}>
83
- <Icon
84
- name="x"
85
- size={35}
86
- style={{ backgroundColor: 'white', paddingTop: 30, paddingLeft: 10 }}
87
- onPress={handleCloseWebview}
88
- />
89
- <OText
90
- style={{
91
- textAlign: 'center',
92
- fontSize: 16,
93
- fontWeight: 'bold',
94
- color: '#00457C',
95
- marginBottom: 5,
96
- marginTop: 10
97
- }}>
98
- {webviewPaymethod?.gateway === 'paypal' ? (t('PAYPAL_GATEWAY', 'PayPal GateWay')) : (t('SQUARE_PAYMENT', 'Square payment'))}
99
- </OText>
100
- <View style={{ padding: 20, opacity: prog ? 1 : 0, backgroundColor: 'white' }}>
101
- <ActivityIndicator size={24} color={progClr} />
102
- </View>
103
- <WebView
104
- source={{ uri: uri }}
105
- onMessage={onMessage}
106
- ref={webviewRef}
107
- javaScriptEnabled={true}
108
- javaScriptEnabledAndroid={true}
109
- cacheEnabled={false}
110
- cacheMode='LOAD_NO_CACHE'
111
- style={{ flex: 1 }}
112
- onShouldStartLoadWithRequest={() => true}
113
- onLoadStart={() => {
114
- setProg(true);
115
- setProgClr('#424242');
116
- }}
117
- onLoadProgress={() => {
118
- setProg(true);
119
- setProgClr('#00457C');
120
- }}
121
- onLoad={() => {
122
- setProg(true);
123
- setProgClr('#00457C');
124
- }}
125
- onLoadEnd={(e) => {
126
- const messageParams = locationId ? { locationId } : {}
127
- const message = {
128
- action: 'init',
129
- data: {
130
- urlPlace: `${ordering.root}/carts/${cart?.uuid}/place`,
131
- urlConfirm: `${ordering.root}/carts/${cart?.uuid}/confirm`,
132
- payData: {
133
- paymethod_id: webviewPaymethod?.id,
134
- amount: cart?.balance ?? cart?.total,
135
- delivery_zone_id: cart?.delivery_zone_id,
136
- user_id: user?.id,
137
- user_name: user?.name
138
- },
139
- currency: configs?.stripe_currency?.value || currency,
140
- userToken: token,
141
- clientId: webviewPaymethod?.credentials?.client_id,
142
- ...messageParams
143
- }
144
- }
145
- setProg(false);
146
- webviewRef?.current?.postMessage?.(JSON.stringify(message))
147
- }}
148
- />
102
+ <Icon
103
+ name="x"
104
+ size={35}
105
+ style={{ backgroundColor: 'white', paddingTop: 30, paddingLeft: 10 }}
106
+ onPress={handleCloseWebview}
107
+ />
108
+ <OText
109
+ style={{
110
+ textAlign: 'center',
111
+ fontSize: 16,
112
+ fontWeight: 'bold',
113
+ color: '#00457C',
114
+ marginBottom: 5,
115
+ marginTop: 10
116
+ }}>
117
+ {title || (webviewPaymethod?.gateway === 'paypal' ? (t('PAYPAL_GATEWAY', 'PayPal GateWay')) : (t('SQUARE_PAYMENT', 'Square payment')))}
118
+ </OText>
119
+ <View style={{ padding: 20, opacity: prog ? 1 : 0, backgroundColor: 'white' }}>
120
+ <ActivityIndicator size={24} color={progClr} />
121
+ </View>
122
+ <WebView
123
+ source={{ uri: uri }}
124
+ onMessage={onMessage}
125
+ ref={webviewRef}
126
+ javaScriptEnabled={true}
127
+ javaScriptEnabledAndroid={true}
128
+ cacheEnabled={false}
129
+ cacheMode='LOAD_NO_CACHE'
130
+ style={{ flex: 1 }}
131
+ onShouldStartLoadWithRequest={() => true}
132
+ originWhitelist={["*"]}
133
+ onLoadStart={() => {
134
+ setProg(true);
135
+ setProgClr('#424242');
136
+ }}
137
+ onLoadProgress={() => {
138
+ setProg(true);
139
+ setProgClr('#00457C');
140
+ }}
141
+ onLoad={() => {
142
+ setProg(true);
143
+ setProgClr('#00457C');
144
+ }}
145
+ onLoadEnd={(e) => {
146
+ const messageParams = locationId ? { locationId, clientId: webviewPaymethod?.credentials?.application_id } : {}
147
+ const message = {
148
+ action: 'init',
149
+ data: {
150
+ urlPlace: `${ordering.root}/carts/${cart?.uuid}/place`,
151
+ urlConfirm: `${ordering.root}/carts/${cart?.uuid}/confirm`,
152
+ payData: {
153
+ paymethod_id: webviewPaymethod?.id,
154
+ amount: cart?.balance ?? cart?.total,
155
+ delivery_zone_id: cart?.delivery_zone_id,
156
+ user_id: user?.id,
157
+ user_name: user?.name
158
+ },
159
+ currency: configs?.stripe_currency?.value || currency,
160
+ userToken: token,
161
+ clientId: webviewPaymethod?.credentials?.client_id,
162
+ ...messageParams,
163
+ ...additionalParams
164
+ }
165
+ }
166
+ setProg(false);
167
+ webviewRef?.current?.postMessage?.(JSON.stringify(message))
168
+ }}
169
+ />
149
170
  </View>
150
- )}
171
+ )
172
+ }
@@ -592,7 +592,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
592
592
  setBusinessTypes={setBusinessTypes}
593
593
  />
594
594
  )}
595
- {!businessesList.loading && businessesList.businesses.length === 0 && (
595
+ {!businessesList.loading && businessesList.businesses.length === 0 && businessesList?.fetched && (
596
596
  <NotFoundSource
597
597
  content={t(
598
598
  'NOT_FOUND_BUSINESSES',
@@ -625,7 +625,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
625
625
  />
626
626
  )
627
627
  )}
628
- {businessesList.loading && (
628
+ {(businessesList.loading || !businessesList?.fetched) && (
629
629
  <>
630
630
  {[
631
631
  ...Array(
@@ -5,13 +5,9 @@ export const CCContainer = styled.View`
5
5
  `
6
6
 
7
7
  export const CCNotCarts = styled.View`
8
- height: 300px;
9
- display: flex;
10
8
  flex-direction: column;
11
- justify-content: center;
12
- align-items: center;
13
- width: 80%;
14
- margin: auto;
9
+ align-items: center;
10
+ margin-top: 40px;
15
11
  `
16
12
 
17
13
  export const CCList = styled.ScrollView`
@@ -156,6 +156,8 @@ const CheckoutUI = (props: any) => {
156
156
  const [allowedGuest, setAllowedGuest] = useState(false)
157
157
  const [placeByMethodPay, setPlaceByMethodPay] = useState(false)
158
158
  const [methodPaySupported, setMethodPaySupported] = useState({ enabled: false, message: null, loading: true })
159
+ const [cardList, setCardList] = useState<any>({ cards: [], loading: false, error: null })
160
+ const cardsMethods = ['credomatic']
159
161
  const placeSpotTypes = [3, 4, 5]
160
162
  const placeSpotsEnabled = placeSpotTypes.includes(options?.type)
161
163
  const isGiftCardCart = !cart?.business_id
@@ -185,6 +187,7 @@ const CheckoutUI = (props: any) => {
185
187
 
186
188
  const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) ||
187
189
  placing || errorCash || subtotalWithTaxes < cart?.minimum ||
190
+ (cardsMethods.includes(paymethodSelected?.gateway) && cardList?.cards?.length === 0) ||
188
191
  (options.type === 1 &&
189
192
  validationFields?.fields?.checkout?.driver_tip?.enabled &&
190
193
  validationFields?.fields?.checkout?.driver_tip?.required &&
@@ -200,6 +203,9 @@ const CheckoutUI = (props: any) => {
200
203
 
201
204
  const cartsWithProducts = carts && Object.values(carts).filter((cart: any) => cart.products.length) || null
202
205
 
206
+ const isSandboxCredomatic = configs?.credomatic_integration_sandbox?.value === '1'
207
+ const credomaticKeyId = isSandboxCredomatic ? configs?.credomatic_integration_public_sandbox_key?.value : configs?.credomatic_integration_public_production_key?.value
208
+ const credomaticUrl = `https://integrations.ordering.co/credomatic/front/auth_mobile.html?title=${t('CREDOMATIC_PAYMENT', 'Credomatic payment')}&body=${t('CREDOMATIC_PROCESSING', 'Processing transaction')}`
203
209
  const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map((option: any) => {
204
210
  return {
205
211
  value: option?.id, key: option?.id, label: t(option?.name.toUpperCase().replace(/\s/g, '_'), option?.name)
@@ -235,7 +241,7 @@ const CheckoutUI = (props: any) => {
235
241
  const handlePlaceOrder = (confirmPayment: any, forcePlace: boolean = false) => {
236
242
  if (!userErrors.length && (!requiredFields?.length || allowedGuest) || forcePlace) {
237
243
  vibrateApp()
238
- handlerClickPlaceOrder && handlerClickPlaceOrder(null, null, confirmPayment)
244
+ handlerClickPlaceOrder && handlerClickPlaceOrder(null, { isNative: true }, confirmPayment)
239
245
  return
240
246
  }
241
247
  if (requiredFields?.length) {
@@ -351,6 +357,16 @@ const CheckoutUI = (props: any) => {
351
357
  cart && events.emit('checkout_started', cart)
352
358
  }, [])
353
359
 
360
+ useEffect(() => {
361
+ if (cart?.paymethod_data?.gateway === 'credomatic') {
362
+ if (cart?.paymethod_data?.status === 2) {
363
+ setShowGateway({ ...showGateway, open: true })
364
+ } else if (cart?.paymethod_data?.gateway === 'credomatic' && cart?.paymethod_data?.status === 4) {
365
+ setShowGateway({ ...showGateway, open: false })
366
+ }
367
+ }
368
+ }, [cart?.paymethod_data])
369
+
354
370
  return (
355
371
  <>
356
372
  <Container noPadding>
@@ -678,6 +694,8 @@ const CheckoutUI = (props: any) => {
678
694
  methodPaySupported={methodPaySupported}
679
695
  placeByMethodPay={placeByMethodPay}
680
696
  setPlaceByMethodPay={setPlaceByMethodPay}
697
+ cardList={cardList}
698
+ setCardList={setCardList}
681
699
  />
682
700
  </ChPaymethods>
683
701
  </ChSection>
@@ -947,6 +965,29 @@ const CheckoutUI = (props: any) => {
947
965
  locationId={'L1NGAY5M6KJRX'}
948
966
  />
949
967
  )}
968
+ {cart?.paymethod_data?.gateway === 'credomatic' && cart?.paymethod_data?.status === 2 && showGateway.open && (
969
+ <PaymentOptionsWebView
970
+ title={t('CREDOMATIC_PAYMENT', 'Credomatic payment')}
971
+ onNavigationRedirect={onNavigationRedirect}
972
+ uri={credomaticUrl}
973
+ user={user}
974
+ cart={cart}
975
+ additionalParams={{
976
+ type: 'auth',
977
+ key_id: credomaticKeyId,
978
+ hash: cart?.paymethod_data?.result?.hash,
979
+ time: cart?.paymethod_data?.result?.time,
980
+ amount: cart?.total,
981
+ orderid: cart?.uuid,
982
+ ccnumber: cardList?.cards?.[0]?.number,
983
+ ccexp: cardList?.cards?.[0]?.expiryString,
984
+ cvv: cardList?.cards?.[0]?.cvc,
985
+ redirect: credomaticUrl
986
+ }}
987
+ webviewPaymethod={webviewPaymethod}
988
+ setShowGateway={setShowGateway}
989
+ />
990
+ )}
950
991
  </>
951
992
  )
952
993
  }
@@ -973,7 +1014,8 @@ export const Checkout = (props: any) => {
973
1014
  const getOrder = async (cartId: any) => {
974
1015
  try {
975
1016
  let result: any = {}
976
- const cart = orderState?.carts.find((cart: any) => cart.uuid === cartId)
1017
+ const cartsWithProducts = orderState?.carts && (Object.values(orderState?.carts)?.filter(cart => cart?.products && cart?.products?.length) || null)
1018
+ const cart = cartsWithProducts?.find((cart: any) => cart.uuid === cartId)
977
1019
  if (cart) {
978
1020
  result = { ...cart }
979
1021
  } else {
@@ -5,74 +5,99 @@ import IconAntDesign from 'react-native-vector-icons/AntDesign'
5
5
  import { useTheme } from 'styled-components';
6
6
 
7
7
  interface Props {
8
- initialValue: number,
9
- onClick: any,
10
- disableAnimation?: boolean
11
- toValue: number,
12
- style?: ViewStyle,
13
- duration?: number,
14
- type: 'favorite', // animation types
15
- isActive: boolean,
16
- animationType?: ((value: number) => number);
17
- useNativeDriver?: boolean,
18
- iconProps?: { color?: string, size?: number, style?: ViewStyle }
8
+ initialValue: number,
9
+ onClick: any,
10
+ disableAnimation?: boolean
11
+ toValue: number,
12
+ style?: ViewStyle,
13
+ duration?: number,
14
+ type: 'favorite', // animation types
15
+ isActive: boolean,
16
+ animationType?: ((value: number) => number);
17
+ useNativeDriver?: boolean,
18
+ iconProps?: { color?: string, size?: number, style?: ViewStyle }
19
19
  }
20
20
 
21
21
  export const LottieAnimation = (props: Props) => {
22
- const {
23
- initialValue,
24
- onClick,
25
- disableAnimation,
26
- toValue,
27
- style,
28
- duration,
29
- type,
30
- isActive,
31
- useNativeDriver,
32
- animationType,
33
- iconProps
34
- } = props
35
- const theme = useTheme()
36
- const animationProgress = useRef(new Animated.Value(initialValue))
37
- const [isHide, setIsHide] = useState(true)
38
- const favoriteArray = ['heart', 'hearto']
39
- const icon = type === 'favorite' ? favoriteArray : []
40
- const animationGif = type === 'favorite' ? theme.images?.general?.heart : ''
41
- const onPressLottie = () => {
42
- if (!disableAnimation) {
43
- setIsHide(false)
44
- Animated.timing(animationProgress.current, {
45
- toValue,
46
- duration: duration || 5000,
47
- easing: animationType || Easing.linear,
48
- useNativeDriver: useNativeDriver ?? true
49
- }).start();
50
- hideLottie()
51
- }
52
- onClick()
53
- }
22
+ const {
23
+ initialValue,
24
+ onClick,
25
+ disableAnimation,
26
+ toValue,
27
+ style,
28
+ duration,
29
+ type,
30
+ isActive,
31
+ useNativeDriver,
32
+ animationType,
33
+ iconProps
34
+ } = props
35
+
36
+ const theme = useTheme()
37
+ const animationProgress = useRef(new Animated.Value(initialValue))
38
+ const favRef = useRef<Lottie>(null)
39
+ const [isHide, setIsHide] = useState(true)
54
40
 
55
- const hideLottie = () => {
56
- setTimeout(() => setIsHide(true), 4500)
41
+ const favoriteArray = ['heart', 'hearto']
42
+ const icon = type === 'favorite' ? favoriteArray : []
43
+ const animationGif = type === 'favorite' ? theme.images?.general?.heart : ''
44
+
45
+ const onPressLottie = () => {
46
+ if (!disableAnimation) {
47
+ if (type === 'favorite') {
48
+ favRef.current?.play()
49
+ } else {
50
+ setIsHide(false)
51
+ Animated.timing(animationProgress.current, {
52
+ toValue,
53
+ duration: duration || 5000,
54
+ easing: animationType || Easing.linear,
55
+ useNativeDriver: useNativeDriver ?? true
56
+ }).start();
57
+ hideLottie()
58
+ }
57
59
  }
60
+ onClick()
61
+ }
62
+
63
+ const hideLottie = () => {
64
+ setTimeout(() => setIsHide(true), 4500)
65
+ }
58
66
 
59
- return (
60
- <TouchableOpacity
61
- onPress={onPressLottie}
62
- style={style}
63
- >
64
- {!isHide &&
65
- <Lottie
66
- progress={animationProgress.current}
67
- source={animationGif}
68
- />
69
- }
70
- <IconAntDesign
71
- name={isActive ? icon[0] : icon[1]}
72
- color={iconProps?.color || theme.colors.danger5}
73
- size={iconProps?.size || 16}
74
- style={iconProps?.style}
67
+ return (
68
+ <TouchableOpacity
69
+ onPress={onPressLottie}
70
+ style={style}
71
+ >
72
+ {type === 'favorite' ? (
73
+ // <Lottie
74
+ // ref={favRef}
75
+ // progress={initialValue}
76
+ // style={{ width: 20, height: 20 }}
77
+ // source={animationGif}
78
+ // />
79
+ <IconAntDesign
80
+ name={isActive ? icon[0] : icon[1]}
81
+ color={iconProps?.color || theme.colors.danger5}
82
+ size={iconProps?.size || 16}
83
+ style={iconProps?.style}
84
+ />
85
+ ) : (
86
+ <>
87
+ {!isHide &&
88
+ <Lottie
89
+ progress={animationProgress.current}
90
+ source={animationGif}
75
91
  />
76
- </TouchableOpacity>
77
- )
92
+ }
93
+ <IconAntDesign
94
+ name={isActive ? icon[0] : icon[1]}
95
+ color={iconProps?.color || theme.colors.danger5}
96
+ size={iconProps?.size || 16}
97
+ style={iconProps?.style}
98
+ />
99
+ </>
100
+ )}
101
+ </TouchableOpacity>
102
+ )
78
103
  }
@@ -1,8 +1,9 @@
1
1
  import React from 'react'
2
2
  import { View } from 'react-native'
3
- import { OButton, OIcon, OText } from '../shared'
3
+ import { OButton, OText } from '../shared'
4
4
  import { NotFoundSourceParams } from '../../types'
5
5
  import { useTheme } from 'styled-components/native';
6
+ import Foundation from 'react-native-vector-icons/Foundation'
6
7
  import {
7
8
  NotFound,
8
9
  NotFoundImage
@@ -10,34 +11,37 @@ import {
10
11
 
11
12
  export const NotFoundSource = (props: NotFoundSourceParams) => {
12
13
  const {
13
- image,
14
+ hideImage,
14
15
  content,
15
16
  btnTitle,
17
+ btnStyle,
16
18
  conditioned,
17
19
  onClickButton
18
20
  } = props
19
21
 
20
22
  const theme = useTheme();
21
23
 
22
- const errorImage = image || theme.images.general.notFound
23
- const isUrl = typeof errorImage === 'string' && errorImage.includes('http')
24
-
25
24
  return (
26
25
  <NotFound>
27
- {errorImage && (
26
+ {!hideImage && (
28
27
  <NotFoundImage>
29
- <OIcon url={isUrl && errorImage} src={!isUrl && errorImage} width={260} height={220} />
28
+ <Foundation
29
+ name='page-search'
30
+ color={theme.colors.primary}
31
+ size={60}
32
+ style={{ marginBottom: 10 }}
33
+ />
30
34
  </NotFoundImage>
31
35
  )}
32
- {content && conditioned && !errorImage && <OText color={theme.colors.disabled} size={18} style={{ textAlign: 'center' }}>{content}</OText>}
33
- {content && !conditioned && <OText color={theme.colors.disabled} size={18} style={{ textAlign: 'center' }}>{content}</OText>}
36
+ {content && conditioned && <OText color={theme.colors.disabled} size={16} style={{ textAlign: 'center' }}>{content}</OText>}
37
+ {content && !conditioned && <OText color={theme.colors.disabled} size={16} style={{ textAlign: 'center' }}>{content}</OText>}
34
38
  {!onClickButton && props.children && (
35
39
  props.children
36
40
  )}
37
41
  {onClickButton && (
38
42
  <View style={{ marginTop: 10, width: '100%' }}>
39
43
  <OButton
40
- style={{ width: '100%', height: 50 }}
44
+ style={{ width: '100%', height: 50, ...btnStyle }}
41
45
  bgColor={theme.colors.primary}
42
46
  borderColor={theme.colors.primary}
43
47
  onClick={() => onClickButton()}
@@ -23,21 +23,21 @@ export const PreviousProductsOrdered = (props: PreviousProductsOrderedParams) =>
23
23
  },
24
24
  });
25
25
 
26
- const ProductList = ({ style }: any) => {
26
+ const ProductList = () => {
27
27
  return (
28
28
  <>
29
- {products?.map((product: any) => (
30
- <SingleProductCard
31
- key={product?.id}
32
- isProductId
33
- isSoldOut={(product.inventoried && !product.quantity)}
34
- product={product}
35
- businessId={product?.business?.id}
36
- onProductClick={onProductClick}
37
- style={style}
38
- productAddedToCartLength={0}
39
- handleUpdateProducts={handleUpdateProducts}
40
- />
29
+ {products?.filter((product : any) => product?.business?.available)?.map((product: any) => (
30
+ <SingleProductCard
31
+ key={product?.id}
32
+ isProductId
33
+ isSoldOut={(product.inventoried && !product.quantity)}
34
+ product={product}
35
+ businessId={product?.business?.id}
36
+ onProductClick={onProductClick}
37
+ style={{ width: windowWidth - (products?.length > 1 ? 120 : 80), marginRight: 20 }}
38
+ productAddedToCartLength={0}
39
+ handleUpdateProducts={handleUpdateProducts}
40
+ />
41
41
  ))}
42
42
  </>
43
43
  )
@@ -45,7 +45,7 @@ export const PreviousProductsOrdered = (props: PreviousProductsOrderedParams) =>
45
45
  return (
46
46
  <ScrollView horizontal={isBusinessesSearchList} style={styles.container} showsVerticalScrollIndicator={false}>
47
47
  {isBusinessesSearchList ? (
48
- <ProductList style={{ width: windowWidth - 80, marginRight: 20 }} />
48
+ <ProductList />
49
49
  ) : (
50
50
  <ListWrapper isBusinessesSearchList={isBusinessesSearchList}>
51
51
  <ProductList />
@@ -10,6 +10,7 @@ import { PreviousProductsOrdered } from './PreviousProductsOrdered'
10
10
  import { OptionTitle, NoOrdersWrapper } from './styles'
11
11
  import { OrdersOptionParams } from '../../types'
12
12
  import { _setStoreData } from '../../providers/StoreUtil';
13
+ import { NotFoundSource } from '../NotFoundSource';
13
14
  import {
14
15
  Placeholder,
15
16
  PlaceholderLine,
@@ -199,16 +200,13 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
199
200
  <>
200
201
  {!loading && ordersLength.activeOrdersLength === 0 && ordersLength.previousOrdersLength === 0 && !activeOrders && (
201
202
  <NoOrdersWrapper>
202
- <OText size={14} numberOfLines={1}>
203
- {t('YOU_DONT_HAVE_ORDERS', 'You don\'t have any orders')}
204
- </OText>
205
- <OButton
206
- text={t('ORDER_NOW', 'Order now')}
207
- onClick={() => onNavigationRedirect && onNavigationRedirect('BusinessList')}
208
- textStyle={{ color: 'white', fontSize: 14 }}
209
- style={{ borderRadius: 7.6, marginBottom: 10, marginTop: 10, height: 44, paddingLeft: 10, paddingRight: 10 }}
203
+ <NotFoundSource
204
+ hideImage
205
+ btnStyle={{ borderRadius: 8 }}
206
+ content={t('YOU_DONT_HAVE_ORDERS', 'You don\'t have any orders')}
207
+ btnTitle={t('ORDER_NOW', 'Order now')}
208
+ onClickButton={() => onNavigationRedirect && onNavigationRedirect('BusinessList')}
210
209
  />
211
-
212
210
  </NoOrdersWrapper>
213
211
  )}
214
212
  {((ordersLength?.activeOrdersLength > 0 && activeOrders) || (ordersLength?.previousOrdersLength > 0 && !activeOrders)) && (
@@ -10,5 +10,5 @@ export const OptionTitle = styled.View`
10
10
  export const NoOrdersWrapper = styled.View`
11
11
  flex-direction: column;
12
12
  align-items: center;
13
- margin-top: 50px;
13
+ margin-top: 60px;
14
14
  `
@@ -0,0 +1,180 @@
1
+ import React, { useEffect, useRef, useState } from 'react'
2
+ import { View, Modal, TouchableOpacity, StyleSheet, SafeAreaView, KeyboardAvoidingView, Platform, ScrollView } from 'react-native'
3
+ import { OButton, OIcon, OInput, OModal, OText } from '../shared'
4
+ import { PaymentOptionStripe, useLanguage, useSession } from 'ordering-components/native'
5
+ import { StripeCardsListUI } from '../StripeCardsList'
6
+ import { useTheme } from 'styled-components/native';
7
+ import { CreditCardInput } from "react-native-credit-card-input-plus";
8
+ import Alert from '../../providers/AlertProvider'
9
+
10
+ const PaymentOptionCardUI = (props: any) => {
11
+ const {
12
+ cardSelected,
13
+ deleteCard,
14
+ onSelectCard,
15
+ handleCardClick,
16
+ cardsList,
17
+ addCardOpen,
18
+ setAddCardOpen,
19
+ gateway,
20
+ handleNewCard,
21
+ paymethodsWithoutSaveCards
22
+ } = props
23
+ const [, t] = useLanguage()
24
+ const theme = useTheme()
25
+ const [{ token }] = useSession()
26
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<string> }>({ open: false, content: [] })
27
+ const [newCard, setNewCard] = useState<any>(null)
28
+
29
+ const onChangeCardForm = (values : any) => {
30
+ if (values?.valid) {
31
+ const expiry = values?.values?.expiry?.split('/')
32
+ const expiryMonth = expiry[0]
33
+ const expiryYear = expiry[1]
34
+ const expiryString = expiryMonth + expiryYear
35
+ let lastFourDigits = values?.values?.number?.substr(-4);
36
+ setNewCard({
37
+ name: values?.values.name,
38
+ number: values?.values.number.replace(/\s/g, ''),
39
+ cvc: values?.values.cvc,
40
+ expiryMonth: expiryMonth,
41
+ expiryYear: expiryYear,
42
+ expiry: expiry,
43
+ brand: values?.values?.type,
44
+ last4: lastFourDigits,
45
+ expiryString: expiryString
46
+ })
47
+ }
48
+ }
49
+
50
+ const handleAddNewCard = () => {
51
+ handleNewCard(newCard)
52
+ setAddCardOpen({ ...addCardOpen, card: false })
53
+ setNewCard(null)
54
+ }
55
+
56
+ useEffect(() => {
57
+ if (cardsList.error && !cardsList.loading) {
58
+ setAlertState({
59
+ open: true,
60
+ content: cardsList.error
61
+ })
62
+ }
63
+ }, [JSON.stringify(cardsList)])
64
+
65
+ const style = StyleSheet.create({
66
+ wrapperIcon: {
67
+ marginLeft: 25,
68
+ marginTop: Platform.OS === 'ios' ? 40 : 12,
69
+ marginBottom: 20,
70
+ alignItems: 'center',
71
+ justifyContent: 'center',
72
+ },
73
+ buttonStyle: {
74
+ marginVertical: 20,
75
+ borderRadius: 7.6,
76
+ shadowOpacity: 0,
77
+ height: 44,
78
+ borderWidth: 1
79
+ }
80
+ })
81
+
82
+ return (
83
+ <View>
84
+ <>
85
+ {token && (!cardSelected || !paymethodsWithoutSaveCards.includes(gateway)) && (
86
+ <OButton
87
+ text={t('ADD_PAYMENT_CARD', 'Add New Payment Card')}
88
+ bgColor={theme.colors.white}
89
+ borderColor={theme.colors.primary}
90
+ style={{
91
+ marginVertical: 20,
92
+ borderRadius: 7.6,
93
+ shadowOpacity: 0,
94
+ height: 44,
95
+ borderWidth: 1
96
+ }}
97
+ textStyle={{ color: theme.colors.primary, fontSize: 12 }}
98
+ imgRightSrc={null}
99
+ onClick={() => setAddCardOpen({ ...addCardOpen, card: true })}
100
+ />
101
+ )}
102
+ <StripeCardsListUI
103
+ cardSelected={cardSelected}
104
+ deleteCard={deleteCard}
105
+ onSelectCard={onSelectCard}
106
+ handleCardClick={handleCardClick}
107
+ cardsList={cardsList}
108
+ noShowErrors
109
+ gateway={gateway}
110
+ />
111
+ </>
112
+ <Modal
113
+ animationType="slide"
114
+ visible={addCardOpen?.card}
115
+ onDismiss={() => setAddCardOpen({ ...addCardOpen, card: false })}
116
+ >
117
+ <KeyboardAvoidingView
118
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
119
+ style={{
120
+ flex: 1,
121
+ }}
122
+ >
123
+ <ScrollView>
124
+ <TouchableOpacity onPress={() => setAddCardOpen({ ...addCardOpen, card: false })}>
125
+ <OIcon
126
+ src={theme.images.general.close}
127
+ width={16}
128
+ style={style.wrapperIcon}
129
+ />
130
+ </TouchableOpacity>
131
+ <>
132
+ <CreditCardInput
133
+ onChange={onChangeCardForm}
134
+ requiresName
135
+ />
136
+ {alertState?.content?.[0] && !cardsList?.loading && (
137
+ <OText
138
+ color={theme?.colors?.error}
139
+ style={{
140
+ alignSelf: 'center'
141
+ }}
142
+ size={20}
143
+ >
144
+ {alertState.content[0]}
145
+ </OText>
146
+ )}
147
+ <OButton
148
+ text={t('ADD_CARD', 'Add card')}
149
+ isDisabled={!newCard || cardsList?.loading}
150
+ isLoading={cardsList?.loading}
151
+ onClick={() => handleAddNewCard()}
152
+ style={{
153
+ margin: 20,
154
+ ...style.buttonStyle
155
+ }}
156
+ />
157
+ </>
158
+ </ScrollView>
159
+ </KeyboardAvoidingView>
160
+ </Modal>
161
+ <Alert
162
+ open={alertState?.open || false}
163
+ title=''
164
+ content={alertState.content}
165
+ onClose={() => setAlertState({ open: false, content: [] })}
166
+ onAccept={() => setAlertState({ open: false, content: [] })}
167
+ />
168
+ </View>
169
+ )
170
+ }
171
+
172
+ export const PaymentOptionCard = (props : any) => {
173
+ const paymentOptions = {
174
+ ...props,
175
+ UIComponent: PaymentOptionCardUI
176
+ }
177
+ return (
178
+ <PaymentOptionStripe {...paymentOptions} />
179
+ )
180
+ }
@@ -16,6 +16,8 @@ import { useTheme } from 'styled-components/native';
16
16
  import { PaymentOptionCash } from '../PaymentOptionCash';
17
17
  import { StripeElementsForm } from '../StripeElementsForm';
18
18
  import { StripeCardsList } from '../StripeCardsList';
19
+ import { PaymentOptionCard } from '../PaymentOptionCard'
20
+
19
21
  // import { PaymentOptionStripe } from '../PaymentOptionStripe';
20
22
  // import { StripeRedirectForm } from '../StripeRedirectForm';
21
23
  // import { PaymentOptionPaypal } from '../PaymentOptionPaypal'
@@ -44,6 +46,7 @@ const stripeDirectMethods = ['stripe_direct']
44
46
 
45
47
  const webViewPaymentGateway: any = ['paypal', 'square']
46
48
  const multiCheckoutMethods = ['global_google_pay', 'global_apple_pay']
49
+ const cardsPaymethods = ['credomatic']
47
50
 
48
51
  const PaymentOptionsUI = (props: any) => {
49
52
  const {
@@ -64,7 +67,9 @@ const PaymentOptionsUI = (props: any) => {
64
67
  setMethodPaySupported,
65
68
  placeByMethodPay,
66
69
  methodPaySupported,
67
- setPlaceByMethodPay
70
+ setPlaceByMethodPay,
71
+ setCardList,
72
+ onPaymentChange
68
73
  } = props
69
74
 
70
75
  const theme = useTheme();
@@ -96,7 +101,7 @@ const PaymentOptionsUI = (props: any) => {
96
101
 
97
102
  const [, t] = useLanguage();
98
103
 
99
- const [addCardOpen, setAddCardOpen] = useState({ stripe: false, stripeConnect: false });
104
+ const [addCardOpen, setAddCardOpen] = useState({ stripe: false, stripeConnect: false, card: false });
100
105
  const paymethodSelected = props.paySelected || props.paymethodSelected || isOpenMethod?.paymethod
101
106
  // const [{ token }] = useSession()
102
107
 
@@ -192,7 +197,7 @@ const PaymentOptionsUI = (props: any) => {
192
197
  }
193
198
 
194
199
  const excludeIds: any = [32]; //exclude paypal & connect & redirect
195
- const filterMethodsPay = (gateway : string) => Platform.OS === 'ios' ? gateway !== 'google_pay' : gateway !== 'apple_pay'
200
+ const filterMethodsPay = (gateway: string) => Platform.OS === 'ios' ? gateway !== 'google_pay' : gateway !== 'apple_pay'
196
201
 
197
202
  return (
198
203
  <PMContainer>
@@ -202,9 +207,9 @@ const PaymentOptionsUI = (props: any) => {
202
207
  showsHorizontalScrollIndicator={false}
203
208
  // data={paymethodsList.paymethods.sort((a: any, b: any) => a.id - b.id)}
204
209
  data={paymethodsList.paymethods.sort((a: any, b: any) => a.id - b.id)
205
- .filter((p: any) =>
206
- !multiCheckoutMethods.includes(p.gateway) &&
207
- filterMethodsPay(p.gateway) &&
210
+ .filter((p: any) =>
211
+ !multiCheckoutMethods.includes(p.gateway) &&
212
+ filterMethodsPay(p.gateway) &&
208
213
  !excludeIds.includes(p.id))}
209
214
  renderItem={renderPaymethods}
210
215
  keyExtractor={(paymethod: any) => paymethod?.id?.toString?.()}
@@ -324,6 +329,24 @@ const PaymentOptionsUI = (props: any) => {
324
329
  />
325
330
  )}
326
331
 
332
+ {(cardsPaymethods.includes(isOpenMethod?.paymethod?.gateway) || cardsPaymethods.includes(paymethodSelected?.gateway)) && (
333
+ <PaymentOptionCard
334
+ setCardList={setCardList}
335
+ paymethod={isOpenMethod?.paymethod}
336
+ businessId={props.businessId}
337
+ publicKey={isOpenMethod?.paymethod?.credentials?.publishable}
338
+ gateway={isOpenMethod?.paymethod?.gateway || paymethodSelected?.gateway}
339
+ onPaymentChange={onPaymentChange}
340
+ payType={isOpenMethod?.paymethod?.name}
341
+ onSelectCard={handlePaymethodDataChange}
342
+ addCardOpen={addCardOpen}
343
+ setAddCardOpen={setAddCardOpen}
344
+ onCancel={() => handlePaymethodClick(null)}
345
+ paymethodSelected={paymethodSelected?.data?.id}
346
+ handlePaymentMethodClick={handlePaymentMethodClick}
347
+ />
348
+ )}
349
+
327
350
  <OModal
328
351
  entireModal
329
352
  title={t('ADD_CREDIT_OR_DEBIT_CARD', 'Add credit or debit card')}
@@ -375,8 +375,8 @@ const SingleOrderCardUI = (props: SingleOrderCardParams) => {
375
375
  <LottieAnimation
376
376
  type='favorite'
377
377
  onClick={handleChangeFavorite}
378
- initialValue={order?.favorite ? 0.75 : 0}
379
- toValue={order?.favorite ? 0 : 0.75}
378
+ initialValue={order?.favorite ? 0.5 : 0}
379
+ toValue={order?.favorite ? 0 : 0.5}
380
380
  style={{ marginBottom: 5 }}
381
381
  iconProps={{ color: theme.colors.danger5, size: 16, style: { top: 7 } }}
382
382
  isActive={order?.favorite}
@@ -201,8 +201,8 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
201
201
  <LottieAnimation
202
202
  type='favorite'
203
203
  onClick={handleChangeFavorite}
204
- initialValue={product?.favorite ? 0.75 : 0}
205
- toValue={product?.favorite ? 0 : 0.75}
204
+ initialValue={product?.favorite ? 0.5 : 0}
205
+ toValue={product?.favorite ? 0 : 0.5}
206
206
  disableAnimation={!auth}
207
207
  iconProps={{ color: theme.colors.danger5, size: 18 }}
208
208
  isActive={product?.favorite}
@@ -353,6 +353,8 @@ export interface NotFoundSourceParams {
353
353
  conditioned?: boolean,
354
354
  onClickButton?: any,
355
355
  children?: any
356
+ hideImage?: any
357
+ btnStyle?: any
356
358
  }
357
359
  export interface OrdersOptionParams {
358
360
  orderList?: any,